"zipapp" --- Manage executable Python zip archives
**************************************************

버전 3.5에 추가.

**소스 코드:** Lib/zipapp.py

======================================================================

이 모듈은 파이썬 인터프리터가 직접 실행할 수 있는 파이썬 코드를 포함하
는 zip 파일 생성을 관리하는 도구를 제공합니다. 이 모듈은 명령 줄 인터
페이스와 파이썬 API를 모두 제공합니다.


기본 예
=======

다음 예제는 명령 줄 인터페이스를 사용하여 파이썬 코드가 포함된 디렉터
리에서 실행 가능 아카이브를 만드는 방법을 보여줍니다. 실행하면, 아카이
브가 아카이브의 모듈 "myapp"에서 "main" 함수를 실행합니다.

   $ python -m zipapp myapp -m "myapp:main"
   $ python myapp.pyz
   <output from myapp>


명령 줄 인터페이스
==================

명령 줄에서 프로그램으로 호출될 때, 다음 형식이 사용됩니다:

   $ python -m zipapp source [options]

*source*가 디렉터리면, *source*의 내용으로부터 아카이브를 만듭니다.
*source*가 파일이면, 아카이브여야 하며, 대상 아카이브로 복사됩니다 (또
는 --info 옵션이 지정되면 셔뱅(shebang) 줄의 내용이 표시됩니다).

다음과 같은 옵션이 이해됩니다:

-o <output>, --output=<output>

   출력을 *output*이라는 이름의 파일에 씁니다. 이 옵션을 지정하지 않으
   면, 출력 파일명은 입력 *source*와 같고, 확장자 ".pyz"가 추가됩니다.
   명시적인 파일명이 제공되면, 그대로 사용됩니다 (그래서 필요하면
   ".pyz" 확장자를 포함해야 합니다).

   *source*가 아카이브이면 반드시 출력 파일명을 지정해야 합니다 (그리
   고 이 경우, *output*은 *source*와 달라야 합니다).

-p <interpreter>, --python=<interpreter>

   실행할 명령으로 *interpreter*를 지정하여 "#!" 줄을 아카이브에 추가
   합니다. 또한, POSIX에서, 아카이브를 실행 파일로 만듭니다. 기본값은
   "#!" 줄을 쓰지 않고, 파일을 실행 파일로 만들지 않는 것입니다.

-m <mainfn>, --main=<mainfn>

   아카이브에 *mainfn*을 실행하는 "__main__.py" 파일을 씁니다.
   *mainfn* 인자는 "pkg.mod:fn" 형식이어야 합니다. 여기서 "pkg.mod"는
   아카이브의 패키지/모듈이며, "fn"은 주어진 모듈에 있는 콜러블입니다.
   "__main__.py" 파일은 그 콜러블을 실행합니다.

   아카이브를 복사할 때 "--main"을 지정할 수 없습니다.

-c, --compress

   디플레이트(deflate) 메서드로 파일을 압축하여, 출력 파일의 크기를 줄
   입니다. 기본적으로, 파일은 아카이브에 압축되지 않은 상태로 저장됩니
   다.

   아카이브를 복사할 때 "--compress"는 효과가 없습니다.

   버전 3.7에 추가.

--info

   진단 목적으로, 아카이브에 내장된 인터프리터를 표시합니다. 이 경우,
   다른 옵션은 무시되고 SOURCE는 디렉터리가 아닌 아카이브여야 합니다.

-h, --help

   간단한 사용법 메시지를 인쇄하고 종료합니다.


파이썬 API
==========

이 모듈은 두 개의 편의 함수를 정의합니다:

