28.4. zipapp --- 実行可能な python zip 書庫を管理する

バージョン 3.5 で追加.

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


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

28.4.1. 基本的な例

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

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

28.4.2. コマンドラインインターフェイス

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

$ 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 を指定することは出来ません。

--info

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

-h, --help

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

28.4.3. Python API

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

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

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

  • ディレクトリ名、または 新しいアプリケーションアーカイブがディレクトリのコンテンツから作成される場合に pathlib.Path オブジェクトが参照するディレクトリ。
  • 既存のアプリケーションアーカイブファイルの名前、 または(interpreter 引数に指定した値を反映し、修正する)アーカイブへ ファイルがコピーされる場合に pathlib.Path オブジェクトが参照するファイル。
  • バイトモードの読込みで開くファイルオブジェクト。 ファイルの内容がアプリケーションアーカイブとなり、 ファイルオブジェクトがアーカイブの起点となります。

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

  • ファイル名、または pathlb.Path オブジェクトを指定した場合、アーカイブは指定したファイルへ書込まれます。
  • 開いているファイルオブジェクトを指定した場合、 アーカイブはそのファイルオブジェクトへ書込みを行ないます。 ファイルオブジェクトは必ずバイトモードの書込みで開いてください。
  • 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 は無視すべきエラーとなり、 作成されたアーカイブには実行可能ビットが設定されません。

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

既存のアーカイブをコピーする際、ファイルオブジェクトは read , readline , write メソッドのみを提供します。 アーカイブをディレクトリから作成する際、 target がファイルオブジェクトである場合は、 zipfile.ZipFile クラスへ渡されます。必ずクラスが必要とするメソッドを提供してください。

zipapp.get_interpreter(archive)

アーカイブの最初の行の #! に指定されたインタープリタを返します。 #! が無い場合は None を返します。 archive 引数は、ファイル名またはバイトモードの読込みで開いた ファイルに準じるオブジェクトを指定することができ、アーカイブの起点で決定されます。

28.4.4. 使用例

ディレクトリを書庫に圧縮し、実行します。

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

同じことを create_archive() 関数を使用して行うことが出来ます:

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

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.

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