"zipapp" --- 実行可能な Python zip 書庫を管理する
*************************************************

バージョン 3.5 で追加.

**ソースコード:** Lib/zipapp.py

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

このモジュールは Python コードを含む zip ファイルの作成を行うツールを
提供します。 zip ファイルは Python インタープリタで直接実行することが
出来ます。 このモジュールは コマンドラインインターフェイス と Python
API の両方を提供します。


基本的な例
==========

実行可能なアーカイブを Python コードを含むディレクトリから作成する為に
コマンドラインインターフェイス をどのように利用することができるかを以
下に例示します。アーカイブは実行時にアーカイブ内の "myapp" モジュール
から "main" 関数を実行します。

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


コマンドラインインターフェイス
==============================

コマンドラインからプログラムとして呼び出す場合は、次の形式を使用います
:

   $ python -m zipapp source [options]

*source* がディレクトリである場合、 *source* ディレクトリの内容からア
ーカイブを作成します。 *source* がファイルである場合、 *source* ファイ
ル自身をアーカイブ化し、保存先アーカイブへコピーします。(または --info
オプションが指定されている場合はファイルのシェバン行が表示されます。)

以下のオプションが解釈されます:

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

   出力を *output* に指定した名前のファイルへ書込みます。このオプショ
   ンが指定されていない場合、出力先ファイル名は入力元 *source* と同じ
   になり、 ".pyz" 拡張子が付与されます。 ファイル名が明示的に指定され
   ている場合は、指定されたファイル名を使用します。(必要であれば
   ".pyz" 拡張子が含まれます。)

   *source* がアーカイブである場合は、出力先ファイル名を必ず指定しなけ
   ればなりません。 (*source* がアーカイブである場合は *output* を必ず
   *source* とは別の名前にしてください。)

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

   実行コマンドとしての *interpreter* を指定する "#!" 行を書庫に追加し
   ます。 また、POSIX では書庫を実行可能にします。 デフォルトでは "#!"
   行を書かず、ファイルを実行可能にはしません。

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

   *mainfn* を実行するアーカイブへ "__main__.py" ファイルを書込んでく
   ださい。 *mainfn* 引数は "pkg.mod:fn" の形式で指定します。
   "pkg.mod" の場所はアーカイブ内の package/module です。 "fn" は指定
   した module から呼出すことのできる関数です。 "__main__.py" ファイル
   が module から呼出すことのできる関数を実行します。

   書庫をコピーする際、 "--main" を指定することは出来ません。

-c, --compress

   Compress files with the deflate method, reducing the size of the
   output file. By default, files are stored uncompressed in the
   archive.

   "--compress" has no effect when copying an archive.

   バージョン 3.7 で追加.

--info

   診断するために書庫に埋め込まれたインタープリタを表示します。 この場
   合、他の全てのオプションは無視され、SOURCE はディレクトリではなく書
   庫でなければなりません。

-h, --help

   簡単な使用法を表示して終了します。


Python API
==========

このモジュールは 2 つの簡便関数を定義しています:

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

   *source* からアプリケーション書庫を作成します。 ソースは以下のいず
   れかです:

   * ディレクトリ名、または 新しいアプリケーションアーカイブがディレク
     トリのコンテンツから作成される場合に *path-like object* オブジェ
     クトが参照するディレクトリ。

   * 既存のアプリケーションアーカイブファイルの名前、 または
     (*interpreter* 引数に指定した値を反映し、修正する)アーカイブへ フ
     ァイルがコピーされる場合に *path-like object* オブジェクトが参照
     するファイル。

   * バイトモードの読込みで開くファイルオブジェクト。 ファイルの内容が
     アプリケーションアーカイブとなり、 ファイルオブジェクトがアーカイ
     ブの起点となります。

   *target* 引数は作成される書庫が書き込まれる場所を決めます:

   * ファイル名、または *path-like object* オブジェクトを指定した場合
     、アーカイブは指定したファイルへ書込まれます。

   * 開いているファイルオブジェクトを指定した場合、 アーカイブはそのフ
     ァイルオブジェクトへ書込みを行ないます。 ファイルオブジェクトは必
     ずバイトモードの書込みで開いてください。

   * target を指定しないか "None" を渡した場合、 source は必ずディレク
     トリでなければならず、target は source のファイル名に ".pyz" 拡張
     子を付与したファイル名となります。

   *interpreter* 引数はアーカイブが実行時に使用する Python インタープ
   リタの名前を指定します。 インタープリタ名は "シェバン" 行としてアー
   カイブの起点に書込まれます。 POSIX では OS によってシェバンが解釈さ
   れ、 Windows では Python ランチャーによって扱われます。 シェバン行
   が書込まれていない場合は *interpreter* の結果を無視します。
   interpreter が指定されており、 target がファイル名である場合、
   target ファイルの実行可能ビットが設定されます。

   *main* 引数はアーカイブのメインプログラムとして使用する callable の
   名前を指定します。 *main* 引数は source がディレクトリであり、
   source が既に "__main__.py" ファイルを保持していない場合に限り、指
   定することができます。 *main* 引数は "pkg.module:callable" の形式を
   取り、 アーカイブは "pkg.module" をインポートして実行され、 指定し
   た callable を引数なしで実行します。 source がディレクトリであり、
   "__main__.py" が含まれていない場合、 *main* は無視すべきエラーとな
   り、 作成されたアーカイブには実行可能ビットが設定されません。

   The optional *filter* argument specifies a callback function that
   is passed a Path object representing the path to the file being
   added (relative to the source directory).  It should return "True"
   if the file is to be added.

   The optional *compressed* argument determines whether files are
   compressed.  If set to "True", files in the archive are compressed
   with the deflate method; otherwise, files are stored uncompressed.
   This argument has no effect when copying an existing archive.

   *source* または *target* へファイルオブジェクトを指定した場合、
   caller が create_archive の呼出し後にオブジェクトを閉じます。

   既存のアーカイブをコピーする際、ファイルオブジェクトは "read" ,
   "readline" , "write" メソッドのみを提供します。 アーカイブをディレ
   クトリから作成する際、 target がファイルオブジェクトである場合は、
   "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()" function: を使
