跳到主要内容

Pyproject

这个文档讲述了在 openRuyi 打包时,如何使用名为 pyproject 的声明式构建系统。

当你所打包的软件包使用 pyproject.toml 声明构建后端,并遵循 PEP 517PEP 518 时,推荐使用 BuildSystem: pyproject,以便复用标准化的 Python 构建流程,并减少重复样板代码。

通常来说,这类软件包包括绝大多数现代 Python 模块,也包括一部分以 Python 为主、但同时会安装命令行工具的项目。

依赖

如需要使用 pyproject 构建系统,那么通常至少需要添加这些 BuildRequires

BuildRequires:  pyproject-rpm-macros
BuildRequires: pkgconfig(python3)

自动生成依赖

通过在使用 pyproject 声明式构建系统的 spec 文件中编写以下内容来让构建系统自动根据 PEP 517 和 PEP 518 添加构建依赖项。

%generate_buildrequires
%pyproject_buildrequires

如果自动生成的构建依赖不足,或者软件包还需要非 Python 依赖、系统库依赖,则应继续按需补充 BuildRequires

测试依赖通常可以通过 BuildOption(generate_buildrequires) 传递给 %pyproject_buildrequires 的相关参数生成,例如用于从 tox 默认环境读取测试依赖的  -t 选项;无法自动生成时再手动补充。

注意,通过 %generate_buildrequires 自动生成依赖时,它可能会在构建日志中输出错误信息,这是预期行为。

适用范围

pyproject 声明式构建系统适用于以下场景:

  • 上游源码根目录存在 pyproject.toml
  • 构建过程遵循 PEP 517 接口

需要注意的是,如果项目虽然包含 pyproject.toml,但实际构建流程依赖自定义脚本、非标准构建步骤,或者主要不是 Python 包,则不一定适合直接使用 pyproject 声明式构建系统。

示例

假设原有的生成构建依赖、构建与安装配置如下:

%generate_buildrequires
%pyproject_buildrequires -x test

%build
%pyproject_wheel

%install
%pyproject_install
%pyproject_save_files example_pkg

%check
%pytest

使用 pyproject 声明式构建系统后,部分参数可以直接交由构建系统默认处理,而无需显式写明。我们可以改写为如下形式:

BuildSystem:  pyproject

BuildOption(generate_buildrequires): -x test
BuildOption(install): -l example_pkg

注意,在使用 pyproject 声明式构建系统时,一定要在 BuildOption(install) 处传入对应的模块名。由于该选项会作为参数传递给 %pyproject_save_files,因此通常建议默认添加 -l 参数。

-l 参数会根据 PEP 639 检查上游是否声明了 License-File;如果构建时报出 No License-File 错误,则去掉该参数。

当上游正确声明了 License-File 时,%pyproject_save_files -l 会自动将对应文件记录到 Python 包的 .dist-info/licenses/ 目录下。这种情况下通常不需要再在 %files 中手动写 %license LICENSE;只有未被自动记录、但仍需作为许可证文件安装的内容,才需要额外补充。

如果原有安装阶段还有额外清理逻辑,例如:

%install
%pyproject_install
%pyproject_save_files -l example_pkg
rm -f %{buildroot}%{_bindir}/debug-helper

那么修改后可以写为:

BuildSystem:  pyproject

BuildOption(install): -l example_pkg

%install -a
rm -f %{buildroot}%{_bindir}/debug-helper

测试

pyproject 声明式构建系统默认会进行冒烟测试,即对已安装的模块做 import 检查。通常来说,不应直接置空 %check 来跳过测试。

如果在这个过程中需要排除某些模块,可以通过 BuildOption(check)%pyproject_check_import 传递参数,并且在上方写明跳过的原因。例如:

BuildSystem:  pyproject

BuildOption(install): example_pkg
# No module named 'marray'
BuildOption(check): -e 'example_pkg.tests*'

如需额外补充 pytest 测试,可以直接编写追加操作步骤:

%check -a
%pytest

tox 等测试同理,可使用 %tox 宏。

构建系统宏说明

pyproject 的相关构建系统宏在 /usr/lib/rpm/macros.d/macros.pyproject 内。

部分构建宏的介绍,可参考 Python 打包指南下方的 RPM 宏说明。