zipapp.create_archive(source, target=None, interpreter=None, main=None, filter=None, compressed=False)

   *source*로 응용 프로그램 아카이브를 만듭니다. 소스는 다음 중 하나일
   수 있습니다:

   * 디렉터리 이름, 또는 디렉터리를 참조하는 *경로류 객체*. 이 경우 해
     당 디렉터리의 내용으로 새 응용 프로그램 아카이브가 만들어집니다.

   * 기존 응용 프로그램 아카이브 파일의 이름, 또는 이러한 파일을 참조
     하는 *경로류 객체*. 이 경우 파일이 대상(target)으로 복사됩니다
     (*interpreter* 인자에 제공된 값을 반영하도록 수정하면서). 필요하
     면, 파일 이름에 ".pyz" 확장자가 포함되어야 합니다.

   * 바이너리 모드에서 읽기로 열린 파일 객체. 파일의 내용은 응용 프로
     그램 아카이브여야 하며, 파일 객체는 아카이브의 시작 부분에 위치한
     것으로 가정합니다.

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

   * 파일 이름이거나 *경로류 객체*이면, 아카이브가 그 파일에 기록됩니
     다.

   * 열린 파일 객체면, 그 파일 객체에 아카이브가 기록되며, 파일은 바이
     너리 모드로 쓰기로 열려 있어야 합니다.

   * target이 생략되면 (또는 "None"이면), 소스(source)는 디렉터리여야
     하며 대상은 ".pyz" 확장자가 추가된 소스와 이름이 같은 파일이 됩니
     다.

   *interpreter* 인자는 아카이브가 실행될 파이썬 인터프리터의 이름을
   지정합니다. 아카이브 시작 부분에 "셔뱅(shebang)" 줄로 기록됩니다.
   POSIX에서는 이를 OS가 해석하고, 윈도우에서는 파이썬 런처가 이를 처
   리합니다. *interpreter*를 생략하면 셔뱅 줄이 기록되지 않습니다.
   interpreter가 지정되고 target이 파일명이면, target 파일의 실행 가능
   비트가 설정됩니다.

   *main* 인자는 아카이브의 메인 프로그램으로 사용될 콜러블의 이름을
   지정합니다. 소스가 디렉터리이고 소스에 아직 "__main__.py" 파일이 없
   을 때만 지정할 수 있습니다. *main* 인자는 "pkg.module:callable" 형
   식이어야 하며 아카이브는 "pkg.module"을 임포트 하고 인자 없이 지정
   된 콜러블을 실행해서 실행됩니다. 소스가 디렉터리이고 "__main__.py"
   파일을 포함하지 않을 때 *main*을 생략하는 것은 에러입니다, 그렇지
   않으면 결과 아카이브가 실행 가능하지 않기 때문입니다.

   선택적 *filter* 인자는 추가되는 파일의 (소스 디렉터리에 상대적인)
   경로를 나타내는 Path 객체가 전달되는 콜백 함수를 지정합니다. 파일을
   추가하려면 "True"를 반환해야 합니다.

   선택적 *compressed* 인자는 파일을 압축할지를 결정합니다. "True"로
   설정하면, 아카이브의 파일이 디플레이트(deflate) 메서드로 압축됩니다
   ; 그렇지 않으면 파일이 압축되지 않은 상태로 저장됩니다. 기존 아카이
   브를 복사할 때는 이 인자가 효과가 없습니다.

   *source*나 *target*에 파일 객체가 지정되면, create_archive를 호출한
   후 파일 객체를 닫는 것은 호출자의 책임입니다.

   기존 아카이브를 복사할 때, 제공된 파일 객체에는 "read"와 "readline"
   또는 "write" 메서드만 필요합니다. 디렉터리에서 아카이브를 만들 때,
   대상이 파일 객체면 "zipfile.ZipFile" 클래스로 전달되며, 해당 클래스
   에 필요한 메서드를 제공해야 합니다.

   버전 3.7에서 변경: *filter*와 *compressed* 매개 변수를 추가했습니다
   .

zipapp.get_interpreter(archive)

   아카이브 시작 부분에서 "#!" 줄에 지정된 인터프리터를 반환합니다.
   "#!" 줄이 없으면, "None"을 반환합니다. *archive* 인자는 파일명이나
   바이너리 모드로 읽기로 열린 파일류 객체일 수 있습니다. 아카이브가
   시작 부분에 위치한 것으로 가정합니다.


예
==

