现代 Python 项目管理:pyproject.toml 完全指南

Intro

最近打算构建一些开源工具套件,想着能不能把 ruff, darglint, mypy 这些 lint 工具全部 all in one 整合一下,化简配置流程,因此详细看了一下这些框架是怎么做 pyproject.toml 配置的。

在 Python 项目开发的历史长河中,我们经历了从 setup.pyrequirements.txt,再到 setup.cfg 的变迁。

所以你可以看到到 python 会有各种各样的配置文件,属实有点头疼,各种工具链也到处配置,真的不让人省心…

而现在,pyproject.toml 的出现标志着 Python 项目管理进入了一个新的时代,本文会详细解读一下这个现代 Python 项目管理的核心配置文件。

为什么需要 pyproject.toml?

在传统的 Python 项目中,我们往往需要维护多个配置文件:

  • setup.py 用于项目打包
  • requirements.txt 管理依赖
  • setup.cfg 存放项目元数据
  • 各种工具的配置文件(.pylintrcpytest.ini 等)
  • 这种分散的配置方式带来了几个问题:

    1. 配置分散,难以统一管理
    2. 不同文件格式增加学习成本
    3. 工具配置可能存在冲突
    4. 项目结构不够清晰

    pyproject.toml 的出现就是为了解决这些问题。它提供了一个集中的、标准化的配置方式,让项目管理变得更加简单和清晰。

    pyproject.toml 的标准之路

    PEP 518:奠定基础

    2016 年,PEP 518 提案定义了 pyproject.toml 文件的基本结构和构建系统规范。这个提案主要解决了 Python 项目构建时的依赖问题,让构建过程变得更加可靠。

    Link: https://peps.python.org/pep-0518/

    PEP 621:统一项目元数据

    2020 年,PEP 621 进一步规范化了项目元数据的格式,使得不同的构建后端都能以统一的方式处理项目信息。

    Link: https://peps.python.org/pep-0621/

    pyproject.toml 的核心结构

    1. 构建系统配置

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

    这部分定义了构建项目所需的工具和后端。

    2. 项目元数据

    [project]
    name = "your-awesome-project"
    version = "0.1.0"
    description = "一个很棒的项目"
    authors = [
        {name = "作者名", email = "author@example.com"}
    ]
    dependencies = [
        "requests>=2.24.0",
        "pandas>=1.0.0"
    ]
    

    这里包含了项目的基本信息和依赖要求。

    3. 开发依赖和可选功能

    [project.optional-dependencies]
    dev = ["pytest", "black", "mypy"]
    docs = ["sphinx", "sphinx-rtd-theme"]
    

    你可以定义不同场景下需要的额外依赖。

    4. 工具配置

    [tool.black]
    line-length = 88
    target-version = ['py37']
    
    [tool.isort]
    profile = "black"
    
    [tool.pytest.ini_options]
    minversion = "6.0"
    addopts = "-ra -q"
    

    各种开发工具的配置都可以统一在这里管理。

    现代化工具支持

    现代 Python 项目管理工具都对 pyproject.toml 提供了很好的支持:

    1. Poetry:完全基于 pyproject.toml 的依赖管理工具
    2. PDM:新一代 Python 包管理器
    3. Hatch:现代化的项目管理工具
    4. Rye:新兴的 Python 项目管理工具

    自定义配置信息

    如果你有一些自己的配置信息,自己读取 pyproject.toml 也很简单,就像读取 json,yaml 一样,下面是一个示例代码:

    import tomli  # For Python < 3.11
    # For Python 3.11+, you can use: import tomllib
    
    def read_pyproject_toml(file_path="pyproject.toml"):
        """
        读取并解析 pyproject.toml 文件
        
        Args:
            file_path (str): pyproject.toml 文件的路径
            
        Returns:
            dict: 解析后的 TOML 内容
        """
        try:
            with open(file_path, mode="rb") as fp:
                # 使用 rb (二进制读取模式) 来避免编码问题
                toml_dict = tomli.load(fp)
                return toml_dict
        except FileNotFoundError:
            print(f"错误: 找不到文件 '{file_path}'")
            return None
        except Exception as e:
            print(f"解析 TOML 文件时出错: {str(e)}")
            return None
    
    def print_project_info(toml_dict):
        """
        打印项目主要信息
        
        Args:
            toml_dict (dict): 解析后的 TOML 字典
        """
        if not toml_dict:
            return
        
        # 打印项目基本信息
        if "project" in toml_dict:
            project = toml_dict["project"]
            print("项目信息:")
            print(f"名称: {project.get('name', '未指定')}")
            print(f"版本: {project.get('version', '未指定')}")
            print(f"描述: {project.get('description', '未指定')}")
            print(f"作者: {project.get('authors', ['未指定'])}")
            
            # 打印依赖信息
            if "dependencies" in project:
                print("\n依赖项:")
                for dep in project["dependencies"]:
                    print(f"- {dep}")
        
        # 打印构建系统信息
        if "build-system" in toml_dict:
            build_system = toml_dict["build-system"]
            print("\n构建系统:")
            print(f"构建后端: {build_system.get('build-backend', '未指定')}")
            print(f"依赖项: {build_system.get('requires', [])}")
    
    def main():
        # 读取并解析 TOML 文件
        toml_dict = read_pyproject_toml()
        
        if toml_dict:
            # 打印完整的解析结果
            print("完整的 TOML 内容:")
            print(toml_dict)
            print("\n" + "="*50 + "\n")
            
            # 打印格式化的项目信息
            print_project_info(toml_dict)
    
    if __name__ == "__main__":
        main()
    

    需要注意的是:

  • Python < 3.11 需要安装 tomli: pip install tomli
  • Python 3.11+ 可以直接使用内置的 tomllib
  • 至此,大致就可以理解各种工具链是如何配置的自己的参数了,当然如何更好地配置,还是要看官方文档(虽然有些文档真的写的很烂,如 darglint)。

    下一步,我将尝试设计一套 all in one 的 lint 方案。

    作者:Zeeland

    物联沃分享整理
    物联沃-IOTWORD物联网 » 现代 Python 项目管理:pyproject.toml 完全指南

    发表回复