28.4. zipapp - 管理可执行文件python zip档案

版本3.5中的新功能。

源代码: Lib / zipapp.py

此模块提供的工具可用于管理包含Python代码的zip文件的创建,这种zip文件可直接被Python解释器执行该模块提供命令行界面Python API

28.4.1. Basic Example

以下示例说明如何从包含Python代码的目录使用命令行界面创建可执行文件。When run, the archive will execute the main function from the module myapp in the archive.

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

28.4.2. Command-Line Interface

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

$ python -m zipapp source [options]

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

以下选项被理解:

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

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

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

-p <interpreter>, --python=<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)

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

  • 目录的名称或指向目录的pathlib.Path对象,在这种情况下,将从该目录的内容创建新的应用程序归档。
  • 现有应用程序归档文件的名称或引用此类文件的pathlib.Path对象,在这种情况下,将文件复制到目标(修改它以反映为>解释器参数)。如果需要,文件名应包含.pyz扩展名。
  • 以字节模式读取的文件对象。文件的内容应该是应用程序归档,并且文件对象假定位于归档的开始。

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

  • 如果它是文件的名称或pathlb.Path对象,则归档将写入该文件。
  • 如果它是一个打开的文件对象,则归档将被写入该文件对象,该对象必须打开以便以字节模式写入。
  • 如果省略目标(或无),则源必须是目录,目标将是与源相同名称的文件,并添加了.pyz扩展名。

解释器参数指定将要执行归档的Python解释器的名称。它在归档开始时写为“shebang”行。在POSIX上,这将被操作系统解释,在Windows上它将由Python启动程序处理。省略解释器会导致没有写入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. Examples

将目录封装到归档中,并运行它。

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

同样可以使用create_archive() functon:

>>> 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. The Python Zip Application Archive Format

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')字符。解释器名称可以是OS“shebang”处理或Windows上的Python启动器可接受的任何名称。解释器应该在Windows上以UTF-8编码,在POSIX上在sys.getfilesystemencoding()中编码。
  2. 标准zip文件数据,由zipfile模块生成。zip文件内容必须包含一个名为__main__.py的文件(它必须位于zip文件的“根目录”中,即不能位于子目录中)。zipfile数据可以是压缩的或未压缩的。

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

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