Python 打包指南:setup.py 与 pyproject.toml 的全面对比与实战

该文章已生成可运行项目,

在 Python 开发中,创建可安装的包是分享代码的重要方式。本文将深入解析两种主流打包方法——setup.pypyproject.toml,并通过一个实际项目示例,展示如何使用现代的 pyproject.toml 方法构建、测试和发布 Python 包。

一、setup.py 与 pyproject.toml 的区别

在这里插入图片描述

1. setup.py(传统方式)

setup.py 是 Python 打包的传统方法,使用 setuptoolsdistutils 定义包的元数据和依赖关系。典型示例如下:

from setuptools import setup

setup(
    name='mypackage',
    version='0.1',
    packages=['mypackage'],
    install_requires=['requests']
)

使用方法

python setup.py sdist bdist_wheel
pip install .

2. pyproject.toml(现代方式)

自 PEP 518 引入后,pyproject.toml 成为推荐的配置方式。它分离了构建系统配置和包元数据,支持多种构建工具(如 setuptoolspoetry 等)。示例:

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

[project]
name = "mypackage"
version = "0.1"
dependencies = ["requests"]

使用方法

pip install .

二、为什么推荐 pyproject.toml?

  1. 标准化与兼容性:符合最新打包标准,与各种工具兼容性更好。
  2. 简化配置:分离构建系统和元数据,使配置更清晰。
  3. 多构建系统支持:支持多种工具,提供更大灵活性。
  4. 安全性:减少对自定义脚本的依赖,降低风险。

实际场景中的必要性

假设你正在开发一个复杂的机器学习库,涉及多个依赖项和复杂的构建步骤。使用 pyproject.toml 可以轻松定义这些需求,并确保在不同的开发和部署环境中保持一致性。此外,许多现代工具(如 CI/CD 系统)已经内置了对 pyproject.toml 的支持,简化了自动化流程。

构建 Python 包的最佳实践

  1. 新项目使用 pyproject.toml:对于新项目,推荐使用 pyproject.toml,以符合现代打包标准并提高兼容性。
  2. 旧项目逐步迁移:如果维护的是已有使用 setup.py 的项目,可以继续使用,但建议在可行时迁移到 pyproject.toml
  3. 结合使用:在某些情况下,可以同时使用 pyproject.tomlsetup.py,例如用 pyproject.toml 处理大部分配置,而保留一个最小化的 setup.py 来处理特定功能(如构建 C 扩展)。
  4. 使用 setup.cfg:如果希望采用更声明式的格式但仍使用 setup.py,可以考虑使用 setup.cfg,将元数据放在配置文件中,逻辑保留在 setup.py 中。
  5. 利用构建工具:使用如 PoetryFlit 等工具,可以简化依赖管理和打包流程,自动管理 pyproject.toml 和其他相关文件的创建。

三、实战示例:构建和发布一个机器学习包

下面通过一个实际的机器学习项目示例,展示如何使用 pyproject.toml 构建、测试和发布一个 Python 包。

项目概述

我们将构建一个名为 mlpredictor 的包,该包:

  • 包含一个使用 scikit-learn 的简单分类器模型。
  • 提供训练模型和进行预测的功能。
  • 结构化以便发布到 PyPI 和 GitHub。

步骤详解

1. 创建项目结构
mlpredictor/
│
├── mlpredictor/
│   ├── __init__.py
│   ├── model.py
│
├── tests/
│   ├── test_model.py
│
├── LICENSE
├── README.md
├── pyproject.toml
└── .gitignore
2. 编写代码

mlpredictor/model.py

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
import pickle


class MLPredictor:
    def __init__(self):
        self.model = None

    def train(self):
        iris = load_iris()
        X_train, X_test, y_train, y_test = train_test_split(
            iris.data, iris.target, test_size=0.2, random_state=42
        )
        self.model = RandomForestClassifier()
        self.model.fit(X_train, y_train)

    def predict(self, data):
        if not self.model:
            raise Exception("Model is not trained yet!")
        return self.model.predict([data])

    def save_model(self, path="model.pkl"):
        with open(path, "wb") as f:
            pickle.dump(self.model, f)

    def load_model(self, path="model.pkl"):
        with open(path, "rb") as f:
            self.model = pickle.load(f)