用して変更された書庫を作成します:

   >>> 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())


インタープリタの指定
====================

Note that if you specify an interpreter and then distribute your
application archive, you need to ensure that the interpreter used is
portable.  The Python launcher for Windows supports most common forms
of POSIX "#!" line, but there are other issues to consider:

* If you use "/usr/bin/env python" (or other forms of the "python"
  command, such as "/usr/bin/python"), you need to consider that your
  users may have either Python 2 or Python 3 as their default, and
  write your code to work under both versions.

* If you use an explicit version, for example "/usr/bin/env python3"
  your application will not work for users who do not have that
  version.  (This may be what you want if you have not made your code
  Python 2 compatible).

* There is no way to say "python X.Y or later", so be careful of using
  an exact version like "/usr/bin/env python3.4" as you will need to
  change your shebang line for users of Python 3.5, for example.

Typically, you should use an "/usr/bin/env python2" or "/usr/bin/env
python3", depending on whether your code is written for Python 2 or 3.


Creating Standalone Applications with zipapp
============================================

Using the "zipapp" module, it is possible to create self-contained
Python programs, which can be distributed to end users who only need
to have a suitable version of Python installed on their system.  The
key to doing this is to bundle all of the application's dependencies
into the archive, along with the application code.

The steps to create a standalone archive are as follows:

1. Create your application in a directory as normal, so you have a
   "myapp" directory containing a "__main__.py" file, and any
   supporting application code.

2. Install all of your application's dependencies into the "myapp"
   directory, using pip:

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

   (this assumes you have your project requirements in a
   "requirements.txt" file - if not, you can just list the
   dependencies manually on the pip command line).

3. Optionally, delete the ".dist-info" directories created by pip in
   the "myapp" directory. These hold metadata for pip to manage the
   packages, and as you won't be making any further use of pip they
   aren't required - although it won't do any harm if you leave them.

4. Package the application using:

      $ python -m zipapp -p "interpreter" myapp

This will produce a standalone executable, which can be run on any
machine with the appropriate interpreter available. See インタープリタ
の指定 for details. It can be shipped to users as a single file.

On Unix, the "myapp.pyz" file is executable as it stands.  You can
rename the file to remove the ".pyz" extension if you prefer a "plain"
command name.  On Windows, the "myapp.pyz[w]" file is executable by
virtue of the fact that the Python interpreter registers the ".pyz"
and ".pyzw" file extensions when installed.


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).


Caveats
-------

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. If your application depends on a package that includes a C
   extension, that package cannot be run from a zip file (this is an
   OS limitation, as executable code must be present in the filesystem
   for the OS loader to load it). In this case, you can exclude that
   dependency from the zipfile, and either require your users to have
   it installed, or ship it alongside your zipfile and add code to
   your "__main__.py" to include the directory containing the unzipped
   module in "sys.path". In this case, you will need to make sure to
   ship appropriate binaries for your target architecture(s) (and
   potentially pick the correct version to add to "sys.path" at
   runtime, based on the user's machine).

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.


The Python Zip Application Archive Format
=========================================

Python has been able to execute zip files which contain a
"__main__.py" file since version 2.6.  In order to be executed by
Python, an application archive simply has to be a standard zip file
containing a "__main__.py" file which will be run as the entry point
for the application.  As usual for any Python script, the parent of
the script (in this case the zip file) will be placed on "sys.path"
and thus further modules can be imported from the zip file.

The zip file format allows arbitrary data to be prepended to a zip
file.  The zip application format uses this ability to prepend a
standard POSIX "shebang" line to the file ("#!/path/to/interpreter").

Formally, the Python zip application format is therefore:

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. Standard zipfile data, as generated by the "zipfile" module.  The
   zipfile content *must* include a file called "__main__.py" (which
   must be in the "root" of the zipfile - i.e., it cannot be in a
   subdirectory).  The zipfile data can be compressed or uncompressed.

If an application archive has a shebang line, it may have the
executable bit set on POSIX systems, to allow it to be executed
directly.

There is no requirement that the tools in this module are used to
create application archives - the module is a convenience, but
archives in the above format created by any means are acceptable to
Python.
