Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 441 – 提升 Python ZIP 应用程序支持

作者:
Daniel Holth <dholth at gmail.com>, Paul Moore <p.f.moore at gmail.com>
讨论列表:
Python-Dev 邮件列表
状态:
最终版
类型:
标准轨迹
创建日期:
2013年3月30日
Python 版本:
3.5
历史记录:
2013年3月30日,2013年4月1日,2015年2月16日
决议:
Python-Dev 邮件列表

目录

提升 Python ZIP 应用程序支持

从 Python 2.6 版本开始 [1],Python 就具备将目录或 ZIP 格式的归档文件作为脚本执行的能力。当使用 zip 文件或目录作为其第一个参数调用解释器时,解释器会将该目录添加到 sys.path 并执行 __main__ 模块。这些归档文件提供了一种极好的方式来发布需要作为单个文件脚本分发的软件,但其复杂度足以需要编写为模块集合。

此功能的普及度不如预期,主要是因为它在 Python 2.6 中没有得到推广 [2],因此鲜为人知,同时也因为 Windows 安装程序没有为此格式的文件注册文件扩展名(除了 .py),以将其与启动器关联。

本 PEP 提出通过重新宣传此功能、将 .pyz.pyzw 扩展名定义为“Python ZIP 应用程序”和“窗口化 Python ZIP 应用程序”以及提供一些简单的工具来管理该格式来解决这些问题。

新的 Python ZIP 应用程序扩展

术语“Python Zip 应用程序”将是用于包含 Python 代码的 zip 格式归档文件的正式术语,该代码可以由 Python 直接执行(具体来说,它必须在归档文件的根目录中包含 __main__.py 文件)。扩展名 .pyz 将正式与这些文件相关联。

Python 3.5 安装程序将 .pyz.pyzw “Python Zip 应用程序”与平台启动器关联,以便可以执行它们。.pyz 归档文件是控制台应用程序,而 .pyzw 归档文件是窗口化应用程序,指示在运行应用程序时是否应显示控制台。

在 Unix 上,如果注册了 .pyz 扩展名和名称“Python Zip 应用程序”(在 mime 类型数据库中?),那将是理想的。但是,这种关联不在本 PEP 的范围内。

Python Zip 应用程序可以以指向正确 Python 解释器和可选说明的 #! 行为前缀。

#!/usr/bin/env python3
#  Python application packed with zipapp module
(binary contents of archive)

在 Unix 上,这允许操作系统通过标准的“shebang”支持使用正确的解释器运行该文件。在 Windows 上,Python 启动器实现了 shebang 支持。

但是,始终可以通过直接向 Python 解释器提供文件名来执行 .pyz 应用程序。

作为背景,ZIP 归档文件定义了包含文件末尾的相对偏移量的页脚。当与任何其他文件的末尾连接时,它们仍然有效。此功能是完全标准的,并且是自解压 ZIP 归档文件和 bdist_wininst 安装程序格式的工作方式。

最小工具:zipapp 模块

本 PEP 还建议包含一个用于处理这些归档文件的模块。该模块将包含用于处理 Python zip 应用程序归档文件的函数,以及一个命令行界面(通过 python -m zipapp)用于创建和操作它们。

鼓励将更完整的 Python Zip 应用程序管理工具作为 PyPI 上的第三方应用程序。目前,pyzzer [5] 和 pex [6] 是两个这样的工具。

模块接口

zipapp 模块将提供以下函数

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

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

  • 目录的名称,在这种情况下,将从该目录的内容创建一个新的应用程序归档文件。
  • 现有应用程序归档文件的名称,在这种情况下,该文件将被复制到目标。文件名应包含 .pyz.pyzw 扩展名(如果需要)。
  • 以字节模式打开以供读取的文件对象。文件的内容应为应用程序归档文件,并且假定文件对象位于归档文件的开头。

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

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

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

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

如果为 sourcetarget 指定了文件对象,则调用者有责任在调用 create_archive 后关闭它。

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

get_interpreter(archive)

返回 archive 的 shebang 行中指定的解释器。如果没有 shebang,则函数返回 Nonearchive 参数可以是文件名或以字节模式打开以供读取的文件类对象。

命令行用法

zipapp 模块可以使用 python -m 标志运行。命令行界面如下所示:

python -m zipapp directory [options]

    Create an archive from the given directory.  An archive will
    be created from the contents of that directory.  The archive
    will have the same name as the source directory with a .pyz
    extension.

    The following options can be specified:

    -o archive / --output archive

        The destination archive will have the specified name.  The
        given name will be used as written, so should include the
        ".pyz" or ".pyzw" extension.

    -p interpreter / --python interpreter

        The given interpreter will be written to the shebang line
        of the archive.  If this option is not given, the archive
        will have no shebang line.

    -m pkg.mod:fn / --main pkg.mod:fn

        The source directory must not have a __main__.py file. The
        archiver will write a __main__.py file into the target
        which calls fn from the module pkg.mod.

