Python 打包已经发展了很多。最新的(“beta”)使用一个文件 pyproject.toml
来控制包。
一个最小的 pyproject.toml
可能看起来像这样
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "cool_project"
version = "1.0.0"
project 部分
project 部分是关于 Python 项目自身的数据,包括诸如 name 和 version 等字段,这些字段是必需的。
其他字段也经常使用,包括
- description:一行描述。
- readme:README 文件的位置。
- authors:作者姓名和电子邮件。
- dependencies:此项目使用的其他包。
build-system 部分
虽然不一定必须是第一个,但 build-system 通常位于顶部。这是因为它最重要。
build-backend 键指向一个模块,该模块知道如何从项目构建源发行版和 wheel 文件。requires 字段允许指定构建时依赖项。
许多项目都是用 setuptools 构建的。还有一些新的替代方案,例如 flit 和 hatch。
插件
build-system 中 requires 部分的一个好处是它可以用来安装插件。特别是 setuptools 包,可以使用插件来修改其行为。
插件可以做的一件事是自动设置版本。这是一个普遍的需求,因为版本管理通常很麻烦。
过渡
在继续之前,值得反思一下“模仿”的本质。X 的模仿 是 X 的一个实例,它夸大了某些方面,通常达到了幽默的程度。
例如,“间谍电影的模仿”是一部间谍电影,即使它戏仿了这种类型。
setuptools 插件的模仿
考虑到这一点,setuptools 插件的模仿会是什么样子?根据上面的规则,它必须是一个插件。
这个插件名为 onedotoh,它将版本设置为... 1.0.0。为了成为一个插件,它首先必须是一个包。
一个包应该有一个 pyproject.toml
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "onedotoh"
version = "1.0.0"
[project.entry-points."setuptools.finalize_distribution_options"]
setuptools_scm = "onedotoh:guess_version"
有一个新的部分:project.entry-points。这意味着当 setuptools 准备好最终确定分发选项时,将调用函数 guess_version。
guess_version 的代码只有一行
def guess_version(dist):
dist.metadata.version = "1.0.0"
版本设置为 1.0.0
使用 onedotoh 很微妙。一个问题是编写 pyproject.toml 的 project 部分,使其看起来像这样
[project]
name = "a_pyproject"
version = "0.1.2"
pyproject.toml 中的 version 将覆盖来自插件的版本。
显而易见的解决方案是删除 version 字段
[project]
name = "a_pyproject"
但这会以不同的方式失败。如果没有 project 部分中的 version,该文件将无效。name 将不会被使用。
正确的方法如下
[project]
name = "a_pyproject"
dynamic = ["version"]
这种方法明确地将 version 字段声明为动态的。
一个完整的例子看起来像这样
[build-system]
requires = [
"setuptools",
"onedotoh",
]
build-backend = "setuptools.build_meta"
[project]
name = "a_pyproject"
dynamic = ["version"]
最终,版本被自动设置为 1.0.0。
总结
setuptools 插件仍然可以与现代 Python 打包一起使用,只要相关功能被明确声明为“动态”。这使得该领域非常适合进一步的自动化实验。
例如,除了从外部元数据猜测版本之外,如果它也使用 git remote URL 来猜测名称,会怎么样呢?
评论已关闭。