web-dev-qa-db-ja.com

すべてのpythonコードを単一のZipファイルにバンドルするにはどうすればよいですか?

アプリケーションを配布するときに、卵のallを1つのZipファイルにまとめて配布する必要があるのは、1つのZipファイルと実行可能ファイル(単純に起動し、 Zipファイルの主な機能とキックpythonオフまたは類似)。

私はこれをオンラインで行う話をいくつか見ましたが、実際にそれを行う方法の例はありません。

(Zipセーフであれば)卵をZipファイルに変換できることを知っています。

私がよくわからないのは:

どういうわけか、すべての卵を1つのZipファイルに結合できますか?もしそうなら、どのように?

特定の卵からコードをどのようにロードして実行しますか?

そのEgg内のコードがすべての依存関係(つまり、Zipファイル内の他のegg)にアクセスできることをどのように保証しますか?

人々はこの種のものを頻繁に尋ね、次のような答えを得ます。 py2exeを使用します。はい、わかりました。それが1つの解決策です。それは私がここで尋ねている質問ではありません...

26
Doug

通常のpythonツールでほとんどの作業を自動化できます。クリーンなvirtualenvから始めましょう。

[zart@feena ~]$ mkdir ziplib-demo
[zart@feena ~]$ cd ziplib-demo
[zart@feena ziplib-demo]$ virtualenv .
New python executable in ./bin/python
Installing setuptools.............done.
Installing pip...............done.

次に、zip形式のライブラリに入れるパッケージのセットをインストールします。トリックはそれらを特定のディレクトリに強制的にインストールすることです。

(注:コマンドラインまたはpip.conf/pip.iniで--Eggオプションを使用しないでください。ファイルレイアウトが壊れ、Zipにインポートできなくなります)

[zart@feena ziplib-demo]$ bin/pip install --install-option --install-lib=$PWD/unpacked waitress
Downloading/unpacking waitress
  Downloading waitress-0.8.5.tar.gz (112kB): 112kB downloaded
  Running setup.py Egg_info for package waitress

Requirement already satisfied (use --upgrade to upgrade): setuptools in ./lib/python2.7/site-packages/setuptools-0.6c11-py2.7.Egg (from waitress)
Installing collected packages: waitress
  Running setup.py install for waitress

    Installing waitress-serve script to /home/zart/ziplib-demo/bin
Successfully installed waitress
Cleaning up...

Update:pipに-t <path>スイッチが追加されました。これは--install-option --install-lib=と同じ機能を果たします。

それらすべてを1つのZipにパックしましょう