mlpredictor/*init*.py

from .model import MLPredictor

__all__ = ["MLPredictor"]
3. 创建 pyproject.toml 文件

pyproject.toml

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

[project]
name = "mlpredictor"
version = "0.1.0"
description = "A simple machine learning package using scikit-learn"
authors = [
    {name = "Ebrahim", email = "ebimsv0501@gmail.com"}
]
license = {text = "MIT"}
readme = "README.md"
requires-python = ">=3.6"
dependencies = [
    "scikit-learn>=1.0",
]

[project.urls]
"Homepage" = "https://github.com/xxx_your_account/mlpredictor"
  • [build-system]:指定构建系统要求,这里使用 setuptoolswheel
  • [project]:包含包的元数据,如名称、版本、描述、作者、许可证、依赖项等。
4. 编写测试

使用 pytest 添加测试。

tests/test_model.py

import pytest
from mlpredictor import MLPredictor

def test_train_and_predict():
    model = MLPredictor()
    model.train()
    result = model.predict([5.1, 3.5, 1.4, 0.2])
    assert len(result) == 1

if __name__ == "__main__":
    pytest.main()
5. 添加 README、License 和 .gitignore

README.md

# MLPredictor

MLPredictor 是一个简单的机器学习包,使用 scikit-learn 训练 RandomForest 模型,并使用户能够进行预测。该包旨在演示如何打包 Python 机器学习项目以供分发。

## 特性

- 在 Iris 数据集上训练 RandomForestClassifier。
- 训练后对新数据进行预测。
- 保存和加载训练好的模型。

## 安装

您可以通过 **PyPI** 或从 **源代码** 安装该包。

### 通过 PyPI 安装

```bash
pip install mlpredictor

通过源代码安装(GitHub)

git clone https://github.com/xxx_your_account/mlpredictor.git
cd mlpredictor
pip install .

使用方法

安装后,可以使用 MLPredictor 训练模型并进行预测。

示例:训练和预测

from mlpredictor import MLPredictor

# 初始化预测器
predictor = MLPredictor()

# 在 Iris 数据集上训练模型
predictor.train()

# 对样本输入进行预测
sample_input = [5.1, 3.5, 1.4, 0.2]
prediction = predictor.predict(sample_input)

print(f"预测类别: {prediction}")

LICENSE

可以选择合适的开源许可证,如 MIT License。

.gitignore

*.pyc
__pycache__/
*.pkl
dist/
build/
6. 本地测试包

通过以下命令安装包:

pip install .

安装后,运行测试以确保一切正常:

pytest tests

注意

  • 如果使用 setup.py,它会读取 setup.py 文件以收集包元数据和安装信息,并解析和安装指定的依赖项。

  • 如果使用pyproject.toml ,它会读取该文件,可能指定构建系统要求和配置。执行上述命令后,通常会创建以下目录:

    • Distribution Directory:可能是 build/dist/.eggs/ 目录,具体取决于安装过程以及是源码安装还是 wheel 安装。
    • build/:在构建过程中创建,包含用于创建包的临时文件。
    • dist/:包含从包生成的构建分发文件(如 wheel 文件)。
    • egg-info/.egg-info/:包含有关已安装包的元数据,包括其依赖项和版本号。

确保项目正常工作后,继续后续步骤。

7. 推送到 GitHub
  1. 初始化 Git 仓库

    git init
    git add .
    git commit -m "Initial commit"
    
  2. 创建 GitHub 仓库

    前往 GitHub 并创建一个名为 mlpredictor 的新仓库。

  3. 推送代码到 GitHub

    git remote add origin https://github.com/xxx_your_account/mlpredictor.git
    git branch -M main
    git push -u origin main
    

    注意:将 xxx_your_account 替换为您的 GitHub 用户名。

8. 发布到 PyPI

现在项目已经设置并推送到 GitHub,可以将其发布到 PyPI。

  1. 安装必要的工具

    pip install twine build
    
  2. 构建包

    python -m build
    

    这将在 dist/ 目录下创建 .tar.gz.whl 文件。检查 dist/ 目录,确保包含类似以下文件:

    mlpredictor-0.1.0-py3-none-any.whl
    mlpredictor-0.1.0.tar.gz
    
  3. 上传到 PyPI

    twine upload dist/*
    

    您需要一个 PyPI 账户才能上传包。上传成功后,其他人可以通过以下命令安装您的包:

    pip install mlpredictor
    
9. 安装并使用包

通过 pip 安装后,可以在 Python 代码中使用该包:

from mlpredictor import MLPredictor

predictor = MLPredictor()
predictor.train()
prediction = predictor.predict([5.1, 3.5, 1.4, 0.2])
print("Predicted class:", prediction.item())

# 输出示例:
# Predicted class: 0

五、总结

在 Python 打包领域,setup.pypyproject.toml 各有其重要性和适用场景。尽管 setup.py 在传统项目中仍然发挥作用,但向 pyproject.toml 的转变代表了 Python 社区向更安全、标准化实践发展的趋势。对于新项目,强烈建议采用 pyproject.toml,因为它不仅简化了打包过程,还提高了与各种工具和库的兼容性。

通过本文的实战示例,您应该能够掌握如何使用 pyproject.toml 构建、测试和发布一个功能完善的 Python 包。无论是个人项目还是团队协作,遵循这些最佳实践将大大提升项目的可维护性和可扩展性。

本文章已经生成可运行项目
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值