如何将所有 python 代码打包成一个 zip 文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17486578/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can you bundle all your python code into a single zip file?
提问by Doug
It would be convenient when distributing applications to combine allof the eggs into a single zip file so that all you need to distribute is a single zip file and an executable (some custom binary that simply starts, loads the zip file's main function and kicks python off or similar).
在分发应用程序时将所有的鸡蛋组合到一个 zip 文件中会很方便,这样您只需要分发一个 zip 文件和一个可执行文件(一些自定义二进制文件,只需启动,加载 zip 文件的主要功能并启动 python关闭或类似)。
I've seen some talk of doing this online, but no examples of how to actually do it.
我在网上看到了一些关于这样做的讨论,但没有实际操作的例子。
I'm aware that you can (if it is zip safe) convert eggs into zip files.
我知道您可以(如果它是 zip 安全的)将鸡蛋转换为 zip 文件。
What I'm not sure about is:
我不确定的是:
Can you somehow combine all your eggs into a single zip file? If so, how?
你能以某种方式将所有的鸡蛋组合成一个 zip 文件吗?如果是这样,如何?
How would you load and run code from a specific egg?
你将如何从特定的鸡蛋加载和运行代码?
How would you ensure that the code in that egg could access all the dependencies (ie. other eggs in the zip file)?
您如何确保该鸡蛋中的代码可以访问所有依赖项(即 zip 文件中的其他鸡蛋)?
People ask this sort of stuff a lot and get answers like; use py2exe. Yes, I get it, that's one solution. It's not the question I'm asking here though...
人们经常问这类问题,得到的答案是:使用 py2exe。是的,我明白了,这是一种解决方案。虽然这不是我在这里问的问题......
采纳答案by Zart
You can automate most of the work with regular python tools. Let's start with clean virtualenv.
您可以使用常规 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.
Now let's install set of packages that will go into zipped library. The trick is to force installing them into specific directory.
现在让我们安装一组将进入压缩库的软件包。诀窍是强制将它们安装到特定目录中。
(Note: don't use --egg option either on command-line or in pip.conf/pip.ini because it will break file layout making it non-importable in 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 now has -t <path>
switch, that does the same thing as --install-option --install-lib=
.
更新:pip 现在有-t <path>
开关,它与--install-option --install-lib=
.
Now let's pack all of them into one zip
现在让我们将它们全部打包成一个 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 ..
Note that those files should be at top of zip, you can't just zip -r9 library.zip unpacked
请注意,这些文件应该位于 zip 的顶部,您不能只是 zip -r9 library.zip unpacked
Checking the result:
检查结果:
[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>>>
Update:since python 3.5 there is also zipapp modulewhich can help with bundling the whole package into .pyz file. For more complex needs pyinstaller, py2exeor py2appmight better fit the bill.
更新:从 python 3.5 开始,还有zipapp 模块可以帮助将整个包捆绑到 .pyz 文件中。对于更复杂的需求pyinstaller、py2exe或py2app可能更适合该法案。
回答by John Zwinck
You could use a self-extracting zip file, set up to launch a Python interpreter after decompressing the eggs from within the very same .exe file that contains them.
您可以使用自解压 zip 文件,设置为在从包含它们的同一个 .exe 文件中解压鸡蛋后启动 Python 解释器。
回答by Lennart Regebro
Yes, one zip-file/egg can provide multiple modules, so you can combine them into one file. I'm however highly skeptical to that being a good idea. You still need to install that zip-file, and it may still clash with other already installed versions, etc.
是的,一个 zip-file/egg 可以提供多个模块,因此您可以将它们组合成一个文件。然而,我非常怀疑这是一个好主意。您仍然需要安装该 zip 文件,并且它可能仍会与其他已安装的版本等发生冲突。
So the first question to ask is what the aim is. Why do you want just one file? Is it for ease of install, or ease of distribution, or what?
所以首先要问的问题是目标是什么。为什么你只想要一个文件?是为了便于安装,还是为了便于分发,还是什么?
Having just one file will not really make the install easier, there are other, better ways. You can let the install download and install the dependencies automatically, that's easy to do.
只有一个文件不会真正使安装更容易,还有其他更好的方法。您可以让安装自动下载并安装依赖项,这很容易做到。
And having them in one zip-file still means you need to expand that zip-file and run setup.py, which isn't very userfriendly.
将它们放在一个 zip 文件中仍然意味着您需要扩展该 zip 文件并运行 setup.py,这对用户来说不是很友好。
So having just one file doesn't really solve many problems, so the question is which problem you are trying to solve.
所以只有一个文件并不能真正解决很多问题,所以问题是你要解决哪个问题。
回答by soerium
Well, it's possible to create your own "packages/eggs" in your {app-home-dir/packages} (by coping eggs there for example) and configure extra files in setup.py (setuptools) to pack it all as single distribution (What is setup.py?). Note, that before you launch your app main function you need to inform Python where exactly your external "packages/eggs" are - by adding {app-home-dir/packages} to sys.path. That is the easies way to create standalone package ..however with that goes dangers regarding dependencies and their versions, Python modules mixed with Ansi C code, etc.
好吧,可以在您的 {app-home-dir/packages} 中创建您自己的“包/鸡蛋”(例如通过在那里处理鸡蛋)并在 setup.py(setuptools)中配置额外的文件以将其全部打包为单一发行版(什么是 setup.py?)。请注意,在启动应用程序 main 函数之前,您需要通过将 {app-home-dir/packages} 添加到 sys.path 来通知 Python 您的外部“包/鸡蛋”的确切位置。这是创建独立包的简单方法……但是,这会带来依赖项及其版本、与 Ansi C 代码混合的 Python 模块等方面的危险。
回答by Rod
Can you somehow combine all your eggs into a single zip file? If so, how?
你能以某种方式将所有的鸡蛋组合成一个 zip 文件吗?如果是这样,如何?
Yes you can. Python will load from zip archive that are added in sys.path (see PEP 273). If you put all python libraries inside an archive, the archive is treated as a directory. This is what some of the py2exe, bbfreeze, etc. tools can do to isolate the libraries.
是的你可以。Python 将从 sys.path 中添加的 zip 存档加载(请参阅PEP 273)。如果将所有 python 库放在一个存档中,则该存档将被视为一个目录。这是一些 py2exe、bbfreeze 等工具可以用来隔离库的功能。
As for the how, it really depends on how your eggs are installed: pip, easy_install, etc. The logic would be to inspect all you dependent eggs and gather their install path and then zip the eggs inside an archive.
至于如何安装,这实际上取决于您的鸡蛋的安装方式:pip、easy_install 等。逻辑是检查所有依赖的鸡蛋并收集它们的安装路径,然后将鸡蛋压缩到存档中。
How would you load and run code from a specific egg?
你将如何从特定的鸡蛋加载和运行代码?
You need to define load and run. If you are talking about importing module and packages, you do not have to do anything special. Here is an interesting blog post on the subject including some caveat Packaging Python programs as runnable ZIP files
您需要定义加载和运行。如果您正在谈论导入模块和包,您不必做任何特别的事情。这是一篇关于该主题的有趣博客文章,其中包括一些警告将Python 程序打包为可运行的 ZIP 文件
How would you ensure that the code in that egg could access all the dependencies (ie. other eggs in the zip file)?
您如何确保该鸡蛋中的代码可以访问所有依赖项(即 zip 文件中的其他鸡蛋)?
This is built-in as long as the eggs are not extensions (ie zip safe). See also zipimport
只要鸡蛋不是扩展(即 zip 安全),这是内置的。另见zipimport
回答by Matt
Python will execute zip files as if they were single scripts if they contain an __main__.py[c] file inside at the top level. Package imports will then also check inside the zip that __main__ is executing from within.
如果 zip 文件在顶层包含 __main__.py[c] 文件,则 Python 会将它们作为单个脚本执行。然后,包导入还将检查 __main__ 正在从内部执行的 zip 内部。
So create your setup.py (py_modules = ['__main__']
is important here along with specifying all your packages and other modules).
所以创建你的 setup.py (py_modules = ['__main__']
在这里很重要,同时指定你的所有包和其他模块)。
Then run python setup.py bdist --format zip
to create the zip file. Now if you want it to be executable you can do the following. At this point you can execute the resulting zip file like any other python script.
然后运行python setup.py bdist --format zip
以创建 zip 文件。现在,如果您希望它是可执行的,您可以执行以下操作。此时,您可以像执行任何其他 python 脚本一样执行生成的 zip 文件。
One more step for Linux/Mac users reading this to improve convenience (although probably not your scenario as you mention py2exe)
阅读本文的 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
This just prepends a #! line to the zip file so that when run from the shell you do not need to specify the interpreter. At this point you can execute it like any other binary on the system although secretly it is a zip file full of python. I typically create a makefile to run setup.py and then do this conversion.
这只是在前面加上一个 #! 行到 zip 文件,这样当从 shell 运行时,您不需要指定解释器。此时你可以像系统上的任何其他二进制文件一样执行它,尽管它是一个充满 python 的 zip 文件。我通常会创建一个 makefile 来运行 setup.py,然后进行此转换。
回答by Flux
You can use the zipappmodule from the standard library to create executable Python zip archives. It is available from Python 3.5 onwards.
您可以使用标准库中的zipapp模块来创建可执行的 Python zip 存档。它从 Python 3.5 开始可用。
One way to create a bundle is to add a top-level file named __main__.py
, which will be the script that Python runs when the zip executable archive is executed.
创建包的一种方法是添加一个名为 的顶级文件__main__.py
,该文件将是执行 zip 可执行存档时 Python 运行的脚本。
Suppose your directory structure is now like this:
假设你的目录结构现在是这样的:
└── myapp
├── __main__.py
├── myprog1.py
└── myprog2.py
If your code has external dependencies (e.g. listed in a file named requirements.txt
), install them into the directory using:
如果您的代码具有外部依赖项(例如在名为 的文件中列出requirements.txt
),请使用以下命令将它们安装到目录中:
pip3 install -r requirements.txt --target myapp/
note 1: This will fill the myapp/
directory with the external dependencies.
注意 1:这将myapp/
使用外部依赖项填充目录。
note 2: Debian/Ubuntu users may need to use the --system
option for pip3
, because the Debian/Ubuntu version of pip seems to default to using --user
by default.
注意 2:Debian/Ubuntu 用户可能需要使用--system
选项pip3
,因为 Debian/Ubuntu 版本的 pip 似乎默认使用--user
默认设置。
Then, create the zip executable archive using:
然后,使用以下命令创建 zip 可执行存档:
python3 -m zipapp myapp/
This will create a zip executable archive named myapp.pyz
, which you can execute by running:
这将创建一个名为 的 zip 可执行存档myapp.pyz
,您可以通过运行来执行它:
python3 myapp.pyz
When the zip executable archive is executed, it is __main__.py
that is run.
当 zip 可执行存档被执行时,它__main__.py
就是运行。
If, in addition to Python scripts, you need to include other data files (e.g. text files, PNG images, etc.) used by the Python scripts, see: python: can executable zip files include data files?
如果除了 Python 脚本之外,还需要包含 Python 脚本使用的其他数据文件(例如文本文件、PNG 图像等),请参阅:python:可执行的 zip 文件可以包含数据文件吗?