Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 441 – Python ZIP 애플리케이션 지원 개선

Author:
Daniel Holth <dholth at gmail.com>, Paul Moore <p.f.moore at gmail.com>
Discussions-To:
Python-Dev message
Status:
Final
Type:
Standards Track
Created:
30-Mar-2013
Python-Version:
3.5
Post-History:
30-Mar-2013, 01-Apr-2013, 16-Feb-2015
Resolution:
Python-Dev message

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

Python ZIP 애플리케이션 지원 개선

Python은 버전 2.6부터 디렉터리 또는 ZIP 형식 아카이브를 스크립트로 실행할 수 있습니다 [1]. zip 파일 또는 디렉터리를 첫 번째 인자로 지정하여 호출하면 인터프리터는 해당 디렉터리를 sys.path에 추가하고 __main__ 모듈을 실행합니다. 이러한 아카이브는 단일 파일 스크립트로 배포해야 하지만 여러 모듈의 모음으로 작성해야 할 만큼 복잡한 소프트웨어를 게시하는 훌륭한 방법을 제공합니다.

이 기능은 Python 2.6의 일부로 홍보되지 않아 [2] 상대적으로 잘 알려지지 않았다는 점이 주된 이유로 기대만큼 널리 사용되지 않으며, Windows 설치 프로그램이 이 형식의 파일에 대해 실행 프로그램과 연결할 파일 확장자(.py 이외의 확장자)를 등록하지 않는다는 점도 이유입니다.

이 PEP는 기능을 다시 홍보하고, .pyz.pyzw 확장자를 각각 “Python ZIP Applications” 및 “Windowed Python ZIP Applications”로 정의하며, 해당 형식을 관리할 수 있는 간단한 도구를 제공하여 이러한 문제를 해결할 것을 제안합니다.

새로운 Python ZIP 애플리케이션 확장자

“Python Zip Application”이라는 용어는 Python 코드가 Python에서 직접 실행될 수 있는 형태로 포함된 zip 형식 아카이브를 가리키는 공식 용어로 사용됩니다(구체적으로 아카이브의 루트 디렉터리에 __main__.py 파일이 있어야 합니다). .pyz 확장자는 이러한 파일과 공식적으로 연결됩니다.

Python 3.5 설치 프로그램은 실행할 수 있도록 .pyz.pyzw “Python Zip Applications”를 플랫폼 실행 프로그램과 연결합니다. .pyz 아카이브는 콘솔 애플리케이션이고 .pyzw 아카이브는 윈도우 애플리케이션이며, 이는 앱을 실행할 때 콘솔이 표시되는지를 나타냅니다.

Unix에서는 .pyz 확장자와 “Python Zip Application”이라는 이름이 (mime types 데이터베이스에?) 등록되는 것이 이상적입니다. 그러나 이러한 연결은 이 PEP의 범위를 벗어납니다.

Python Zip 애플리케이션에는 올바른 Python 인터프리터를 가리키는 #! 행과 선택적인 설명을 앞에 추가할 수 있습니다.:

#!/usr/bin/env python3
#  Python application packed with zipapp module
(binary contents of archive)

Unix에서는 표준 “셔뱅(shebang)” 지원을 통해 OS가 올바른 인터프리터로 파일을 실행할 수 있습니다. Windows에서는 Python 런처가 셔뱅 지원을 구현합니다.

그러나 파일명을 Python 인터프리터에 직접 전달하여 .pyz 애플리케이션을 실행하는 것은 항상 가능합니다.

배경 설명을 하자면, ZIP 아카이브는 파일 끝에서의 상대 오프셋을 포함하는 푸터로 정의됩니다. 다른 파일의 끝에 이어붙여져도 여전히 유효합니다. 이 기능은 완전히 표준적인 것으로, 자체 추출 ZIP 아카이브와 bdist_wininst 설치 프로그램 형식이 동작하는 방식입니다.

최소한의 도구: zipapp 모듈

