"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 は受け付けます。
