Skip to main content

28.4. zipapp —管理可执行的python zip存档

3.5 新版功能.

源代码: Lib/zipapp.py


此模块提供了管理包含Python代码(可以是 直接由Python解释器执行)的zip文件的创建的工具。该模块提供 命令行界面Python API

28.4.1. 基本示例

以下示例显示了如何使用 命令行界面 从包含Python代码的目录创建可执行归档。运行时,归档将从归档中的模块 myapp 执行 main 功能。

$ python -m zipapp myapp -m "myapp:main"
$ python myapp.pyz
<output from myapp>

28.4.2. 命令行界面

当从命令行调用为程序时,使用以下形式:

$ python -m zipapp source [options]

如果 source 是目录,则将从 source 的内容创建归档。如果 source 是一个文件,它应该是一个存档,并且它将被复制到目标存档(或者如果指定了–info选项,将显示其shebang行的内容)。

以下选项被理解:

-o <output>, --output=<output>

将输出写入名为 output 的文件。如果未指定此选项,则输出文件名将与输入 source 相同,并添加扩展名 .pyz。如果给出了显式文件名,则按原样使用(因此,如果需要,应包括 .pyz 扩展名)。

如果 source 是存档,则必须指定输出文件名(在这种情况下,output 不能与 source 相同)。

-p <interpreter>, --python=<interpreter>

#! 行添加到指定 interpreter 的归档作为要运行的命令。此外,在POSIX上,使归档可执行。默认是不写入 #! 行,并且不使文件可执行。

-m <mainfn>, --main=<mainfn>

__main__.py 文件写入执行 mainfn 的归档。 mainfn 参数的格式应为“pkg.mod:fn”,其中“pkg.mod”是存档中的包/模块,“fn”是给定模块中的可调用。 __main__.py 文件将执行该可调用。

复制存档时无法指定 --main

--info

显示嵌入在归档中的解释器,用于诊断目的。在这种情况下,将忽略任何其他选项,SOURCE必须是归档,而不是目录。

-h, --help

打印简短的使用消息并退出。

28.4.3. Python API

模块定义了两个方便的功能:

zipapp.create_archive(source, target=None, interpreter=None, main=None)

source 创建应用程序归档。源可以是以下任何一种:

  • 目录的名称或引用目录的 pathlib.Path 对象,在这种情况下,将从该目录的内容创建新的应用程序归档。

  • 现有应用程序归档文件的名称或引用此类文件的 pathlib.Path 对象,在这种情况下,将文件复制到目标(修改它以反映为 interpreter 参数指定的值)。如果需要,文件名应包括 .pyz 扩展名。

  • 以字节模式读取的文件对象。文件的内容应该是应用程序归档,并且文件对象假定位于归档的开头。

target 参数确定将写入结果归档的位置:

  • 如果它是文件的名称或 pathlb.Path 对象,则归档将被写入该文件。

  • 如果它是一个打开的文件对象,则归档将被写入该文件对象,该对象必须打开以便以字节模式写入。

  • 如果省略目标(或 None),则源必须是目录,目标将是与源名称相同的文件,并添加 .pyz 扩展名。

interpreter 参数指定将执行归档的Python解释器的名称。它在归档开始时写为“shebang”行。在POSIX上,这将被操作系统解释,在Windows上它将由Python启动器处理。省略 interpreter 将导致没有shebang行被写入。如果指定了解释器,并且目标是文件名,则将设置目标文件的可执行位。

main 参数指定将被用作归档的主程序的可调用的名称。它只能在源是目录且源尚未包含 __main__.py 文件时指定。 main 参数应该采用“pkg.module:callable”的形式,并且通过导入“pkg.module”并执行没有参数的给定callable来运行归档。如果源是目录并且不包含 __main__.py 文件,那么省略 main 是错误,否则生成的归档将不可执行。

如果为 sourcetarget 指定了文件对象,则调用者在调用create_archive之后应该关闭它。

复制现有归档时,提供的文件对象只需要 readreadlinewrite 方法。从目录创建归档时,如果目标是文件对象,它将被传递到 zipfile.ZipFile 类,并且必须提供该类所需的方法。

zipapp.get_interpreter(archive)

返回在归档开始时在 #! 行中指定的解释器。如果没有 #! 线,则返回 Nonearchive 参数可以是以字节模式读取的文件名或类似文件的对象。它假定在归档的开始。

28.4.4. 例子

将目录打包到归档中,然后运行它。

$ python -m zipapp myapp
$ python myapp.pyz
<output from myapp>

同样可以使用 create_archive() 功能:

>>> import zipapp
>>> zipapp.create_archive('myapp.pyz', 'myapp')

要使应用程序在POSIX上直接可执行,请指定要使用的解释器。

$ python -m zipapp myapp -p "/usr/bin/env python"
$ ./myapp.pyz
<output from myapp>

要替换现有归档上的shebang行,请使用 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”(或其他形式的“python”命令,如“/usr/bin/python”),你需要考虑你的用户可能有Python 2或Python 3作为它们的默认值,并且编写代码以在两个版本下工作。

  • 如果您使用显式版本,例如“/usr/bin/env python3”,您的应用程序将不适用于没有该版本的用户。 (这可能是你想要的,如果你没有使你的代码Python 2兼容)。

  • 没有办法说“python XY或更高版本”,所以要小心使用像“/usr/bin/env python3.4”的确切版本,因为你需要为Python 3.5的用户更改你的shebang行,例如。

28.4.5. Python Zip应用程序存档格式

Python自2.6版本起就能够执行包含 __main__.py 文件的zip文件。为了由Python执行,应用程序归档只需要是包含 __main__.py 文件的标准zip文件,该文件将作为应用程序的入口点运行。像任何Python脚本一样,脚本的父代(在这种情况下是zip文件)将放置在 sys.path 上,因此可以从zip文件导入更多的模块。

zip文件格式允许将任意数据添加到zip文件。 zip应用程序格式使用此功能在文件(#!/path/to/interpreter)前面添加标准POSIX“shebang”行。

正式来说,Python zip应用程序格式是:

  1. 可选的shebang行,包含字符 b'#!' 后跟解释器名称,然后是换行符(b'\n')字符。解释器名称可以是操作系统“shebang”处理或Windows上的Python启动器可接受的任何名称。解释器应该在Windows上以UTF-8编码,在POSIX上以 sys.getfilesystemencoding() 编码。

  2. 标准zipfile数据,由 zipfile 模块生成。 zip文件内容 must 包括一个名为 __main__.py 的文件(它必须在zip文件的“根”中 - 即它不能在子目录中)。 zipfile数据可以是压缩或未压缩的。

如果应用程序归档具有shebang行,则它可以在POSIX系统上设置可执行位,以允许它直接执行。

没有要求该模块中的工具用于创建应用程序归档 - 该模块是方便的,但是通过任何方式创建的上述格式的归档都可以被Python接受。