디렉터리를 아카이브로 패킹하고, 실행합니다.

   $ python -m zipapp myapp
   $ python myapp.pyz
   <output from myapp>

"create_archive()" 함수를 사용하여 같은 작업을 수행할 수 있습니다:

   >>> import zipapp
   >>> zipapp.create_archive('myapp', 'myapp.pyz')

POSIX에서 응용 프로그램을 직접 실행할 수 있게 만들려면, 사용할 인터프
리터를 지정하십시오.

   $ python -m zipapp myapp -p "/usr/bin/env python"
   $ ./myapp.pyz
   <output from myapp>

기존 아카이브에서 셔뱅 줄을 바꾸려면, "create_archive()" 함수를 사용하
여 수정된 아카이브를 만드십시오:

   >>> import zipapp
   >>> zipapp.create_archive('old_archive.pyz', 'new_archive.pyz', '/usr/bin/python3')

파일을 제자리에서 갱신하려면, "BytesIO" 객체를 사용하여 메모리에서 치
환을 수행한 다음, 나중에 소스를 덮어씁니다. 파일을 제자리에서 덮어쓰면
에러로 인해 원본 파일을 손실할 위험이 있음에 유의하십시오. 이 코드는
이러한 에러에 대한 보호는 없지만, 프로덕션 코드는 이를 방지해야 합니다
. 또한, 이 방법은 아카이브가 메모리에 올라올 수 있을 때만 작동합니다:

   >>> import zipapp
   >>> import io
   >>> temp = io.BytesIO()
   >>> zipapp.create_archive('myapp.pyz', temp, '/usr/bin/python2')
   >>> with open('myapp.pyz', 'wb') as f:
   >>>     f.write(temp.getvalue())


인터프리터 지정하기
===================

인터프리터를 지정한 다음 응용 프로그램 아카이브를 배포한다면, 사용된
인터프리터가 이식성 있는지 확인할 필요가 있음에 유의하십시오. 윈도우
용 파이썬 런처는 가장 일반적인 POSIX "#!" 줄 형식을 지원하지만, 고려해
야 할 다른 문제가 있습니다:

* "/usr/bin/env python"(또는 "/usr/bin/python"과 같은 "python" 명령의
  다른 형식)을 사용한다면, 사용자에게 기본적으로 파이썬 2나 파이썬 3이
  있을 수 있음을 고려해야 하고, 두 버전에서 작동하도록 코드를 작성하십
  시오.

* "/usr/bin/env python3"과 같이 명시적인 버전을 사용하면 해당 버전이
  없는 사용자에게는 응용 프로그램이 작동하지 않습니다. (여러분의 코드
  를 파이썬 2 호환으로 만들지 않았다면 이것이 여러분이 원하는 것일 수
  있습니다).

* "파이썬 X.Y 이상"이라고 말할 방법이 없어서, "/usr/bin/env python3.4"
  처럼 정확한 버전을 사용할 때는 주의하십시오. 예를 들어 파이썬 3.5 사
  용자를 위해서는 셔뱅 줄을 변경해야 합니다.

일반적으로, 여러분의 코드가 파이썬 2나 3중 어느 것으로 작성되었는지에
따라 "/usr/bin/env python2"나 "/usr/bin/env python3"을 사용해야 합니다
.


zipapp으로 독립형 응용 프로그램 만들기
======================================

"zipapp" 모듈을 사용하면, 시스템에 적합한 버전의 파이썬만 설치되어있는
최종 사용자에게 배포 할 수 있는 필요한 모든 것이 담긴 파이썬 프로그램
을 만들 수 있습니다. 이 작업의 핵심은 응용 프로그램 코드와 함께 모든
응용 프로그램의 종속성을 아카이브에 묶는 것입니다.

독립형 아카이브를 만드는 단계는 다음과 같습니다:

1. 정상적으로 디렉터리에 응용 프로그램을 만드십시오, 그러면
   "__main__.py" 파일과 모든 지원 응용 프로그램 코드를 포함하는
   "myapp" 디렉터리를 얻게 됩니다.