이 PEP는 또한 이러한 아카이브를 다루기 위한 모듈을 포함할 것을 제안합니다. 이 모듈은 Python zip 애플리케이션 아카이브를 다루기 위한 함수들과, 그것들의 생성 및 조작을 위한 명령줄 인터페이스(python -m zipapp를 통한)를 포함할 것입니다.

Python Zip 애플리케이션을 관리하기 위한 더 완전한 도구들은 PyPI상의 서드파티 애플리케이션으로 장려됩니다. 현재 pyzzer [5]와 pex [6]가 그러한 도구 두 가지입니다.

모듈 인터페이스

zipapp 모듈은 다음 함수들을 제공할 것입니다:

create_archive(source, target=None, interpreter=None, main=None)

source로부터 애플리케이션 아카이브를 생성합니다. source는 다음 중 어느 것이든 될 수 있습니다:

  • 디렉터리의 이름이며, 이 경우 해당 디렉터리의 내용으로부터 새 애플리케이션 아카이브가 생성됩니다.
  • 기존 애플리케이션 아카이브 파일의 이름이며, 이 경우 해당 파일이 대상으로 복사됩니다. 파일 이름에는 필요한 경우 .pyz 또는 .pyzw 확장자가 포함되어야 합니다.
  • 바이트 모드로 읽기 위해 열린 파일 객체입니다. 파일의 내용은 애플리케이션 아카이브여야 하며, 파일 객체는 아카이브의 시작 위치에 놓여 있다고 가정됩니다.

target 인자는 생성될 아카이브가 기록될 위치를 결정합니다:

  • 파일 이름인 경우, 아카이브는 해당 파일에 기록됩니다.
  • 열린 파일 객체인 경우, 아카이브는 해당 파일 객체에 기록되며, 이 파일 객체는 바이트 모드로 쓰기 위해 열려 있어야 합니다.
  • target이 생략된 경우(또는 None인 경우), source는 반드시 디렉터리여야 하며, target은 source와 같은 이름에 .pyz 확장자가 추가된 파일이 됩니다.

interpreter 인자는 아카이브를 실행할 파이썬 인터프리터의 이름을 지정합니다. 이는 아카이브 시작 부분에 “shebang” 줄로 기록됩니다. 유닉스에서는 이것이 운영체제에 의해 해석되며, 윈도우에서는 파이썬 런처에 의해 처리됩니다. 인터프리터를 생략하면 셰뱅 라인이 기록되지 않습니다. 인터프리터가 지정되고 target이 파일 이름인 경우, 대상 파일의 실행 비트가 설정됩니다.

main 인자는 아카이브의 메인 프로그램으로 사용될 호출 가능 객체의 이름을 지정합니다. 이는 소스가 디렉터리이고 소스에 이미 __main__.py 파일이 없는 경우에만 지정할 수 있습니다. main 인자는 “pkg.module:callable” 형식을 취해야 하며, 아카이브는 “pkg.module”을 임포트하고 인자 없이 주어진 호출 가능 객체를 실행함으로써 실행됩니다. 소스가 디렉터리이고 __main__.py 파일을 포함하지 않는 경우 main을 생략하는 것은 오류인데, 그렇지 않으면 결과로 생성된 아카이브를 실행할 수 없기 때문입니다.

source 또는 target에 파일 객체가 지정된 경우, create_archive 호출 후 이를 닫는 것은 호출자의 책임입니다.

기존 아카이브를 복사할 때, 제공되는 파일 객체는 readreadline, 또는 write 메서드만 있으면 됩니다. 디렉터리에서 아카이브를 생성할 때, 대상이 파일 객체이면 이는 zipfile.ZipFile 클래스에 전달되며, 해당 클래스가 필요로 하는 메서드를 제공해야 합니다.

get_interpreter(archive)

archive의 셔뱅 줄에 지정된 인터프리터를 반환합니다. 셔뱅이 없으면 함수는 None을 반환합니다. archive 인자는 파일 이름이거나 바이트 모드로 읽기 위해 열린 파일과 유사한 객체일 수 있습니다.

명령줄 사용법

zipapp 모듈은 python -m 플래그로 실행할 수 있습니다. 명령줄 인터페이스는 다음과 같습니다:

