PEP 517 Python打包指南 | AI生成和翻译

Home 2025.10

PEP 517 于 2016 年被采纳,它为构建 Python 包定义了一个标准化接口,将构建后端(创建分发包的逻辑)与前端(如 pip 这类编排流程的工具)解耦。这使得开发者能够使用现代构建工具,而无需受限于像 setuptools 的 setup.py 这样的遗留系统。结合 PEP 518(指定构建依赖),它支持从源码树或源码分发包(sdists)进行可靠、隔离的构建。截至 2025 年,PEP 517 已成为现代 Python 打包的基础,得到了 pip(自版本 10 起支持 PEP 518,自版本 19 起完全支持 PEP 517)以及 Poetry、Flit 和 PDM 等工具的支持。

本指南涵盖了其动机、关键概念、规范、工作流程、实现及最佳实践。

动机与背景

Python 打包从 distutils(Python 1.6 引入,2000 年)发展到 setuptools(2004 年),后者增加了依赖管理但也带来了问题:

这些问题抑制了创新,并在源码安装(例如从 Git)时导致错误。PEP 517 通过标准化一个最小接口解决了这个问题:前端在隔离环境中调用后端钩子。Wheels(预构建的二进制文件,2014 年引入)简化了分发——后端只需生成符合规范的 wheels/sdists。PEP 518 通过 pyproject.toml 声明构建需求来补充,实现了隔离。

结果是:一个声明式、可扩展的生态系统,其中 setup.py 是可选的,并且像 pip 这样的工具可以在没有遗留回退的情况下构建任何兼容的项目。

关键概念

源码树与分发包

遗留的 sdists(PEP 517 之前)解压到可执行树,但现在必须包含 pyproject.toml 以符合规范。

pyproject.toml

这个 TOML 文件集中了配置。[build-system] 部分(来自 PEP 518/517)指定:

最小配置示例:

[build-system]
requires = ["setuptools>=40.8.0", "wheel"]
build-backend = "setuptools.build_meta"

需求形成一个有向无环图(无环;前端检测到环则失败)。其他部分如 [project](PEP 621)或 [tool.poetry] 保存元数据/依赖。

构建后端与前端

钩子使用 config_settings(用于标志的字典,例如 {"--debug": true})并可能输出到 stdout/stderr(UTF-8 编码)。

规范详情

[build-system] 详情

钩子

后端将这些作为属性暴露:

必需:

可选(默认为 [] 或回退):

钩子在出错时抛出异常。前端在隔离环境中调用钩子(例如,仅包含标准库 + 需求的 venv)。

构建环境

构建流程详解

逐步工作流程

对于 pip install .(源码树)或 sdist 安装:

  1. 发现:前端读取 pyproject.toml
  2. 隔离设置:创建 venv;安装 requires
  3. 需求查询:调用 get_requires_for_build_wheel(安装额外依赖)。
  4. 元数据准备:调用 prepare_metadata_for_build_wheel(或构建 wheel 并提取)。
  5. Wheel 构建:在隔离环境中调用 build_wheel;安装生成的 wheel。
  6. 回退:如果不支持 sdist,则构建 wheel;如果无钩子,则使用遗留 setup.py

对于 sdists:解包,视为源码树。开发者工作流程(例如 pip wheel .):

  1. 隔离环境。
  2. 调用后端钩子以构建 wheel/sdist。

构建隔离(PEP 518)

为构建创建临时 venv,避免污染主机环境。Pip 的 --no-build-isolation 禁用此功能(谨慎使用)。像 tox 这样的工具默认使用隔离。

新旧对比:

实现一个构建后端

创建后端:

  1. 定义一个包含钩子的模块(例如 mybackend.py)。
  2. build-backend 指向它。

最小示例(纯 Python 包):

# mybackend.py
from zipfile import ZipFile
import os
from pathlib import Path

def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
    # 复制源码到 wheel 目录,压缩为 .whl
    dist = Path(wheel_directory) / "myproj-1.0-py3-none-any.whl"
    with ZipFile(dist, 'w') as z:
        for src in Path('.').rglob('*'):
            z.write(src, src.relative_to('.'))
    return str(dist.relative_to(wheel_directory))

# 可选钩子
def get_requires_for_build_wheel(config_settings=None):
    return []

def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
    # 写入 METADATA 等
    return "myproj-1.0.dist-info"

pyproject.toml 中:

[build-system]
requires = []
build-backend = "mybackend:build_wheel"  # 实际指向模块对象

使用像 pyproject-hooks 这样的库来处理样板代码。对于扩展,通过 config_settings 集成 C 编译器。

与工具一起使用 PEP 517

迁移遗留项目:添加 [build-system];移除 setup.py 调用。

错误处理与最佳实践

截至 2025 年,setuptools 仍占主导地位(根据调查),但 Poetry/Flit 因其简洁性而采用率增长。

参考资料


Back

x-ai/grok-4-fast

Donate