2. pip을 사용하여 모든 응용 프로그램의 종속성을 "myapp" 디렉터리에 설
   치하십시오:

      $ python -m pip install -r requirements.txt --target myapp

   (이것은 "requirements.txt" 파일에 프로젝트 요구 사항이 있다고 가정
   합니다 - 그렇지 않으면, pip 명령 줄에 종속성을 수동으로 나열할 수
   있습니다).

3. 다음과 같이 응용 프로그램을 패키징하십시오:

      $ python -m zipapp -p "interpreter" myapp

그러면 독립형 실행 파일이 생성되며, 사용 가능한 적절한 인터프리터가 있
는 모든 시스템에서 실행할 수 있습니다. 자세한 내용은 인터프리터 지정하
기를 참조하십시오. 단일 파일로 사용자에게 제공될 수 있습니다.

유닉스에서, "myapp.pyz" 파일은 그대로 실행 파일입니다. "평범한" 명령
이름을 선호하면, 파일 이름을 변경하여 ".pyz" 확장자를 제거할 수 있습니
다. 윈도우에서, 파이썬 인터프리터가 설치될 때 ".pyz"와 ".pyzw" 파일 확
장자를 등록한다는 점에서  "myapp.pyz[w]" 파일은 실행 파일입니다.


Making a Windows executable
---------------------------

On Windows, registration of the ".pyz" extension is optional, and
furthermore, there are certain places that don't recognise registered
extensions "transparently" (the simplest example is that
"subprocess.run(['myapp'])" won't find your application - you need to
explicitly specify the extension).

On Windows, therefore, it is often preferable to create an executable
from the zipapp.  This is relatively easy, although it does require a
C compiler.  The basic approach relies on the fact that zipfiles can
have arbitrary data prepended, and Windows exe files can have
arbitrary data appended.  So by creating a suitable launcher and
tacking the ".pyz" file onto the end of it, you end up with a single-
file executable that runs your application.

A suitable launcher can be as simple as the following:

   #define Py_LIMITED_API 1
   #include "Python.h"

   #define WIN32_LEAN_AND_MEAN
   #include <windows.h>

   #ifdef WINDOWS
   int WINAPI wWinMain(
       HINSTANCE hInstance,      /* handle to current instance */
       HINSTANCE hPrevInstance,  /* handle to previous instance */
       LPWSTR lpCmdLine,         /* pointer to command line */
       int nCmdShow              /* show state of window */
   )
   #else
   int wmain()
   #endif
   {
       wchar_t **myargv = _alloca((__argc + 1) * sizeof(wchar_t*));
       myargv[0] = __wargv[0];
       memcpy(myargv + 1, __wargv, __argc * sizeof(wchar_t *));
       return Py_Main(__argc+1, myargv);
   }

If you define the "WINDOWS" preprocessor symbol, this will generate a
GUI executable, and without it, a console executable.

To compile the executable, you can either just use the standard MSVC
command line tools, or you can take advantage of the fact that
distutils knows how to compile Python source:

   >>> from distutils.ccompiler import new_compiler
   >>> import distutils.sysconfig
   >>> import sys
   >>> import os
   >>> from pathlib import Path

   >>> def compile(src):
   >>>     src = Path(src)
   >>>     cc = new_compiler()
   >>>     exe = src.stem
   >>>     cc.add_include_dir(distutils.sysconfig.get_python_inc())
   >>>     cc.add_library_dir(os.path.join(sys.base_exec_prefix, 'libs'))
   >>>     # First the CLI executable
   >>>     objs = cc.compile([str(src)])
   >>>     cc.link_executable(objs, exe)
   >>>     # Now the GUI executable
   >>>     cc.define_macro('WINDOWS')
   >>>     objs = cc.compile([str(src)])
   >>>     cc.link_executable(objs, exe + 'w')

   >>> if __name__ == "__main__":
   >>>     compile("zastub.c")

The resulting launcher uses the "Limited ABI", so it will run
unchanged with any version of Python 3.x.  All it needs is for Python
("python3.dll") to be on the user's "PATH".

