打包和分发项目¶
- 页面状态:
过时
- 上次审核时间:
2023-12-14
本节介绍使用 setuptools 配置、打包和分发 Python 项目的一些额外细节,这些细节在 打包 Python 项目 的入门教程中没有涉及。它仍然假定您已经熟悉 安装包 页面的内容。
本节并不旨在涵盖 Python 项目开发的整体最佳实践。例如,它不提供版本控制、文档或测试的指导或工具建议。
有关更多参考资料,请参阅 Setuptools 文档中的 构建和分发包,但请注意,其中一些建议内容可能已过时。如果存在冲突,请优先参考 Python 打包用户指南中的建议。
打包和分发的要求¶
配置您的项目¶
初始文件¶
setup.py¶
最重要的文件是 setup.py,它位于您的项目目录的根部。例如,请参阅 PyPA 示例项目中的 setup.py。
setup.py 主要有两个功能
它是配置项目各个方面的文件。
setup.py的主要特点是它包含一个全局的setup()函数。这个函数的关键字参数是定义项目特定细节的方式。最相关的参数在下面的章节中解释。它是运行与打包任务相关的各种命令的命令行接口。要获取可用命令列表,请运行
python3 setup.py --help-commands。
setup.cfg¶
setup.cfg 是一个 ini 文件,其中包含 setup.py 命令的默认选项。例如,请参阅 PyPA 示例项目中的 setup.cfg。
README.rst / README.md¶
所有项目都应该包含一个 README 文件,涵盖项目目标。最常见的格式是带“rst”扩展名的 reStructuredText,但这并非强制性要求;还支持 Markdown 的多种变体(请查看 setup() 的 long_description_content_type 参数)。
注意
使用 Setuptools 0.6.27+ 的项目默认在源代码分发中包含标准 README 文件(README.rst、README.txt 或 README)。内置的 distutils 库从 Python 3.7 开始采用此行为。此外,Setuptools 36.4.0+ 如果找到 README.md 也会包含它。如果您正在使用 setuptools,则无需在 MANIFEST.in 中列出您的 README 文件。否则,请明确列出。
MANIFEST.in¶
当您需要打包未自动包含在源代码分发中的额外文件时,需要一个 MANIFEST.in。有关编写 MANIFEST.in 文件的详细信息,包括默认包含的文件列表,请参阅“使用 MANIFEST.in”。
然而,您可能不需要使用 MANIFEST.in。例如,PyPA 示例项目已删除了其清单文件,因为所有必需的文件都已由 Setuptools 43.0.0 及更高版本包含。
注意
MANIFEST.in 不影响二进制分发,例如 wheel。
LICENSE.txt¶
每个包都应包含一个许可证文件,详细说明分发条款。在许多司法管辖区,未经明确许可的包除版权所有者外,任何人均不得合法使用或分发。如果您不确定选择哪个许可证,可以使用 GitHub 的 Choose a License 等资源或咨询律师。
例如,请参阅 PyPA 示例项目中的 LICENSE.txt。
<您的包>¶
虽然并非强制要求,但最常见的做法是将您的 Python 模块和包包含在一个顶级包下,该包的名称与您的项目名称相同或非常接近。
setup() 参数¶
如上所述,setup.py 的主要特点是它包含一个全局的 setup() 函数。此函数的关键字参数是定义项目特定细节的方式。
有些内容在此处暂时解释,直到其信息被移至其他地方。完整列表可以在 setuptools 文档中找到。
给出的大多数代码片段都取自 PyPA 示例项目中包含的 setup.py。
有关如何使用版本向用户传达兼容性信息的更多信息,请参阅版本控制。
packages¶
packages=find_packages(include=['sample', 'sample.*']),
将 packages 设置为项目中所有包的列表,包括它们的子包、子子包等。尽管包可以手动列出,但 setuptools.find_packages() 会自动找到它们。使用 include 关键字参数仅查找给定的包。使用 exclude 关键字参数省略不打算发布和安装的包。
py_modules¶
py_modules=["six"],
如果您的项目包含任何不属于包的单文件 Python 模块,请将 py_modules 设置为模块名称列表(不带 .py 扩展名),以便 Setuptools 能够识别它们。
install_requires¶
install_requires=['peppercorn'],
“install_requires” 应用于指定项目运行所需的最低依赖项。当项目由 pip 安装时,这是用于安装其依赖项的规范。
有关使用“install_requires”的更多信息,请参阅install_requires 与 requirements 文件。
package_data¶
package_data={
'sample': ['package_data.dat'],
},
通常,需要将额外的文件安装到包中。这些文件通常是与包实现密切相关的数据,或者是包含使用该包的程序员可能感兴趣的文档的文本文件。这些文件称为“包数据”。
该值必须是从包名到应该复制到包中的相对路径名列表的映射。路径被解释为相对于包含该包的目录。
有关更多信息,请参阅 setuptools 文档中的包含数据文件。
data_files¶
data_files=[('my_data', ['data/data_file'])],
尽管配置 package_data 足以满足大多数需求,但在某些情况下,您可能需要将数据文件放置在 包外部。 data_files 指令允许您这样做。它主要在您需要安装其他程序使用的文件时有用,而这些程序可能不知道 Python 包。
序列中的每个 (directory, files) 对都指定了安装目录和要安装到那里的文件。directory 必须是相对路径(尽管这将来可能会改变,请参阅 wheel Issue #92),并且它相对于安装前缀解释(对于默认安装,是 Python 的 sys.prefix;对于用户安装,是 site.USER_BASE)。files 中的每个文件名都相对于项目源代码分发顶部的 setup.py 脚本解释。
有关更多信息,请参阅 distutils 部分的 安装附加文件。
注意
以 egg 形式安装包时,不支持 data_files。因此,如果您的项目使用 Setuptools,则必须使用 pip 进行安装。或者,如果您必须使用 python setup.py,则需要传递 --old-and-unmanageable 选项。
scripts¶
尽管 setup() 支持 scripts 关键字,用于指向预先制作的脚本进行安装,但实现跨平台兼容性的推荐方法是使用 创建可执行脚本 入口点(参见下文)。
选择版本控制方案¶
有关常见版本方案以及如何选择它们的信息,请参阅版本控制。
在“开发模式”下工作¶
您可以在开发项目时以“可编辑”或“开发”模式安装项目。以可编辑模式安装后,项目可以在不重新安装的情况下原地编辑:对以可编辑模式安装的项目中的 Python 源文件所做的更改将在下次启动解释器进程时反映出来。
要在“可编辑”/“开发”模式下安装 Python 包,请将目录更改到项目目录的根目录并运行
python3 -m pip install -e .
pip 命令行标志 -e 是 --editable 的简写,. 指的是当前工作目录,所以它们合起来表示以可编辑模式安装当前目录(即您的项目)。这还将安装使用 install_requires 声明的任何依赖项和使用 console_scripts 声明的任何脚本。依赖项将以常规的、不可编辑的模式安装。
您可能还希望以可编辑模式安装一些依赖项。例如,假设您的项目需要“foo”和“bar”,但您希望“bar”以可编辑模式从 VCS 安装,那么您可以构建一个如下所示的 requirements 文件
-e .
-e bar @ git+https://somerepo/bar.git
第一行表示安装您的项目和任何依赖项。第二行覆盖了“bar”依赖项,使其从 VCS 而不是 PyPI 获得。
但是,如果您希望以可编辑模式从本地目录安装“bar”,则 requirements 文件应如下所示,本地路径位于文件顶部
-e /path/to/project/bar
-e .
否则,由于 requirements 文件的安装顺序,依赖项将从 PyPI 获取。有关 requirements 文件的更多信息,请参阅 pip 文档中的 Requirements File 部分。有关 VCS 安装的更多信息,请参阅 pip 文档的 VCS Support 部分。
最后,如果您根本不想安装任何依赖项,可以运行
python3 -m pip install -e . --no-deps
有关更多信息,请参阅 Setuptools 文档的 开发模式 部分。
打包您的项目¶
为了让您的项目可以从 包索引(例如 PyPI)安装,您需要为您的项目创建一个分发包(也称为“包”)。
在为您的项目构建 wheels 和 sdists 之前,您需要安装 build 包
python3 -m pip install build
py -m pip install build
源代码分发¶
最低限度,您应该创建一个源代码分发包
python3 -m build --sdist
py -m build --sdist
“源代码分发”是未构建的(即,它不是已构建的分发),并且在由 pip 安装时需要构建步骤。即使分发是纯 Python(即不包含任何扩展),它仍然涉及一个构建步骤,以从 setup.py 和/或 setup.cfg 中构建安装元数据。
Wheels¶
您还应该为您的项目创建一个 wheel。wheel 是一种已构建的包,无需经过“构建”过程即可安装。对于最终用户来说,安装 wheels 比从源代码分发安装要快得多。
如果您的项目是纯 Python,那么您将创建一个“纯 Python Wheel”(参见下文)。
如果您的项目包含编译扩展,那么您将创建所谓的*平台 Wheel*(参见下文)。
注意
如果您的项目还支持 Python 2 且不包含 C 扩展,则应通过在 setup.cfg 文件中添加以下内容来创建 通用 Wheel
[bdist_wheel]
universal=1
仅当您的项目没有任何 C 扩展且支持 Python 2 和 3 时才使用此设置。
纯 Python Wheels¶
纯 Python Wheels 不包含编译扩展,因此只需要一个 Python wheel。
要构建 wheel
python3 -m build --wheel
py -m build --wheel
wheel 包将检测到代码是纯 Python,并构建一个适用于任何 Python 3 安装的 wheel。有关 wheel 文件命名的详细信息,请参见PEP 425。
如果您运行 build 而不带 --wheel 或 --sdist,它将为您同时构建这两个文件;这在您不需要多个 wheel 时很有用。
平台 Wheels¶
平台 Wheels 是特定于某个平台(如 Linux、macOS 或 Windows)的 wheel,通常是因为它们包含编译扩展。
要构建 wheel
python3 -m build --wheel
py -m build --wheel
wheel 包将检测代码不是纯 Python,并构建一个仅适用于构建它的平台的 wheel。有关 wheel 文件命名的详细信息,请参见PEP 425。
将您的项目上传到 PyPI¶
当您运行创建分发的命令时,您的项目根目录下会创建一个新目录 dist/。这就是您要上传的分发文件所在的位置。
注意
这些文件仅在您运行创建分发的命令时创建。这意味着,只要您更改项目源代码或 setup.py 文件中的配置,您就需要重新构建这些文件,然后才能将更改分发到 PyPI。
注意
在发布到主 PyPI 仓库之前,您可能更喜欢使用 PyPI 测试站点进行训练,该站点会定期清理。请参阅使用 TestPyPI,了解如何设置配置以使用它。
警告
在其他资源中,您可能会遇到使用 python setup.py register 和 python setup.py upload 的引用。强烈不鼓励这些注册和上传包的方法,因为在某些 Python 版本上,它可能使用明文 HTTP 或未经验证的 HTTPS 连接,从而允许您的用户名和密码在传输过程中被拦截。
提示
PyPI 上使用的 reStructuredText 解析器不是 Sphinx!此外,为了确保所有用户的安全,某些类型的 URL 和指令是被禁止或删除的(例如,.. raw:: 指令)。在尝试上传您的分发包之前,您应该检查 setup.py 中提供的简短/详细描述是否有效。您可以通过在您的包文件上运行 twine check 来实现这一点
twine check dist/*
创建账户¶
首先,您需要一个 PyPI 用户帐户。您可以通过 PyPI 网站上的表单创建帐户。
现在您将创建一个 PyPI API 令牌,以便您能够安全地上传您的项目。
前往 https://pypi.ac.cn/manage/account/#api-tokens 并创建一个新的 API 令牌;不要将其范围限制在特定项目,因为您正在创建一个新项目。
在复制并保存令牌之前不要关闭页面——您将不会再看到该令牌。
注意
为了避免每次上传时都必须复制和粘贴令牌,您可以创建一个 $HOME/.pypirc 文件
[pypi]
username = __token__
password = <the token value, including the `pypi-` prefix>
请注意,这会将您的令牌以明文形式存储。
有关更多详细信息,请参阅 .pypirc 的规范。
上传您的分发包¶
拥有账户后,您可以使用 twine 将您的分发包上传到 PyPI。
上传发布的过程是相同的,无论项目是否已存在于 PyPI 上 - 如果它尚不存在,它将在第一次发布上传时自动创建。
对于第二次及后续发布,PyPI 只要求新发布的版本号与任何以前的发布版本号不同。
twine upload dist/*
您可以通过导航到 URL https://pypi.ac.cn/project/<sampleproject> 来查看您的包是否成功上传,其中 sampleproject 是您上传的项目的名称。您的项目可能需要一两分钟才能显示在网站上。