目录

简单打包

Python 包现在可以使用现代构建系统,而不是传统但冗长的 setuptools 和 setup.py。您选择的构建系统并不重要;它们都使用在 PEP 621 中引入的 标准配置语言。PyPA 的 Flit 是一个不错的选择。 scikit-build-coremeson-python 正在开发中,以支持这种配置,使二进制扩展包也能从中受益。这些 PEP 621 工具目前包括 HatchPDMFlitSetuptoolsPoetry 最终将在 2.0 版本中获得支持。

传统文件

这些系统不使用也不需要 setup.pysetup.cfgMANIFEST.in。这些文件是用于 setuptools 的。当然,除非您正在使用 setuptools,setuptools 仍然使用 MANIFEST.in。您可以使用 pipx run hatch new --initini2toml 转换旧文件。

选择后端

后端以相同的方式处理元数据,因此选择取决于您如何指定哪些文件进入 SDist 以及其他功能,例如从 VCS 获取版本。如果您没有现有的偏好,hatchling 是一个绝佳的选择,它平衡了速度、可配置性和可扩展性。

pyproject.toml: build-system

PY001 包必须具有 pyproject.toml 文件 PP001,用于选择后端

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

pyproject.toml: project table

元数据以 基于标准 的格式指定

[project]
name = "package"
description = "A great package."
readme = "README.md"
authors = [
  { name = "My Name", email = "me@email.com" },
]
maintainers = [
  { name = "My Organization", email = "myemail@email.com" },
]
requires-python = ">=3.9"

dependencies = [
  "typing_extensions",
]

classifiers = [
  "Development Status :: 4 - Beta",
  "License :: OSI Approved :: BSD License",
  "Programming Language :: Python :: 3 :: Only",
  "Programming Language :: Python :: 3.9",
  "Programming Language :: Python :: 3.10",
  "Programming Language :: Python :: 3.11",
  "Programming Language :: Python :: 3.12",
  "Programming Language :: Python :: 3.13",
  "Topic :: Scientific/Engineering :: Physics",
]

[project.urls]
Homepage = "https://github.com/organization/package"
Documentation = "https://package.readthedocs.io/"
"Bug Tracker" = "https://github.com/organization/package/issues"
Discussions = "https://github.com/organization/package/discussions"
Changelog = "https://package.readthedocs.io/en/latest/changelog.html"

您可以在 packaging.python.orgFlitWhey 中详细了解每个字段以及所有允许的字段。请注意,“主页”很特殊,它替换了旧的 url 设置。

附加功能

建议使用附加功能来代替或补充创建需求文件。这些附加功能 a) 与安装需求和其他内置工具正确交互,b) 通过 PyPI 安装时直接可用,c) 允许在 requirements.txtinstall_requirespyproject.toml 以及大多数其他传递需求的地方。

这是一个简单附加功能的示例

[project.optional-dependencies]
test = [
  "pytest >=6.0",
]
mpl = [
  "matplotlib >=2.0",
]

可以使用包名称来使用自身依赖,例如 dev = ["package[test,examples]"],但这需要 Pip 21.2 或更高版本。我们建议至少提供 testdocs

命令行

如果您想发布一个用户可以从命令行运行的“应用程序”,您需要添加一个 script 入口点。格式为

[project.scripts]
cliapp = "package.__main__:main"

格式为命令行应用程序名称作为键,值为函数路径,后面跟着冒号,然后是将要调用的函数。如果您使用 __main__.py 作为文件,那么后面跟着模块的 python -m 也将起作用来调用应用程序(在这种情况下,__name__ 将为 "__main__")。

对于 requires-python,您应该指定所需的最低版本,并且不应该对其设置上限 PY004,因为此字段用于反向求解通过此检查的旧包版本,允许您安全地放弃 Python 版本。

包结构

所有包应该都有一个 src 文件夹,包代码驻留在其中,例如 src/<package>/。这可能看起来很麻烦;毕竟,如果您没有 src 文件夹,您可以在主目录中键入“python”并避免安装它!但是,这是一种不好的做法,会导致一些常见的错误,例如运行 pytest 并获取本地版本而不是已安装版本 - 如果您构建库的部分内容或访问包元数据,这显然会出错。

不幸的是,这并不属于 [project] 中的标准元数据,因此取决于您使用的后端。Hatchling、Flit、PDM 和 setuptools 使用自动检测。

如果您不匹配包名称和导入名称(除了非常特殊的情况外,您应该这样做),您可能需要在此处进行额外的配置。

您应该有一个 README PY002 和一个 LICENSE PY003 文件。您应该有一个 docs/ 文件夹 PY004。您应该有一个 /tests 文件夹 PY005(推荐)和/或一个 src/<package>/tests 文件夹。

版本控制

您可以手动指定版本(如示例所示),但后端通常提供一些自动功能来帮助您避免这种情况。如果您要求 Flit,它会从文件中提取此信息。Hatchling 和 PDM 可以被指示在文件中查找或使用 git。

您始终需要指定版本将使用以下方式动态提供

dynamic = ["version"]

然后您将配置您的后端以计算版本。

Hatchling 动态版本控制

您可以告诉 hatchling 从 VCS 获取版本。将 hatch-vcs 添加到您的 build-backend.requires 中,然后添加以下配置

[tool.hatch]
version.source = "vcs"
build.hooks.vcs.version-file = "src/<package>/version.py"

或者您可以告诉它在文件中查找它(有关任意正则表达式的详细信息,请参阅文档)

[tool.hatch]
version.path = "src/<package>/__init__.py"

(将 <package> 替换为包路径)。

您还应该添加这两个文件

.git_archival.txt:

node: $Format:%H$
node-date: $Format:%cI$
describe-name: $Format:%(describe:tags=true,match=*[0-9]*)$

以及 .gitattributes(或者如果您已经在使用此文件,请添加此行)

.git_archival.txt  export-subst

这将允许 git 存档(包括从 GitHub 生成的存档)也支持版本控制。

在 SDist 中包含/排除文件

这是特定于工具的。

  • Hatchling 信息在此处。Hatchling 默认情况下使用您的 VCS 忽略文件,因此请确保它是准确的(无论如何这都是一个好主意)。
  • Flit 信息在此处。Flit 在很多情况下需要手动包含/排除,例如使用脏工作目录。
  • PDM 信息在此处.
  • Setuptools 仍然使用 MANIFEST.in

如果您使用标准工具,即使 Flit 可以使用其自己的工具执行此操作,它也不会使用 VCS(如 git)来填充 SDist。因此,请确保列出明确的包含/排除规则,并测试内容

# Show SDist contents
tar -tvf dist/*.tar.gz
# Show wheel contents
unzip -l dist/*.whl

Flit需要在您的 [project] 部分中设置 license.file 以确保它找到许可证文件。