For a fully standalone distribution, you can distribute the launcher
with your application appended, bundled with the Python "embedded"
distribution.  This will run on any PC with the appropriate
architecture (32 bit or 64 bit).


경고
----

There are some limitations to the process of bundling your application
into a single file.  In most, if not all, cases they can be addressed
without needing major changes to your application.

1. 응용 프로그램이 C 확장을 포함하는 패키지에 의존하면, 해당 패키지는
   zip 파일에서 실행할 수 없습니다 (이것은 OS 제한 사항인데, OS 로더가
   로드 할 수 있으려면 실행 코드는 파일 시스템에 있어야만 합니다). 이
   경우, zip 파일에서 해당 종속성을 제외하고, 사용자가 파일을 설치하도
   록 요구하거나, zip 파일과 함께 제공하고 "__main__.py"에 코드를 추가
   하여 "sys.path"에 압축 해제된 모듈을 포함하는 디렉터리를 포함할 수
   있습니다. 이 경우, 대상 아키텍처에 적합한 바이너리를 제공해야 합니
   다 (그리고 아마도 사용자 컴퓨터를 기반으로 실행 시간에 "sys.path"에
   추가할 올바른 버전을 선택해야 합니다).

2. If you are shipping a Windows executable as described above, you
   either need to ensure that your users have "python3.dll" on their
   PATH (which is not the default behaviour of the installer) or you
   should bundle your application with the embedded distribution.

3. The suggested launcher above uses the Python embedding API.  This
   means that in your application, "sys.executable" will be your
   application, and *not* a conventional Python interpreter.  Your
   code and its dependencies need to be prepared for this possibility.
   For example, if your application uses the "multiprocessing" module,
   it will need to call "multiprocessing.set_executable()" to let the
   module know where to find the standard Python interpreter.


파이썬 Zip 응용 프로그램 아카이브 형식
======================================

파이썬은 버전 2.6부터 "__main__.py" 파일이 포함된 zip 파일을 실행할 수
있었습니다. 파이썬에서 실행되려면, 응용 프로그램 아카이브는 응용 프로
그램의 진입점으로 실행될 "__main__.py" 파일이 포함된 표준 zip 파일이어
야 합니다. 모든 파이썬 스크립트와 마찬가지로, 스크립트의 부모(이 경우
zip 파일)가 "sys.path"에 배치되므로 zip 파일에서 추가 모듈을 임포트 할
수 있습니다.

zip 파일 형식은 임의의 데이터를 zip 파일 앞에 추가할 수 있도록 합니다.
zip 응용 프로그램 형식은 이 기능을 사용하여 표준 POSIX "셔뱅(shebang)"
줄을 파일 앞에 추가합니다 ("#!/path/to/interpreter").

따라서 공식적으로 파이썬 zip 응용 프로그램 형식은 다음과 같습니다:

1. An optional shebang line, containing the characters "b'#!'"
   followed by an interpreter name, and then a newline ("b'\n'")
   character.  The interpreter name can be anything acceptable to the
   OS "shebang" processing, or the Python launcher on Windows.  The
   interpreter should be encoded in UTF-8 on Windows, and in
   "sys.getfilesystemencoding()" on POSIX.

2. "zipfile" 모듈에 의해 생성된 표준 zip 파일 데이터. zipfile 내용은 *
   반드시* "__main__.py"라는 파일을 포함해야 합니다 (zip 파일의 "루트"
   에 있어야 합니다 - 즉, 서브 디렉터리에 있을 수 없습니다). zip 파일
   데이터는 압축되거나 그렇지 않을 수 있습니다.

응용 프로그램 아카이브에 셔뱅 줄이 있으면, POSIX 시스템에서 직접 실행
될 수 있도록 실행 파일 비트를 설정할 수 있습니다.

이 모듈의 도구를 사용하여 응용 프로그램 아카이브를 만들 필요는 없습니
다 - 모듈은 편의를 위한 것입니다. 하지만 어떤 방법으로 만들었든 위 형
식의 아카이브는 파이썬에서 허용됩니다.
