如何将所有python代码捆绑到一个zip文件中?

时间:2013-07-05 10:23:42

标签: python setup.py pypi

在分发应用程序以将鸡蛋的所有组合到单个zip文件中时会很方便,因此您需要分发的只是一个zip文件和一个可执行文件(一些自定义二进制文件只是启动,加载zip文件的主要功能并踢掉python或类似的)。

我已经看过一些关于在线进行此操作的讨论,但没有关于如何实际执行此操作的示例。

我知道你可以(如果它的zip安全)将鸡蛋转换为zip文件。

我不确定的是:

你能以某种方式将所有鸡蛋合并成一个zip文件吗?如果是这样,怎么样?

如何加载和运行特定鸡蛋的代码?

您如何确保该鸡蛋中的代码可以访问所有依赖项(即zip文件中的其他鸡蛋)?

人们会问这类东西,并得到像这样的答案;使用py2exe。是的,我明白了,这是一个解决方案。这不是我在这里问的问题......

7 个答案:

答案 0 :(得分:31)

您可以使用常规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.

现在让我们安装一组将进入压缩库的软件包。诀窍是强制将它们安装到特定目录中。

(注意:不要在命令行或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...

更新:pip现在有-t <path>次切换,与--install-option --install-lib=完全相同。

现在让我们将所有这些打包成一个拉链

[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文件中。对于更复杂的需求pyinstallerpy2exepy2app可能更适合该法案。

答案 1 :(得分:8)

您可以使用标准库中的zipapp模块来创建可执行的Python zip归档文件。从Python 3.5及更高版本开始可用。

创建捆绑包的一种方法是添加一个名为 $today = get-date $yesterday = (get-date).AddHours(-1) $Body = Get-QuarantineMessage -Direction Inbound -StartReceivedDate $yesterday -EndReceivedDate $today <#$CredUsername = $Cred.UserName $CredPassword = $Cred.GetNetworkCredential().Password Write-Output "-------------------------------------------------------------------------" Write-Output "Credential Properties: " Write-Output "Username: $CredUsername" Write-Output "Password: *************** `n" Write-Output "-------------------------------------------------------------------------" # Write-Output "Password: $CredPassword `n" 3#> } Send-MailMessage -To 'xisto@xisto.com' -Subject $subject -Body $Body -UseSsl -Port 587 -SmtpServer 'smtp.office365.com' -From $userid -BodyAsHtml -Credential $Cred Write-Output "Mail is now send `n" Write-Output "-------------------------------------------------------------------------" Remove-PSSession $ExchangeOnlineSession 的顶级文件,该文件将是执行zip可执行档案时Python运行的脚本。

假设您的目录结构现在是这样的:

__main__.py

如果您的代码具有外部依赖性(例如,在名为└── myapp ├── __main__.py ├── myprog1.py └── myprog2.py 的文件中列出),请使用以下命令将其安装到目录中:

requirements.txt

注释1:这将用外部依赖项填充pip3 install -r requirements.txt --target myapp/ 目录。

注释2:Debian / Ubuntu用户可能需要对myapp/使用--system选项,因为Debian / Ubuntu版本的pip似乎默认情况下使用pip3。 / p>

然后,使用以下命令创建zip可执行归档文件:

--user

这将创建一个名为python3 -m zipapp myapp/ 的zip可执行存档,您可以通过运行以下命令来执行该存档:

myapp.pyz

执行zip可执行文件存档时,将运行python3 myapp.pyz

如果除Python脚本之外,您还需要包括Python脚本使用的其他数据文件(例如,文本文件,PNG图像等),请参见:python: can executable zip files include data files?

答案 2 :(得分:7)

Python将执行zip文件,就好像它们是单个脚本一样,如果它们在顶层包含__main __。py [c]文件。然后,包导入也将检查__main__正在执行的zip内部。

所以创建你的setup.py(py_modules = ['__main__']在这里很重要,同时指定你所有的包和其他模块。)

然后运行python setup.py bdist --format zip以创建zip文件。现在,如果您希望它可执行,您可以执行以下操作。此时,您可以像执行任何其他python脚本一样执行生成的zip文件。

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文件,这样当从shell运行时,您不需要指定解释器。此时你可以像系统中的任何其他二进制文件一样执行它,虽然它是一个充满python的zip文件。我通常创建一个makefile来运行setup.py,然后进行转换。

答案 3 :(得分:1)

是的,一个zip文件/ egg可以提供多个模块,因此您可以将它们合并为一个文件。然而,我对这是个好主意持高度怀疑态度。您仍然需要安装该zip文件,它仍可能与其他已安装的版本等冲突。

所以要问的第一个问题是目标是什么。为什么你只想要一个文件?它是为了便于安装,还是易于分发,还是什么?

只有一个文件不会真正使安装更容易,还有其他更好的方法。您可以让安装程序自动下载并安装依赖项,这很容易做到。

将它们放在一个zip文件中仍然意味着您需要扩展该zip文件并运行setup.py,这对用户不太友好。

因此只有一个文件并不能解决很多问题,所以问题是你要解决的问题。

答案 4 :(得分:0)

您可以使用self-extracting zip file,设置为在从包含它们的同一个.exe文件中解压缩鸡蛋后启动Python解释器。

答案 5 :(得分:0)

嗯,可以在你的{app-home-dir / packages}中创建自己的“包/鸡蛋”(例如通过在那里处理鸡蛋)并在setup.py(setuptools)中配置额外的文件以将其全部打包作为单一分布(What is setup.py?)。请注意,在启动应用程序主要功能之前,您需要通过向sys.path添加{app-home-dir / packages}来告知Python外部“包/蛋”的确切位置。这是创建独立包的简单方法..然而,这会带来关于依赖关系及其版本的危险,Python模块与Ansi C代码混合等等。

答案 6 :(得分:0)

你能以某种方式将所有鸡蛋合并成一个zip文件吗?如果是这样,怎么样?

是的,你可以。 Python将从sys.path中添加的zip存档加载(参见PEP 273)。如果将所有python库放在归档中,则归档将被视为目录。这就是一些py2exe,bbfreeze等工具可以用来隔离库。

至于如何,它实际上取决于你的鸡蛋的安装方式:pip,easy_install等。逻辑是检查所有你依赖的鸡蛋并收集它们的安装路径然后将鸡蛋压缩到一个档案中。

您如何加载和运行特定鸡蛋的代码?

您需要定义加载并运行。如果您正在谈论导入模块和包,则无需执行任何操作 特别。这是一篇关于这个主题的有趣博客文章,包括一些警告Packaging Python programs as runnable ZIP files

您如何确保该鸡蛋中的代码可以访问所有依赖项(即zip文件中的其他鸡蛋)?

只要鸡蛋不是扩展(即拉链安全),这是内置的。另请参阅zipimport