python -m zipapp directory [options]

    Create an archive from the given directory.  An archive will
    be created from the contents of that directory.  The archive
    will have the same name as the source directory with a .pyz
    extension.

    The following options can be specified:

    -o archive / --output archive

        The destination archive will have the specified name.  The
        given name will be used as written, so should include the
        ".pyz" or ".pyzw" extension.

    -p interpreter / --python interpreter

        The given interpreter will be written to the shebang line
        of the archive.  If this option is not given, the archive
        will have no shebang line.

    -m pkg.mod:fn / --main pkg.mod:fn

        The source directory must not have a __main__.py file. The
        archiver will write a __main__.py file into the target
        which calls fn from the module pkg.mod.

명령줄 인터페이스의 동작은 zipapp.create_archive()의 동작과 일치합니다.

또한, 명령줄 인터페이스를 사용하여 기존 아카이브를 다룰 수 있습니다.:

python -m zipapp app.pyz --show

    Displays the shebang line of an archive.  Output is of the
    form

        Interpreter: /usr/bin/env
    or
        Interpreter: <none>

    and is intended for diagnostic use, not for scripts.

python -m zipapp app.pyz -o newapp.pyz [-p interpreter]

    Copy app.pyz to newapp.pyz, modifying the shebang line based
    on the -p option (as for creating an archive, no -p option
    means remove the shebang line).  Specifying a destination is
    mandatory.

    In-place modification of an archive is *not* supported, as the
    risk of damaging archives is too great for a simple tool.

언급했듯이, 이 아카이브는 표준 zip 파일이므로 어떤 표준 ZIP 유틸리티나 파이썬의 zipfile 모듈로도 압축을 풀 수 있습니다. 이러한 이유로, 아카이브의 내용을 나열하거나 압축을 해제하는 인터페이스는 제공되지 않으며 필요하지도 않습니다.

자주 묻는 질문

표준 ZIP 유틸리티가 맨 앞의 #!를 정말로 처리할 수 있습니까?
물론입니다. zipfile 명세는 zip 파일 앞에 임의의 데이터를 덧붙이는 것을 허용합니다. 이 기능은 “자체 압축 해제 zip” 프로그램에서 흔히 사용됩니다. 여러분의 아카이브 프로그램이 이를 처리하지 못한다면, 그것은 해당 아카이브 프로그램의 버그입니다.
zipapp은 그저 zipfile 모듈을 매우 얇게 감싼 래퍼에 불과하지 않습니까?
그렇습니다. 다른 도구를 사용하여 직접 파이썬 zip 애플리케이션 아카이브를 만드는 쪽을 선호하신다면, 그 방법 역시 마찬가지로 잘 작동할 것입니다. zipapp 모듈은 단지 편의를 위한 것일 뿐, 그 이상은 아닙니다.
왜 그냥 .zip이나 .py 확장자를 사용하지 않습니까?
사용자는 .zip파일이 아카이브 도구로 열리기를 기대하고, .py파일에는 읽을 수 있는 텍스트가 들어 있기를 기대합니다. 둘 다 이 용도로는 혼란을 줄 것입니다.
이것은 기존 패키지 형식들과 비교했을 때 어떤 경쟁력이 있습니까?
sdist, bdist, wheel 형식은 기존 Python 설치에 설치될 모듈을 패키징하기 위해 설계되었습니다. 이들은 설치 없이 사용하도록 의도된 것이 아닙니다. 실행 가능 zip 형식은 설치가 필요 없는 독립 실행형 사용을 위해 특별히 설계되었습니다. 이들은 사실상 독립 실행형 Python 스크립트의 다중 파일 버전입니다.

거부된 제안

셔뱅 줄을 위한 편의 값

일반적인 인터프리터 값들에 대해 “편의” 형식을 두는 것이 가치가 있을까요? 예를 들어, -p 3-p "/usr/bin/env python3"와 같은 의미를 갖는 경우입니다. 이는 일반적인 경우에 많은 타이핑을 절약해 줄 뿐만 아니라, “다른” 플랫폼에서의 셔뱅 처리의 복잡한 세부 사항을 이해하고 싶지 않거나 이해할 필요가 없는 사람들에게 크로스 플랫폼 옵션을 제공해 줄 것입니다.

