打包 Python 项目#
本教程将指导你如何打包一个简单的 Python 项目。它将向你展示如何添加必要的文件和结构来创建软件包,如何构建软件包,以及如何将其上传到 Python 软件包索引 (PyPI)。
提示
如果你在运行本教程中的命令时遇到问题,请复制命令及其输出,然后在 GitHub 上的 packaging-problems 存储库中打开一个问题。我们会尽力帮助你!
某些命令需要较新版本的 pip,因此首先确保已安装最新版本
python3 -m pip install --upgrade pip
py -m pip install --upgrade pip
一个简单的项目#
本教程使用一个名为 example_package_YOUR_USERNAME_HERE
的简单项目。如果你的用户名是 me
,那么软件包将是 example_package_me
;这可确保你拥有一个唯一的软件包名称,不会与按照本教程操作的其他人员上传的软件包冲突。我们建议按照本教程使用此项目,然后再打包你自己的项目。
在本地创建以下文件结构
packaging_tutorial/
└── src/
└── example_package_YOUR_USERNAME_HERE/
├── __init__.py
└── example.py
包含 Python 文件的目录应与项目名称匹配。这简化了配置,并且对于安装软件包的用户来说更明显。
建议创建文件 __init__.py
,因为 __init__.py
文件的存在允许用户将目录作为常规软件包导入,即使(如本教程中所示)__init__.py
为空。 [1]
example.py
是软件包中模块的一个示例,该模块可以包含软件包的逻辑(函数、类、常量等)。打开该文件并输入以下内容
def add_one(number):
return number + 1
如果你不熟悉 Python 的 模块 和 导入软件包,请花几分钟阅读 Python 文档中的软件包和模块。
创建此结构后,您需要在这个 packaging_tutorial
目录中运行本教程中的所有命令。
创建包文件#
现在,您将添加用于准备项目分发的文件。完成后,项目结构将如下所示
packaging_tutorial/
├── LICENSE
├── pyproject.toml
├── README.md
├── src/
│ └── example_package_YOUR_USERNAME_HERE/
│ ├── __init__.py
│ └── example.py
└── tests/
创建测试目录#
tests/
是测试文件的占位符。现在将其留空。
选择构建后端#
诸如 pip 和 build 等工具实际上不会将您的源代码转换为 发行包(例如轮子);这项工作由 构建后端 执行。构建后端决定您的项目将如何指定其配置,包括元数据(有关项目的信息,例如在 PyPI 上显示的名称和标签)和输入文件。构建后端具有不同的功能级别,例如它们是否支持构建 扩展模块,您应该选择一个适合您的需求和偏好的构建后端。
您可以从多个后端中进行选择;本教程默认使用 Hatchling,但它与 Setuptools、Flit、PDM 和其他支持 元数据 的 [project]
表的后端完全相同。
注意
某些构建后端是更大工具的一部分,这些工具提供带有附加功能(如项目初始化和版本管理以及构建、上传和安装包)的命令行界面。本教程使用独立工作的单用途工具。
pyproject.toml
告诉 构建前端 工具(如 pip 和 build)为您的项目使用哪个后端。以下是常见构建后端的示例,但请查看您自己的后端文档以了解更多详细信息。
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[build-system]
requires = ["flit_core>=3.4"]
build-backend = "flit_core.buildapi"
[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"
requires
键是构建您的包所需的包的列表。在构建您的包时,前端 应自动安装它们。前端通常在隔离的环境中运行构建,因此在此处省略依赖项可能会导致构建时错误。这应始终包括您的后端包,并且可能还有其他构建时依赖项。
build-backend
键是前端将用于执行构建的 Python 对象的名称。
这两个值都将由您的构建后端的文档提供,或由其命令行界面生成。您无需自定义这些设置。
构建工具的其他配置将位于 pyproject.toml
的 tool
部分或构建工具定义的特殊文件中。例如,在使用 setuptools
作为您的构建后端时,可以将其他配置添加到 setup.py
或 setup.cfg
文件中,并在构建中指定 setuptools.build_meta
,以便工具可以自动找到并使用它们。
配置元数据#
打开 pyproject.toml
并输入以下内容。将 name
更改为包含你的用户名;这将确保你拥有一个唯一的包名称,不会与按照本教程上传包的其他人上传的包冲突。
[project]
name = "example_package_YOUR_USERNAME_HERE"
version = "0.0.1"
authors = [
{ name="Example Author", email="author@example.com" },
]
description = "A small example package"
readme = "README.md"
requires-python = ">=3.8"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
[project.urls]
Homepage = "https://github.com/pypa/sampleproject"
Issues = "https://github.com/pypa/sampleproject/issues"
name
是包的发行名称。只要它只包含字母、数字、.
、_
和-
,这可以是任何名称。它还不能在 PyPI 上已被采用。务必使用你的用户名更新此项,因为这将确保你不会尝试上传与已经存在的包同名的包。version
是包版本。(一些构建后端允许以其他方式指定它,例如从文件或 Git 标记中指定。)authors
用于识别包的作者;你为每个作者指定一个名称和一个电子邮件。你还可以以相同的格式列出maintainers
。description
是包的简短、一句话的摘要。readme
是包含包的详细描述的文件的路径。这显示在 PyPI 上的包详细信息页面上。在这种情况下,描述从README.md
(这是一个常见模式)中加载。还有一种更高级的表格形式,在 pyproject.toml 指南 中进行了描述。requires-python
给出了你的项目支持的 Python 版本。像 pip 这样的安装程序将回溯包的旧版本,直到找到一个具有匹配的 Python 版本的包。classifiers
为索引和 pip 提供有关你的包的一些附加元数据。在这种情况下,该包仅与 Python 3 兼容,在 MIT 许可证下获得许可,并且与操作系统无关。你应该始终至少包括你的包适用于哪些 Python 版本、你的包在哪个许可证下可用以及你的包将在哪些操作系统上运行。有关分类器的完整列表,请参阅 https://pypi.ac.cn/classifiers/。urls
允许你列出任意数量的额外链接以在 PyPI 上显示。通常这可能是指向源、文档、问题跟踪器等。
请参阅 pyproject.toml 指南,了解可以在 [project]
表中定义的这些字段和其他字段的详细信息。其他常见字段是 keywords
,用于提高可发现性,以及安装你的包所需的 dependencies
。
创建 README.md#
打开 README.md
并输入以下内容。如果你愿意,可以自定义此内容。
# Example Package
This is a simple example package. You can use
[GitHub-flavored Markdown](https://guides.github.com/features/mastering-markdown/)
to write your content.
创建 LICENSE#
上传到 Python 包索引的每个包都必须包含许可证,这一点非常重要。这会告知安装你的包的用户他们可以使用你的包的条款。有关选择许可证的帮助,请参阅 https://choosealicense.com/。一旦你选择了许可证,请打开 LICENSE
并输入许可证文本。例如,如果你选择了 MIT 许可证
Copyright (c) 2018 The Python Packaging Authority
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
大多数构建后端会自动在包中包含许可证文件。有关更多详细信息,请参阅后端的文档。
包括其他文件#
上面列出的文件将自动包含在你的 源发行版 中。如果你想包含其他文件,请参阅构建后端的文档。
生成发行存档#
下一步是为该软件包生成分发软件包。这些是上传到 Python 软件包索引的存档,并且可以通过pip进行安装。
确保已安装最新版本的 PyPA 的build
python3 -m pip install --upgrade build
py -m pip install --upgrade build
提示
如果你在安装这些软件包时遇到问题,请参阅安装软件包教程。
现在,从位于pyproject.toml
的同一目录中运行此命令
python3 -m build
py -m build
此命令应输出大量文本,并且完成后应在dist
目录中生成两个文件
dist/
├── example_package_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl
└── example_package_YOUR_USERNAME_HERE-0.0.1.tar.gz
tar.gz
文件是源代码分发,而.whl
文件是已构建分发。较新的pip版本优先安装已构建分发,但如果需要,将回退到源代码分发。你应该始终上传源代码分发,并为你的项目兼容的平台提供已构建分发。在这种情况下,我们的示例软件包与任何平台上的 Python 兼容,因此只需要一个已构建分发。
上传分发存档#
最后,是时候将你的软件包上传到 Python 软件包索引了!
你需要做的第一件事是在 TestPyPI 上注册一个帐户,它是软件包索引的一个单独实例,用于测试和实验。对于像本教程这样的事情来说,这是非常棒的,因为我们不一定想上传到真正的索引。要注册一个帐户,请转到https://test.pypi.org/account/register/并完成该页面上的步骤。你还需要验证你的电子邮件地址,然后才能上传任何软件包。有关更多详细信息,请参阅使用 TestPyPI。
要安全地上传你的项目,你需要一个 PyPI API 令牌。在https://test.pypi.org/manage/account/#api-tokens创建一个,将“范围”设置为“整个帐户”。在复制并保存令牌之前不要关闭页面——你将不会再次看到该令牌。
现在你已经注册,你可以使用twine上传分发软件包。你需要安装 Twine
python3 -m pip install --upgrade twine
py -m pip install --upgrade twine
安装完成后,运行 Twine 以上传dist
下的所有存档
python3 -m twine upload --repository testpypi dist/*
py -m twine upload --repository testpypi dist/*
系统将提示你输入用户名和密码。对于用户名,使用__token__
。对于密码,使用令牌值,包括pypi-
前缀。
命令完成后,你应该看到类似于此的输出
Uploading distributions to https://test.pypi.org/legacy/
Enter your username: __token__
Uploading example_package_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.2/8.2 kB • 00:01 • ?
Uploading example_package_YOUR_USERNAME_HERE-0.0.1.tar.gz
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.8/6.8 kB • 00:00 • ?
上传后,你的软件包应该可以在 TestPyPI 上查看;例如:https://test.pypi.org/project/example_package_YOUR_USERNAME_HERE
。
安装你新上传的软件包#
你可以使用pip安装你的软件包并验证其是否有效。创建一个虚拟环境,并从 TestPyPI 安装你的软件包
python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps example-package-YOUR-USERNAME-HERE
py -m pip install --index-url https://test.pypi.org/simple/ --no-deps example-package-YOUR-USERNAME-HERE
确保在包名中指定你的用户名!
pip 应该从 TestPyPI 安装包,输出应类似于以下内容
Collecting example-package-YOUR-USERNAME-HERE
Downloading https://test-files.pythonhosted.org/packages/.../example_package_YOUR_USERNAME_HERE_0.0.1-py3-none-any.whl
Installing collected packages: example_package_YOUR_USERNAME_HERE
Successfully installed example_package_YOUR_USERNAME_HERE-0.0.1
注意
此示例使用 --index-url
标志来指定 TestPyPI 而不是实时 PyPI。此外,它指定 --no-deps
。由于 TestPyPI 没有与实时 PyPI 相同的包,因此尝试安装依赖项可能会失败或安装一些意外的内容。虽然我们的示例包没有任何依赖项,但在使用 TestPyPI 时避免安装依赖项是一个好习惯。
你可以通过导入包来测试它是否已正确安装。确保你仍处于虚拟环境中,然后运行 Python
python3
py
并导入包
>>> from example_package_YOUR_USERNAME_HERE import example
>>> example.add_one(2)
3
后续步骤#
恭喜,你已经打包并分发了一个 Python 项目! ✨ 🍰 ✨
请记住,本教程向你展示了如何将你的包上传到 Test PyPI,它不是永久存储。Test 系统偶尔会删除包和帐户。最好将 TestPyPI 用于此教程中的测试和实验。
当你准备好将一个真正的包上传到 Python 包索引时,你可以做与本教程中所做的大致相同的事情,但有以下重要区别
为你的包选择一个令人难忘且唯一的名称。你不必像在本教程中那样附加你的用户名,但你不能使用现有的名称。
在 https://pypi.ac.cn 上注册一个帐户 - 请注意,这是两个独立的服务器,测试服务器的登录详细信息不会与主服务器共享。
使用
twine upload dist/*
上传你的包并输入你在真正的 PyPI 上注册的帐户的凭据。现在你正在生产环境中上传包,你不需要指定--repository
;包将默认上传到 https://pypi.ac.cn/。使用
python3 -m pip install [your-package]
从真正的 PyPI 安装你的包。
此时,如果你想阅读更多有关打包 Python 库的信息,你可以做以下一些事情
阅读你选择的构建后端的详细配置:Hatchling、setuptools、Flit、PDM。
考虑使用打包工具,这些工具为项目管理和打包提供了一个单一的命令行界面,例如 hatch、flit、pdm 和 poetry。
备注