编写您的 pyproject.toml
#
pyproject.toml
是打包工具以及其他工具(如 linter、类型检查器等)使用的配置文件。此文件中可能有三个可能的 TOML 表格。
[build-system]
表格强烈推荐使用。它允许您声明您使用的 构建后端 以及构建项目所需的哪些其他依赖项。[project]
表格是大多数构建后端用于指定项目的元数据的格式,例如依赖项、您的名称等。[tool]
表格具有特定于工具的子表格,例如[tool.hatch]
、[tool.black]
、[tool.mypy]
。我们在此仅涉及此表格,因为其内容由每个工具定义。查阅特定工具的文档以了解其可以包含的内容。
注意
[build-system]
和 [project]
表格之间存在显著差异。无论您使用哪个构建后端,前者都应始终存在(因为它定义您使用的工具)。后者被大多数构建后端理解,但有些构建后端使用不同的格式。
在撰写本文时(2023 年 11 月),Poetry 是一个不使用 [project]
表格的著名构建后端(它使用 [tool.poetry]
表格)。
此外,setuptools 构建后端同时支持 [project]
表格和 setup.cfg
或 setup.py
中的旧格式。对于新项目,建议使用 [project]
表格,并且仅在需要一些编程配置(例如构建 C 扩展)时保留 setup.py
,但 setup.cfg
和 setup.py
格式仍然有效。请参阅 setup.py 是否已弃用?。
声明构建后端#
[build-system]
表格包含一个 build-backend
键,它指定要使用的构建后端。它还包含一个 requires
键,它是构建项目所需依赖项的列表——这通常只是构建后端包,但它也可能包含其他依赖项。您还可以限制版本,例如 requires = ["setuptools >= 61.0"]
。
通常,您只需复制构建后端文档建议的内容(在 选择构建后端 之后)。以下是一些常见构建后端的取值
[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"
静态元数据与动态元数据#
本指南的其余部分专门介绍 [project]
表格。
大多数情况下,您将直接编写 [project]
字段的值。例如:requires-python = ">= 3.8"
,或 version = "1.0"
。
但是,在某些情况下,让构建后端为您计算元数据很有用。例如:许多构建后端可以从代码中的 __version__
属性、Git 标记或类似内容中读取版本。在这种情况下,您应该使用以下方法将字段标记为动态,例如
[project]
dynamic = ["version"]
当一个字段是动态的,填充它的责任就落在了构建后端上。查阅构建后端的文档以了解它是如何完成的。
基本信息#
name
#
将您的项目名称放在 PyPI 上。此字段是必需的,并且是唯一不能标记为动态的字段。
[project]
name = "spam-eggs"
项目名称必须由 ASCII 字母、数字、下划线“_
”、连字符“-
”和句点“.
”组成。它不能以下划线、连字符或句点开头或结尾。
项目名称的比较不区分大小写,并将任意长的下划线、连字符和/或句点视为相等。例如,如果您注册了一个名为 cool-stuff
的项目,用户将能够使用以下任何拼写下载它或声明对它的依赖:Cool-Stuff
、cool.stuff
、COOL_STUFF
、CoOl__-.-__sTuFF
。
version
#
填写您项目的版本。
[project]
version = "2020.0.0"
一些更复杂的版本说明符,如 2020.0.0a1
(用于 alpha 版本)是可能的;有关完整详细信息,请参见 规范。
此字段是必需的,尽管它经常使用以下方式标记为动态
[project]
dynamic = ["version"]
这允许使用案例,例如从 __version__
属性或 Git 标记中填充版本。有关更多详细信息,请参阅 单一来源的包版本。
依赖项和要求#
dependencies
/optional-dependencies
#
如果你的项目有依赖项,请像这样列出它们
[project]
dependencies = [
"httpx",
"gidgethub[httpx]>4.0.0",
"django>2.1; os_name != 'nt'",
"django>2.0; os_name == 'nt'",
]
请参阅 依赖项说明符,了解可用于限制版本的完整语法。
如果你只想为特定功能添加依赖项,则可以将一些依赖项设为可选。在这种情况下,请将它们放入 optional-dependencies
。
[project.optional-dependencies]
gui = ["PyQt5"]
cli = [
"rich",
"click",
]
每个键都定义了一个“打包额外内容”。在上面的示例中,可以使用 pip install your-project-name[gui]
来安装带有 GUI 支持的项目,并添加 PyQt5 依赖项。
requires-python
#
这让你可以声明你支持的最低 Python 版本 [1]。
[project]
requires-python = ">= 3.8"
创建可执行脚本#
要将命令作为包的一部分进行安装,请在 [project.scripts]
表中声明它。
[project.scripts]
spam-cli = "spam:main_cli"
在此示例中,在安装项目后,将提供 spam-cli
命令。执行此命令将等同于 from spam import main_cli; main_cli()
。
在 Windows 上,以这种方式打包的脚本需要一个终端,因此如果你从图形应用程序中启动它们,它们会弹出一个终端。为了防止这种情况发生,请使用 [project.gui-scripts]
表,而不是 [project.scripts]
。
[project.gui-scripts]
spam-gui = "spam:main_gui"
在这种情况下,从命令行启动脚本将立即返回控制权,让脚本在后台运行。
[project.scripts]
和 [project.gui-scripts]
之间的区别仅与 Windows 相关。
关于你的项目#
description
#
这应该是你项目的单行描述,以在 PyPI 上的项目页面上显示为“标题”(示例),以及其他地方,例如搜索结果列表(示例)。
[project]
description = "Lovely Spam! Wonderful Spam!"
readme
#
这是你项目的较长描述,以在 PyPI 上的项目页面上显示。通常,你的项目将有一个 README.md
或 README.rst
文件,你只需在此处放置其文件名即可。
[project]
readme = "README.md"
README 的格式会根据扩展名自动检测
README.md
→ GitHub 样式 Markdown,README.rst
→ reStructuredText(没有 Sphinx 扩展)。
你还可以像这样显式指定格式
[project]
readme = {file = "README.txt", content-type = "text/markdown"}
# or
readme = {file = "README.txt", content-type = "text/x-rst"}
license
#
这可以采用两种形式。你可以将许可证放在一个文件中,通常是 LICENSE
或 LICENSE.txt
,然后在此处链接该文件
[project]
license = {file = "LICENSE"}
或者你可以写下许可证的名称
[project]
license = {text = "MIT License"}
如果你正在使用一个标准的、众所周知的许可证,则不必使用此字段。相反,你应该使用以 License ::
开头的 分类器 之一。(一般来说,最好使用一个标准的、众所周知的许可证,既可以避免混淆,又因为有些组织会避免使用许可证未经批准的软件。)
keywords
#
这将帮助 PyPI 的搜索框在人们搜索这些关键字时建议你的项目。
[project]
keywords = ["egg", "bacon", "sausage", "tomatoes", "Lobster Thermidor"]
classifiers
#
适用于你的项目的 PyPI 分类器列表。查看 可能性完整列表。
classifiers = [
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
"Development Status :: 4 - Beta",
# Indicate who your project is intended for
"Intended Audience :: Developers",
"Topic :: Software Development :: Build Tools",
# Pick your license as you wish (see also "license" above)
"License :: OSI Approved :: MIT License",
# Specify the Python versions you support here.
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
]
尽管分类器列表通常用于声明项目支持哪些 Python 版本,但此信息仅用于在 PyPI 上搜索和浏览项目,而不是用于安装项目。要实际限制项目可以安装的 Python 版本,请使用 requires-python 参数。
要防止将包上传到 PyPI,请使用特殊 Private :: Do Not Upload
分类器。PyPI 始终会拒绝以 Private ::
开头的分类器开始的包。
urls
#
与你的项目关联的 URL 列表,显示在 PyPI 项目页面的左侧边栏中。
[project.urls]
Homepage = "https://example.com"
Documentation = "https://readthedocs.org"
Repository = "https://github.com/me/spam.git"
Issues = "https://github.com/me/spam/issues"
Changelog = "https://github.com/me/spam/blob/master/CHANGELOG.md"
请注意,如果键包含空格,则需要引用,例如,Website = "https://example.com"
但 "Official Website" = "https://example.com"
。
高级插件#
一些包可以通过插件进行扩展。示例包括 Pytest 和 Pygments。要创建这样的插件,你需要在 [project.entry-points]
的子表中声明它,如下所示
[project.entry-points."spam.magical"]
tomatoes = "spam:main_tomatoes"
有关更多信息,请参阅 插件指南。
一个完整的示例#
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "spam-eggs"
version = "2020.0.0"
dependencies = [
"httpx",
"gidgethub[httpx]>4.0.0",
"django>2.1; os_name != 'nt'",
"django>2.0; os_name == 'nt'",
]
requires-python = ">=3.8"
authors = [
{name = "Pradyun Gedam", email = "pradyun@example.com"},
{name = "Tzu-Ping Chung", email = "tzu-ping@example.com"},
{name = "Another person"},
{email = "different.person@example.com"},
]
maintainers = [
{name = "Brett Cannon", email = "brett@example.com"}
]
description = "Lovely Spam! Wonderful Spam!"
readme = "README.rst"
license = {file = "LICENSE.txt"}
keywords = ["egg", "bacon", "sausage", "tomatoes", "Lobster Thermidor"]
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python"
]
[project.optional-dependencies]
gui = ["PyQt5"]
cli = [
"rich",
"click",
]
[project.urls]
Homepage = "https://example.com"
Documentation = "https://readthedocs.org"
Repository = "https://github.com/me/spam.git"
"Bug Tracker" = "https://github.com/me/spam/issues"
Changelog = "https://github.com/me/spam/blob/master/CHANGELOG.md"
[project.scripts]
spam-cli = "spam:main_cli"
[project.gui-scripts]
spam-gui = "spam:main_gui"
[project.entry-points."spam.magical"]
tomatoes = "spam:main_tomatoes"