Как вы можете объединить весь код python в один zip-файл?

было бы удобно при распространении приложений для объединения все яиц в один zip-файл, так что все, что вам нужно распространять, это один zip-файл и исполняемый файл (некоторый пользовательский двоичный файл, который просто запускается, загружает основную функцию zip-файла и запускает python или аналогичный).

Я видел некоторые разговоры об этом в интернете, но нет примеров того, как это сделать.

Я знаю, что вы можете (если его zip safe) конвертировать яйца в zip файлы.

в чем я не уверен-это:

можете ли вы как-то объединить все свои яйца в один zip-файл? Если да, то как?

Как бы вы загрузили и запустили код из определенного яйца?

Как бы вы гарантировали, что код в этом яйце может получить доступ ко всем зависимостям (т. е. другие яйца в zip-файле)?

люди спрашивают такие вещи много и получают ответы, как; используйте py2exe. Да, я понимаю, это одно из решений. Это не вопрос я хотя спрашиваю здесь...

6 ответов


вы можете автоматизировать большую часть работы с обычными инструментами 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.

теперь давайте установим набор пакетов,которые войдут в библиотеку zipped. Фокус в том, чтобы принудительно установить их в определенный каталог.

(Примечание: не используйте опцию --egg ни в командной строке, ни в pip.conf / pip.ini, потому что он сломает макет файла, делая его не импортируемым в 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...

обновление: теперь pip имеет -t <path> переключатель, который делает то же самое как --install-option --install-lib=.

теперь давайте соберем их все в один 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 что может помочь с связывать весь пакет В.файл pyz. Для более сложных нужд pyinstaller, py2exe или py2app может лучше подойти.


Python будет выполнять zip-файлы, как если бы они были одиночными скриптами, если они содержат __main__.py [c] файл внутри на верхнем уровне. Импорт пакетов также будет проверять внутри zip, что _ _ main_ _ выполняется изнутри.

так создайте свой setup.py (py_modules = ['__main__'] здесь важно указать все ваши пакеты и другие модули).

выполнить python setup.py bdist --format zip для создания zip-файла. Теперь, если вы хотите, чтобы он был исполняемым, вы можете сделать следующее. В этот момент Вы можете выполните полученный zip-файл, как и любой другой скрипт python.

еще один шаг для пользователей Linux / Mac, читающих это, чтобы улучшить удобство (хотя, вероятно, не ваш сценарий, как вы упоминаете 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-файл так, что при запуске из оболочки вам не нужно указывать переводчика. На данный момент Вы можете выполнить его как любой другой двоичный файл в системе, хотя тайно это zip-файл, полный python. Обычно я создаю makefile для запуска setup.py а затем сделайте это преобразование.


да, один zip-файл / яйцо может предоставить несколько модулей, поэтому вы можете объединить их в один файл. Однако я очень скептически отношусь к тому, что это хорошая идея. Вам все равно нужно установить этот zip-файл, и он все равно может столкнуться с другими уже установленными версиями и т. д.

Итак, первый вопрос, который нужно задать, - это цель. Почему вам нужен только один файл? Это для простоты установки, или для простоты распространения, или что?

только один файл не будет работать установить проще, есть другие, лучшие способы. Вы можете позволить установить загрузку и установить зависимости автоматически, это легко сделать.

и наличие их в одном zip-файле по-прежнему означает, что вам нужно развернуть этот zip-файл и запустить setup.py что не очень-то удобно.

таким образом, наличие только одного файла на самом деле не решает многих проблем, поэтому вопрос в том, какую проблему вы пытаетесь решить.


вы могли бы использовать самораспаковывающийся zip, настроить для запуска интерпретатора Python после распаковки яиц изнутри того же самого .exe-файл, содержащий их.


Ну, можно создать свои собственные "пакеты / яйца" в вашем {app-home-dir/packages} (например, справившись с яйцами там) и настроить дополнительные файлы в setup.py (setuptools), чтобы упаковать все это как один дистрибутив (что такое setup.py?). Обратите внимание, что перед запуском основной функции приложения вам необходимо сообщить Python, где именно находятся ваши внешние "пакеты/яйца", добавив {app - home-dir/packages} в sys.путь. Это простой способ создания автономного пакета ..однако с этим связаны опасности, связанные с зависимостями и их версиями, модулями Python, смешанными с кодом Ansi C и т. д.


можете ли вы как-то объединить все свои яйца в один zip-файл? Если да, то как?

Да, вы можете. Python будет загружаться из zip-архива, добавленного в sys.путь (см. PEP 273). Если вы поместите все библиотеки python в архив, архив будет рассматриваться как каталог. Это то, что некоторые из py2exe, bbfreeze и т. д. инструменты могут сделать, чтобы изолировать библиотеки.

Что касается того, как, это действительно зависит от того, как установлены ваши яйца: pip, easy_install и т. д. Логика заключалась бы в том, чтобы проверить все зависимые яйца и собрать их путь установки, а затем застегнуть яйца внутри архива.

Как бы вы загрузили и запустили код из определенного яйца?

вам нужно определить нагрузку и выполнить. Если вы говорите об импорте модуля и пакетов, вам ничего не нужно делать специальный. Вот интересный пост в блоге на эту тему, включая некоторые нюанс упаковка программ Python как runnable ZIP файлы

Как бы вы гарантировали, что код в этом яйце может получить доступ ко всем зависимостям (т. е. другие яйца в zip-файле)?

это встроено до тех пор, пока яйца не являются расширениями (т. е. zip safe). См. также zipimport