단점은 축약형을 어떻게 변환해야 할지 명확하지 않다는 것입니다. 예를 들어, “3”이 “/usr/bin/env python3”, “/usr/bin/python3”, “python3” 중 무엇을 의미해야 할까요, 아니면 다른 것일까요? 또한, “Python의 사용 가능한 어떤 버전”을 의미하는 핵심 사례인 “/usr/bin/env python”에 대해서는 명확한 축약형이 없으며, 이는 지나치게 제한적인 셔뱅 줄을 가진 스크립트가 작성되는 결과로 쉽게 이어질 수 있습니다.

전반적으로 이는 이점보다 문제가 더 많아 보이며, 그 결과 고려 대상에서 제외되었습니다.

.pyz를 미디어 타입으로 등록하기

.pyz 확장자를 유닉스 확장자 데이터베이스에 등록해야 한다는 제안이 있었습니다 [3]. 이것을 하는 것은 윈도우 설치 프로그램이 확장자를 등록하는 것과 동등한 조치로서 합당하지만, .py 확장자는 미디어 타입 데이터베이스 [4] 에 등재되어 있지 않습니다. .py 없이 .pyz를 등록하는 것은 합리적으로 보이지 않으므로, 이 아이디어는 본 PEP에서 제외되었습니다. 관심 있는 당사자는 향후 .py.pyz 둘 다를 등록하도록 조치할 수 있습니다.

기본 인터프리터

이 PEP의 초안에서는 기본 인터프리터로 /usr/bin/env python을 사용할 것을 제안했습니다. 유닉스 사용자들은 이러한 동작에 문제를 겪는데, 많은 배포판에서 python 명령의 기본값이 파이썬 2이기 때문이며, 이 PEP는 기본적으로 파이썬 3을 선호해야 한다고 여겨집니다. 그러나 python3 명령을 사용하면 윈도우 사용자에게 예기치 않은 동작이 발생할 수 있는데, 윈도우에서는 python 명령에 대한 런처의 기본 동작이 흔히 사용자에 의해 커스터마이즈되지만, python3의 동작은 이에 맞게 수정되지 않을 수 있기 때문입니다.

그 결과, “모호함에 직면했을 때는 추측을 거부한다”는 원칙이 적용되어, 명시적으로 요청하지 않는 한 아카이브에는 셔뱅 줄이 포함되지 않습니다. 윈도우에서는 아카이브가 여전히 (기본 파이썬으로) 런처에 의해 실행되며, 유닉스에서는 원하는 파이썬 인터프리터를 명시적으로 호출하여 아카이브를 실행할 수 있습니다.

셔뱅 줄을 관리하는 명령줄 도구

사용자가 기존 아카이브의 셔뱅 줄을 수정하거나, 심지어 현재 셔뱅 줄을 단순히 표시하고 싶어할 수도 있다는 것은 충분히 있을 법한 일입니다. 이는 기존 도구로는 처리하기 까다로운데(zip 프로그램은 일반적으로 앞에 붙은 데이터를 완전히 무시하며, 텍스트 편집기는 바이너리 데이터가 포함된 파일을 편집하는 데 어려움을 겪을 수 있습니다).

zipapp 모듈은 셔뱅 줄을 처리하는 함수를 제공하지만, 그 기능에 대한 명령줄 인터페이스는 포함하지 않습니다. 이는 결과물인 인터페이스가 지나치게 복잡해지고 혼란스러워질 수 있다는 우려 없이 그러한 인터페이스를 제공하는 방법이 명확하지 않기 때문입니다. 셔뱅 줄을 변경하는 것은 흔치 않은 요구 사항일 것으로 예상됩니다.

참조 구현

참조 구현은 http://bugs.python.org/issue23491 에 있습니다.

참고 문헌

이 PEP에 대한 논의는 python-dev 메일링 리스트에서 이루어졌으며, https://mail.python.org/pipermail/python-dev/2015-February/138277.html 에서 시작하는 스레드에서 진행되었습니다.