[zart@feena ziplib-demo]$ cd unpacked
[zart@feena unpacked]$ ls
waitress  waitress-0.8.5-py2.7.Egg-info
[zart@feena unpacked]$ Zip -r9 ../library.Zip *
  adding: waitress/ (stored 0%)
  adding: waitress/receiver.py (deflated 71%)
  adding: waitress/server.pyc (deflated 64%)
  adding: waitress/utilities.py (deflated 62%)
  adding: waitress/trigger.pyc (deflated 63%)
  adding: waitress/trigger.py (deflated 61%)
  adding: waitress/receiver.pyc (deflated 60%)
  adding: waitress/adjustments.pyc (deflated 51%)
  adding: waitress/compat.pyc (deflated 56%)
  adding: waitress/adjustments.py (deflated 60%)
  adding: waitress/server.py (deflated 68%)
  adding: waitress/channel.py (deflated 72%)
  adding: waitress/task.pyc (deflated 57%)
  adding: waitress/tests/ (stored 0%)
  adding: waitress/tests/test_regression.py (deflated 63%)
  adding: waitress/tests/test_functional.py (deflated 88%)
  adding: waitress/tests/test_parser.pyc (deflated 76%)
  adding: waitress/tests/test_trigger.pyc (deflated 73%)
  adding: waitress/tests/test_init.py (deflated 72%)
  adding: waitress/tests/test_utilities.pyc (deflated 78%)
  adding: waitress/tests/test_buffers.pyc (deflated 79%)
  adding: waitress/tests/test_trigger.py (deflated 82%)
  adding: waitress/tests/test_buffers.py (deflated 86%)
  adding: waitress/tests/test_runner.py (deflated 75%)
  adding: waitress/tests/test_init.pyc (deflated 69%)
  adding: waitress/tests/__init__.pyc (deflated 21%)
  adding: waitress/tests/support.pyc (deflated 48%)
  adding: waitress/tests/test_utilities.py (deflated 73%)
  adding: waitress/tests/test_channel.py (deflated 87%)
  adding: waitress/tests/test_task.py (deflated 87%)
  adding: waitress/tests/test_functional.pyc (deflated 82%)
  adding: waitress/tests/__init__.py (deflated 5%)
  adding: waitress/tests/test_compat.pyc (deflated 53%)
  adding: waitress/tests/test_receiver.pyc (deflated 79%)
  adding: waitress/tests/test_adjustments.py (deflated 78%)
  adding: waitress/tests/test_adjustments.pyc (deflated 74%)
  adding: waitress/tests/test_server.pyc (deflated 73%)
  adding: waitress/tests/fixtureapps/ (stored 0%)
  adding: waitress/tests/fixtureapps/filewrapper.pyc (deflated 59%)
  adding: waitress/tests/fixtureapps/getline.py (deflated 37%)
  adding: waitress/tests/fixtureapps/nocl.py (deflated 47%)
  adding: waitress/tests/fixtureapps/sleepy.pyc (deflated 44%)
  adding: waitress/tests/fixtureapps/echo.py (deflated 40%)
  adding: waitress/tests/fixtureapps/error.py (deflated 52%)
  adding: waitress/tests/fixtureapps/nocl.pyc (deflated 48%)
  adding: waitress/tests/fixtureapps/getline.pyc (deflated 32%)
  adding: waitress/tests/fixtureapps/writecb.pyc (deflated 42%)
  adding: waitress/tests/fixtureapps/toolarge.py (deflated 37%)
  adding: waitress/tests/fixtureapps/__init__.pyc (deflated 20%)
  adding: waitress/tests/fixtureapps/writecb.py (deflated 50%)
  adding: waitress/tests/fixtureapps/badcl.pyc (deflated 44%)
  adding: waitress/tests/fixtureapps/runner.pyc (deflated 58%)
  adding: waitress/tests/fixtureapps/__init__.py (stored 0%)
  adding: waitress/tests/fixtureapps/filewrapper.py (deflated 74%)
  adding: waitress/tests/fixtureapps/runner.py (deflated 41%)
  adding: waitress/tests/fixtureapps/echo.pyc (deflated 42%)
  adding: waitress/tests/fixtureapps/groundhog1.jpg (deflated 24%)
  adding: waitress/tests/fixtureapps/error.pyc (deflated 48%)
  adding: waitress/tests/fixtureapps/sleepy.py (deflated 42%)
  adding: waitress/tests/fixtureapps/toolarge.pyc (deflated 43%)
  adding: waitress/tests/fixtureapps/badcl.py (deflated 45%)
  adding: waitress/tests/support.py (deflated 52%)
  adding: waitress/tests/test_task.pyc (deflated 78%)
  adding: waitress/tests/test_channel.pyc (deflated 78%)
  adding: waitress/tests/test_regression.pyc (deflated 68%)
  adding: waitress/tests/test_parser.py (deflated 80%)
  adding: waitress/tests/test_server.py (deflated 78%)
  adding: waitress/tests/test_receiver.py (deflated 87%)
  adding: waitress/tests/test_compat.py (deflated 51%)
  adding: waitress/tests/test_runner.pyc (deflated 72%)
  adding: waitress/__init__.pyc (deflated 50%)
  adding: waitress/channel.pyc (deflated 58%)
  adding: waitress/runner.pyc (deflated 54%)
  adding: waitress/buffers.py (deflated 74%)
  adding: waitress/__init__.py (deflated 61%)
  adding: waitress/runner.py (deflated 58%)
  adding: waitress/parser.py (deflated 69%)
  adding: waitress/compat.py (deflated 69%)
  adding: waitress/buffers.pyc (deflated 69%)
  adding: waitress/utilities.pyc (deflated 60%)
  adding: waitress/parser.pyc (deflated 53%)
  adding: waitress/task.py (deflated 72%)
  adding: waitress-0.8.5-py2.7.Egg-info/ (stored 0%)
  adding: waitress-0.8.5-py2.7.Egg-info/dependency_links.txt (stored 0%)
  adding: waitress-0.8.5-py2.7.Egg-info/installed-files.txt (deflated 83%)
  adding: waitress-0.8.5-py2.7.Egg-info/top_level.txt (stored 0%)
  adding: waitress-0.8.5-py2.7.Egg-info/PKG-INFO (deflated 65%)
  adding: waitress-0.8.5-py2.7.Egg-info/not-Zip-safe (stored 0%)
  adding: waitress-0.8.5-py2.7.Egg-info/SOURCES.txt (deflated 71%)
  adding: waitress-0.8.5-py2.7.Egg-info/entry_points.txt (deflated 33%)
  adding: waitress-0.8.5-py2.7.Egg-info/requires.txt (deflated 5%)
