zipapp --- 実行可能な Python zip アーカイブを管理する

Added in version 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 がファイルの場合は既存のアーカイブでなければならず、出力先のアーカイブへコピーされます (--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" はアーカイブ内のパッケージまたはモジュールで、"fn" はそのモジュール内の呼び出し可能オブジェクトです。 __main__.py ファイルはそのオブジェクトを呼び出します。

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

-c, --compress

ファイルを deflate 方式で圧縮し、出力ファイルのサイズを小さくします。 デフォルトではファイルは圧縮せずにアーカイブに格納されます。

書庫をコピーする際、 --compress に効果はありません。

Added in version 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。 この場合、そのディレクトリの内容から新しいアプリケーションアーカイブを作成します。

  • 既存のアプリケーションアーカイブのファイル名、またはそのファイルを指す path-like object。 この場合、interpreter 引数の値を反映するよう変更して、ファイルを出力先へコピーします。 必要に応じて、ファイル名には .pyz 拡張子を含めてください。

  • バイナリモードで読み込み用に開かれたファイルオブジェクト。 ファイルの内容はアプリケーションアーカイブでなければならず、ファイル位置はアーカイブの先頭にあるものとします。

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

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

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

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

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

main 引数は、アーカイブのメインプログラムとして使う呼び出し可能オブジェクトの名前を指定します。 source がディレクトリで、そこに __main__.py がまだない場合にのみ指定できます。 main 引数は "pkg.module:callable" の形式で指定します。 アーカイブの実行時には "pkg.module" をインポートし、指定された呼び出し可能オブジェクトを引数なしで呼び出します。 source がディレクトリで __main__.py がない場合、main を省略するとエラーになります。 省略を許すと、作成されるアーカイブを実行できないためです。

省略可能な filter 引数にはコールバック関数を指定します。 追加するファイルへのパス (元のディレクトリからの相対パス) を表す Path オブジェクトがこの関数に渡されます。 ファイルを追加する場合は True を返す必要があります。

省略可能な compressed 引数はファイルを圧縮するかどうかを指定します。 True に設定すると、アーカイブ内のファイルは deflate 方式で圧縮されます。 それ以外の場合は圧縮せずに格納されます。 既存のアーカイブをコピーする場合、この引数は効果がありません。

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() 関数で変更済みのアーカイブを作成します。

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

インタープリタの指定

インタープリタを指定してアプリケーションアーカイブを配布する場合、そのインタープリタの指定に移植性があることを確認してください。 Windows 用の Python ランチャーは POSIX の #! 行の一般的な形式をほぼサポートしていますが、ほかにも考慮すべき点があります。

  • "/usr/bin/env python" (または "/usr/bin/python" などの "python" コマンドの形式) を使う場合、ユーザーのデフォルトが Python 2 と Python 3 のどちらの可能性もあることを考慮し、両方のバージョンで動作するコードを書く必要があります。

  • 例えば "/usr/bin/env python3" のようにバージョンを明示すると、そのバージョンを持たないユーザーはアプリケーションを実行できません (コードを Python 2 対応にしていなければ、これは望ましい動作かもしれません)。

  • 「Python X.Y 以降」と指定する方法はありません。 そのため、"/usr/bin/env python3.4" のような厳密なバージョンの指定には注意してください。 例えば Python 3.5 のユーザー向けにはシェバン行を変更する必要があります。

通常は、コードが Python 2 用か Python 3 用かに応じて "/usr/bin/env python2" または "/usr/bin/env python3" を使ってください。

zipapp による単独で使えるアプリケーションの作成

zipapp モジュールを使うと、適切なバージョンの Python さえインストールされていれば使える、自己完結した Python プログラムを作成してエンドユーザーに配布できます。 そのためには、アプリケーションのコードとともに、依存するものをすべてアーカイブに同梱することが重要です。

単独で使えるアーカイブを作成する手順は次のとおりです。

  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
    

これにより、適切なインタープリタが利用できるマシンならどこでも実行できる、単独で使える実行ファイルが作成されます。 詳細は インタープリタの指定 を参照してください。 1 つのファイルとしてユーザーに配布できます。

Unix では myapp.pyz ファイルをそのまま実行できます。 通常のコマンド名にしたければ、ファイル名を変更して .pyz 拡張子を削除できます。 Windows では、Python インタープリタのインストール時に .pyz と .pyzw の拡張子が登録されるため、myapp.pyz[w] ファイルを実行できます。

注意点

アプリケーションが C 拡張を含むパッケージに依存している場合、そのパッケージは zip ファイルから実行できません (OS のローダーが読み込む実行可能コードはファイルシステム上になければならないという、OS の制約によるものです)。 この場合、その依存パッケージを zip ファイルから除外し、ユーザーにインストールしてもらうか、zip ファイルと別に同梱します。 同梱する場合は、展開したモジュールを含むディレクトリを sys.path に追加するコードを __main__.py に加えてください。 その際、対象とするアーキテクチャに適したバイナリを確実に配布する必要があります (場合によっては、実行時にユーザーのマシンに応じて適切なバージョンを選んで sys.path に追加する必要もあります)。

Python zip アプリケーションアーカイブ形式

Python はバージョン 2.6 から、__main__.py ファイルを含む zip ファイルを実行できます。 Python で実行するには、アプリケーションアーカイブが、エントリーポイントとして実行する __main__.py ファイルを含む標準的な zip ファイルであれば十分です。 ほかの Python スクリプトと同様に、スクリプトの親 (この場合は zip ファイル) が sys.path に追加されるため、zip ファイル内のほかのモジュールもインポートできます。

zip ファイル形式では、ファイルの先頭に任意のデータを付けられます。 zip アプリケーション形式はこの機能を使い、標準的な POSIX のシェバン行 (#!/path/to/interpreter) を先頭に付けます。

したがって、Python zip アプリケーション形式は正式には次の構成になります。

  1. 省略可能なシェバン行で、文字 b'#!' にインタープリタ名、改行文字 (b'\n') が続きます。 インタープリタ名には、OS のシェバン処理、または Windows の Python ランチャーが受け付けるものを指定できます。 Windows では UTF-8、POSIX では sys.getfilesystemencoding() が返すエンコーディングでインタープリタ名をエンコードしてください。

  2. zipfile モジュールが生成するような標準的な zip ファイルのデータです。 zip ファイルには __main__.py というファイルを 必ず 含めます (zip ファイルのルートになければならず、サブディレクトリには置けません)。 zip ファイルのデータは圧縮しても、圧縮しなくても構いません。

アプリケーションアーカイブにシェバン行がある場合、POSIX システムでは実行可能ビットを設定して直接実行できるようにしても構いません。

アプリケーションアーカイブをこのモジュールのツールで作成する必要はありません。 このモジュールは便利な手段を提供するものですが、どのような方法で作成しても、上記の形式のアーカイブであれば Python は受け付けます。