☰
HoRain云--Python打包与分发:pyproject.toml、wheel与私有PyPI
2026/10/21 11:37:32 网站建设 项目流程

引言

从脚本到可安装包,打包是分发的前提。本文讲解现代Python打包规范pyproject.toml、wheel构建、私有PyPI搭建和CI发布。

一、打包的历史

  • setup.py:传统方式,执行代码,不安全

  • setup.cfg:声明式,但仍需setup.py

  • pyproject.toml:PEP 518/621,现代标准

二、pyproject.toml

toml

复制

下载

[build-system] requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta" [project] name = "mypackage" version = "1.0.0" description = "一个示例包" readme = "README.md" requires-python = ">=3.9" license = {text = "MIT"} authors = [ {name = "Your Name", email = "you@example.com"}, ] keywords = ["example", "demo"] classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", ] dependencies = [ "requests>=2.28", "pydantic>=2.0", ] [project.optional-dependencies] dev = ["pytest", "ruff", "mypy"] docs = ["sphinx"] [project.scripts] mytool = "mypackage.cli:main" [project.urls] Homepage = "https://github.com/user/mypackage" Repository = "https://github.com/user/mypackage" [tool.setuptools.packages.find] where = ["src"] [tool.setuptools.package-data] mypackage = ["templates/*.html"]

项目结构:

text

复制

下载

mypackage/ ├── pyproject.toml ├── README.md ├── src/ │ └── mypackage/ │ ├── __init__.py │ ├── core.py │ └── cli.py └── tests/

三、动态版本

从__init__.py读取版本:

toml

复制

下载

[project] dynamic = ["version"] [tool.setuptools.dynamic] version = {attr = "mypackage.__version__"}

python

复制

下载

# src/mypackage/__init__.py __version__ = "1.0.0"

或用setuptools_scm从Git tag:

toml

复制

下载

[build-system] requires = ["setuptools>=61", "setuptools_scm>=8"] [tool.setuptools_scm]

四、构建wheel

bash

复制

下载

pip install build python -m build

生成:

text

复制

下载

dist/ ├── mypackage-1.0.0-py3-none-any.whl └── mypackage-1.0.0.tar.gz

wheel vs sdist

  • wheel:预编译,安装快

  • sdist:源码包,需构建

优先发布wheel。

五、安装与测试

bash

复制

下载

# 本地安装 pip install dist/mypackage-1.0.0-py3-none-any.whl # 开发模式 pip install -e . # 测试 pip install -e ".[dev]" pytest

六、CLI入口

python

复制

下载

# src/mypackage/cli.py import argparse def main(): parser = argparse.ArgumentParser() parser.add_argument("name") args = parser.parse_args() print(f"Hello, {args.name}") if __name__ == "__main__": main()

pyproject.toml:

toml

复制

下载

[project.scripts] mytool = "mypackage.cli:main"

安装后可执行:

bash

复制

下载

mytool Tom

七、发布到PyPI

7.1 注册账号

  • PyPI:https://pypi.org

  • TestPyPI:https://test.pypi.org

7.2 配置token

~/.pypirc:

ini

复制

下载

[distutils] index-servers = pypi testpypi [pypi] username = __token__ password = pypi-xxxxx [testpypi] repository = https://test.pypi.org/legacy/ username = __token__ password = pypi-xxxxx

7.3 上传

bash

复制

下载

pip install twine # 测试 twine upload --repository testpypi dist/* # 正式 twine upload dist/*

八、私有PyPI

8.1 devpi

bash

复制

下载

pip install devpi-server devpi-web devpi-server --start --host localhost --port 3141 devpi use http://localhost:3141 devpi user -c myuser password=xxx devpi login myuser --password=xxx devpi index -c dev # 上传 devpi upload dist/*

8.2 pypiserver

bash

复制

下载

pip install pypiserver pypi-server run -p 8080 -P . -a . ./packages

上传:

bash

复制

下载

twine upload --repository-url http://localhost:8080 dist/*

客户端:

bash

复制

下载

pip install mypackage --index-url http://localhost:8080/simple/

8.3 阿里云/腾讯云制品库

企业推荐用云厂商的制品库,集成权限、审计。

九、CI/CD自动发布

9.1 GitHub Actions

yaml

复制

下载

name: Publish on: release: types: [published] jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - run: pip install build twine - run: python -m build - run: twine upload dist/* env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}

9.2 版本号管理

语义化版本MAJOR.MINOR.PATCH:

  • MAJOR:不兼容变更

  • MINOR:新功能

  • PATCH:Bug修复

十、多平台wheel

含C扩展的包需要为每个平台构建wheel。用cibuildwheel:

yaml

复制

下载

- uses: pypa/cibuildwheel@v2.16 env: CIBW_BUILD: cp39-* cp310-* cp311-* CIBW_ARCHS_LINUX: x86_64 CIBW_ARCHS_MACOS: x86_64 arm64

十一、实战:完整打包流程

11.1 项目结构

text

复制

下载

mytool/ ├── pyproject.toml ├── README.md ├── LICENSE ├── src/mytool/ │ ├── __init__.py │ └── cli.py └── tests/test_cli.py

11.2 pyproject.toml

toml

复制

下载

[build-system] requires = ["setuptools>=61"] build-backend = "setuptools.build_meta" [project] name = "mytool" version = "0.1.0" description = "命令行工具示例" readme = "README.md" requires-python = ">=3.9" dependencies = ["click>=8"] [project.scripts] mytool = "mytool.cli:main" [tool.setuptools.packages.find] where = ["src"]

11.3 cli.py

python

复制

下载

import click @click.command() @click.argument("name") def main(name): """向指定用户问好""" click.echo(f"Hello, {name}!") if __name__ == "__main__": main()

11.4 构建发布

bash

复制

下载

python -m build twine check dist/* twine upload dist/*

十二、常见问题

12.1 包找不到

  • 检查[tool.setuptools.packages.find]

  • src布局必须配置where = ["src"]

12.2 数据文件缺失

toml

复制

下载

[tool.setuptools.package-data] mytool = ["data/*.json"]

12.3 版本冲突

用pip check检查依赖。

12.4 平台兼容

用environment markers:

toml

复制

下载

dependencies = [ "pywin32; sys_platform == 'win32'", "uvloop; sys_platform != 'win32'", ]

十三、总结

现代Python打包用pyproject.toml,构建wheel,twine发布。私有包用devpi或pypiserver。CI自动发布提升效率。记住语义化版本和依赖锁定(pip-compile)。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询