[zart@feena unpacked]$ cd ..

これらのファイルはZipの一番上にある必要があることに注意してください。Zip -r9 library.Zip unpacked

結果の確認:

[zart@feena ziplib-demo]$ PYTHONPATH=library.Zip python
Python 2.7.1 (r271:86832, Apr 12 2011, 16:15:16)
[GCC 4.6.0 20110331 (Red Hat 4.6.0-2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import waitress
>>> waitress
<module 'waitress' from '/home/zart/ziplib-demo/library.Zip/waitress/__init__.pyc'>
>>>
>>> from wsgiref.simple_server import demo_app
>>> waitress.serve(demo_app)
serving on http://0.0.0.0:8080
^C>>>

更新:python 3.5なので、 zipapp module もあります。これは、パッケージ全体を.pyzファイルに変換します。より複雑なニーズの場合は、 pyinstallerpy2exe または py2app の方が適しています。

37
Zart

Pythonは、Zipファイルに__main __。py [c]ファイルが最上位に含まれている場合、Zipファイルを単一のスクリプトのように実行します。パッケージのインポートは、__ main__が内部から実行されていることをZipの内部でも確認します。

そのため、setup.pyを作成します(py_modules = ['__main__']は、すべてのパッケージと他のモジュールを指定するとともに、ここで重要です)。

次に、python setup.py bdist --format Zipを実行してZipファイルを作成します。実行可能にしたい場合は、次のようにします。この時点で、他のpythonスクリプトと同様に、結果のZipファイルを実行できます。

Linux/Macユーザーがこれを読んで利便性を向上させるためのもう1つの手順(py2exeについて言及しているように、おそらくシナリオではありません)

echo '#!/usr/bin/env python' > my_executable_Zip
cat output_of_setup_py_bdist.Zip >> my_executable_Zip
chmod +x my_executable_Zip

これは単に#を付加するだけです!シェルから実行するときにインタープリターを指定する必要がないように、Zipファイルに行を追加します。この時点では、システム上の他のバイナリと同様に実行できますが、密かにpythonでいっぱいのZipファイルです。私は通常、makefileを作成してsetup.pyを実行してから、この変換を行います。

10
Matt

標準ライブラリの zipapp モジュールを使用して、実行可能ファイルPython Zipアーカイブを作成できます。これは、Python 3.5以降から入手できます。

バンドルを作成する1つの方法は、__main__.pyという名前の最上位ファイルを追加することです。これは、Zip実行可能アーカイブの実行時にPythonが実行されるスクリプトです。

ディレクトリ構造が次のようになっているとします。

└── myapp
    ├── __main__.py
    ├── myprog1.py
    └── myprog2.py

コードに外部依存関係がある場合(たとえば、requirements.txtという名前のファイルにリストされている場合)は、以下を使用してそれらをディレクトリにインストールします。

pip3 install -r requirements.txt --target myapp/

注1:これにより、myapp/ディレクトリに外部依存関係が設定されます。

注2:Debian/Ubuntuバージョンのpipはデフォルトで--systemを使用するようになっているため、Debian/Ubuntuユーザーはpip3--userオプションを使用する必要がある場合があります。

次に、以下を使用してZip実行可能アーカイブを作成します。

python3 -m zipapp myapp/

これにより、myapp.pyzという名前のZip実行可能アーカイブが作成され、次のコマンドを実行して実行できます。

python3 myapp.pyz

Zip実行可能アーカイブが実行されると、実行されるのは__main__.pyです。

Pythonスクリプトに加えて、Pythonスクリプトによって使用される他のデータファイルを含める必要がある場合は、以下を参照してください。 python:can executable Zipファイルにはデータファイルが含まれますか?

1
Flux

はい、1つのZipファイル/卵で複数のモジュールを提供できるため、それらを1つのファイルに結合できます。しかし、私はそれが良い考えであることに非常に懐疑的です。まだそのZipファイルをインストールする必要があり、それはまだ他のすでにインストールされているバージョンなどと衝突する可能性があります。

したがって、最初に尋ねる質問は、目的が何であるかです。なぜ1つのファイルだけが必要なのですか?インストールのしやすさ、配布のしやすさ、それとも何ですか?

ファイルが1つしかない場合でも、インストールは実際には簡単にはなりません。他にも、より良い方法があります。インストールに依存関係を自動的にダウンロードおよびインストールさせることができます。これは簡単です。

そして、それらを1つのZipファイルに含めることは、そのZipファイルを展開してsetup.pyを実行する必要があることを意味しますが、ユーザーフレンドリーではありません。

したがって、1つのファイルだけでは実際には多くの問題が解決されないため、問題はどの問題を解決しようとしているのかということです。

1
Lennart Regebro

ええと、{app-home-dir/packages}に独自の "packages/eggs"を作成し(eggsをそこにコピーするなど)、setup.py(setuptools)で追加ファイルを構成して、すべてを単一のディストリビューションとしてパックすることができます。 ( setup.pyとは )。アプリのメイン関数を起動する前に、Python正確に外部の "packages/eggs"がどこにあるかを通知する必要があることに注意してください-sys.pathに{app-home-dir/packages}を追加します。 。これは、スタンドアロンパッケージを作成する簡単な方法です。ただし、依存関係とそのバージョン、PythonモジュールとAnsi Cコードが混在しているなど)に関して危険が伴います。

0
soerium

すべての卵を1つのZipファイルにどうにか結合できますか?もしそうなら、どうですか?

はい、できます。 Pythonは、sys.pathに追加されたZipアーカイブからロードされます( PEP 27 を参照)。すべてを配置した場合pythonライブラリアーカイブ内では、アーカイブはディレクトリとして扱われ、これはpy2exe、bbfreezeなどのツールがライブラリを分離するために実行できることです。

方法については、pig、easy_installなど、卵のインストール方法によって異なります。ロジックは、依存するすべての卵を検査し、インストールパスを収集してから、卵をアーカイブ内にZip圧縮することです。

特定の卵からコードをどのようにロードして実行しますか?

ロードと実行を定義する必要があります。モジュールとパッケージのインポートについて話している場合は、特別なことをする必要はありません。これは、いくつかの警告を含む、件名に関する興味深いブログ投稿です Packaging Pythonプログラムを実行可能なZipファイルとして

そのEgg内のコードがすべての依存関係(つまり、Zipファイル内の他の卵)にアクセスできることをどのように保証しますか?

これは、卵が拡張機能でない(つまり、Zipセーフ)限り、組み込みです。参照 zipimport

0
Rod

自己解凍Zipファイル を使用して、Pythonインタープリターを、それらを含む非常に同じ.exeファイル内から解凍した後に起動するように設定できます。

0
John Zwinck