命令行界面的行为与 zipapp.create_archive() 相同。

此外,可以使用命令行界面处理现有归档文件:

python -m zipapp app.pyz --show

    Displays the shebang line of an archive.  Output is of the
    form

        Interpreter: /usr/bin/env
    or
        Interpreter: <none>

    and is intended for diagnostic use, not for scripts.

python -m zipapp app.pyz -o newapp.pyz [-p interpreter]

    Copy app.pyz to newapp.pyz, modifying the shebang line based
    on the -p option (as for creating an archive, no -p option
    means remove the shebang line).  Specifying a destination is
    mandatory.

    In-place modification of an archive is *not* supported, as the
    risk of damaging archives is too great for a simple tool.

如前所述,归档文件是标准的 zip 文件,因此可以使用任何标准的 ZIP 实用程序或 Python 的 zipfile 模块解压缩它们。因此,没有提供或需要列出归档文件内容或解压缩它们的接口。

常见问题

您确定标准的 ZIP 实用程序可以处理开头处的 #! 吗?
当然可以。zipfile 规范允许在 zipfile 前面添加任意数据。此功能通常由“自解压 zip”程序使用。如果您的归档程序无法处理此问题,则这是归档程序中的错误。
zipapp 是否只是 zipfile 模块的一个非常薄的包装器?
是的。如果您更喜欢使用其他工具构建自己的 Python zip 应用程序归档文件,它们也能正常工作。zipapp 模块只是一个便利工具,仅此而已。
为什么不只使用 .zip.py 扩展名?
用户期望使用归档工具打开 .zip 文件,并期望 .py 文件包含可读文本。这两种情况对于此用例来说都令人困惑。
这与现有的软件包格式相比如何?
sdist、bdist 和 wheel 格式旨在打包要安装到现有 Python 安装中的模块。它们不打算在未安装的情况下使用。可执行 zip 格式专门设计用于独立使用,无需安装。它们实际上是独立 Python 脚本的多文件版本。

被拒绝的提案

Shebang 行的便捷值

是否值得为任何常见的解释器值提供“便捷”形式?例如,-p 3 是否表示与 -p "/usr/bin/env python3" 相同。对于常见情况,这可以节省大量输入,并为不想或不需要了解“其他”平台上 shebang 处理复杂性的用户提供跨平台选项。

缺点是缩写的转换方式并不明显。例如,“3”应该表示“/usr/bin/env python3”、“/usr/bin/python3”、“python3”还是其他内容?此外,对于“/usr/bin/env python”(任何可用的 Python 版本)的关键情况,没有明显的简写形式,这很容易导致脚本使用过于严格的 shebang 行编写。

总的来说,这似乎弊大于利,因此已不再考虑。

注册 .pyz 作为媒体类型

有人建议 [3] 在 Unix 扩展名数据库中注册 .pyz 扩展名。虽然将其作为 Windows 安装程序注册扩展名的等效操作是有意义的,但 .py 扩展名未在媒体类型数据库中列出 [4]。在没有 .py 的情况下注册 .pyz 似乎不合理,因此此想法已从本 PEP 中省略。感兴趣的各方可以在将来安排同时注册 .py.pyz

默认解释器

此 PEP 的初始草案建议使用 /usr/bin/env python 作为默认解释器。Unix 用户对此行为存在问题,因为许多发行版中 python 命令的默认值是 Python 2,并且人们认为此 PEP 应该默认优先使用 Python 3。但是,使用 python3 命令可能会导致 Windows 用户出现意外行为,因为命令 python 的启动程序的默认行为通常由用户自定义,但 python3 的行为可能无法修改为匹配。

因此,采用了“在面对歧义时,拒绝猜测”的原则,除非明确请求,否则归档文件将没有 Shebang 行。在 Windows 上,归档文件仍将由启动程序(使用默认 Python)运行,而在 Unix 上,可以通过显式调用所需的 Python 解释器来运行归档文件。

用于管理 Shebang 行的命令行工具

可以设想,用户可能希望修改现有归档文件的 Shebang 行,甚至只是显示当前的 Shebang 行。使用现有工具执行此操作比较棘手(zip 程序通常完全忽略前置数据,文本编辑器可能难以编辑包含二进制数据的文件)。

zipapp 模块提供了处理 Shebang 行的功能,但没有为此功能提供命令行界面。这是因为,如果不希望生成的界面过于复杂且可能令人困惑,则不清楚如何提供一个命令行界面。更改 Shebang 行预计是一个不常见的需求。

参考实现

参考实现位于 http://bugs.python.org/issue23491

参考文献

此 PEP 的讨论发生在 python-dev 邮件列表中,主题从 https://mail.python.org/pipermail/python-dev/2015-February/138277.html 开始。


来源:https://github.com/python/peps/blob/main/peps/pep-0441.rst

上次修改时间:2023-09-09 17:39:29 GMT