윈도우 콘솔 관련 사항

New in version 6.0.

클릭 6.0 전까지는 윈도우 콘솔에서 클릭을 쓰는 데 여러 버그와 제약이 있었다. 특히 파이썬 2에서 잘못된 인코딩으로 명령행 인자 디코딩을 수행했으며 모든 파이썬 버전에서 유니코드 문자 출력이 불가능했다. 클릭 6.0부터는 윈도우에서 출력 스트림을 에뮬레이션 해서 별도 API를 통해 윈도우 콘솔 유니코드 출력을 지원하며 다양한 매개변수 디코딩을 수행한다.

그게 어떻게 동작하고 그래서 어떤 의미가 있는지 간단히 살펴보자.

유니코드 인자

클릭 내부에서는 기본적으로 어느 인자든 바이트 열 또는 유니코드 열로 들어올 수 있다는 걸 전제하고 있으며 타입에서 기대하는 값으로 변환하는 걸 최대한 늦게 수행한다. 이렇게 하면 운영 체제와 파이썬 버전에 가장 적합한 형태로 데이터를 받을 수 있게 된다는 장점이 있다.

예를 들어 따로 지정하지 않는 한 파이썬 2에선 경로를 바이트 그대로 둔다.

이게 윈도우에서 문제를 좀 일으켰다. 초기에는 틀린 인코딩을 써서 입력 데이터가 결국 쓰레기 값이 됐다. 하지만 그 인코딩 부분은 수정됐으며 지금은 sys.argv에서 유니코드 매개변수를 뽑아낸다.

그로 인해 윈도우 하의 파이썬 2에서는 인자가 거의 확실하게 바이트가 아니라 유니코드 방식이 된다. 이전에는 명시적으로 유니코드 매개변수를 주지 않는 한 이런 식으로 동작하지 않았다. 따라서 따로 만든 타입이 있다면 주의할 필요가 있다.

다른 제약 사항도 있다. 클릭 핸들러 호출 전에 sys.argv가 변경됐다면 다시 원래의 바이트 입력 방식을 써야 하는데, 그 경우 유니코드 값 전체가 아니라 매개변수에 쓰인 코드페이지 일부만 사용 가능하다.

유니코드 입출력

윈도우에서 유니코드 출력과 입력은 텍스트 스트림 처리 방식으로 구현돼 있다. 즉 클릭에서 처음 텍스트 출력(또는 입력) 스트림이 필요할 때 몇 가지 검사를 해서 윈도우 콘솔이 연결돼 있는지 여부를 알아낸다. 윈도우 콘솔이 없다면 텍스트 출력 스트림을 그대로 반환하며 그 스트림의 인코딩은 다른 플랫폼과 마찬가지로 utf-8으로 설정돼 있다.

하지만 콘솔이 연결돼 있으면 대신 스트림을 에뮬레이션 하게 되며 cmd.exe의 유니코드 API를 써서 텍스트 정보를 출력한다. 이 경우 그 스트림 역시 내부 인코딩으로 utf-16-le를 쓰게 된다. 하지만 어떤 복잡한 처리가 있어서 저수준 비가공 IO 버퍼가 유니코드 API를 건너뛰고 있고, 그래서 간접적으로 바이트 출력을 하는 게 여전히 가능하다.

그 처리를 파이썬 2와 파이썬 3 모두에서 쓴다. 어느 쪽 버전에서도 cmd.exe에서의 유니코드 문자 사용을 그냥은 지원하지 않기 때문이다. 유의해야 할 제약 사항이 몇 가지 있다.

  • 이런 유니코드 지원은 click.echo, click.prompt, 그리고 click.get_text_stream에 한정된다.

  • 유니코드 값과 바이트 열 중 어느 쪽을 주냐에 따라 내부 제어 흐름이 완전히 달라지며, 그래서 데이터 일부가 버퍼링 되는 경우 뭔가 이상한 결과물이 나올 수 있다. 클릭에서는 항상 직접 플러시를 해서 그런 경우를 막으려 하지만 stdout이나 stderr에서 다른 문자열 타입을 섞어서 쓰는 경우에는 직접 플러시를 해 줘야 한다.

  • 비가공 출력 스트림은 윈도우 전체 동작 방식인 이진 모드로 설정돼 있고, 그래서 print 호출이 영향을 받게 된다. print보단 click.echo를 쓰자.

  • 윈도우 7 및 전에서는 이진 모드에서 한 호출당 최대 64k개 문자까지만 쓸 수 있다는 제한이 있다. 그 경우 sys.stdoutsys.stderr를 래퍼로 교체해서 그 제한을 피한다.

또 유의할 사항은 윈도우 콘솔의 기본 폰트가 많은 문자를 지원하지 않는다는 점이다. 즉 국제적으로 통용되는 문자들은 가능하지만 이모지나 특수 문자는 거의 안 된다.