Python打包配置Skill python-packaging

这个技能用于配置Python软件包的元数据和构建系统,以便通过UV或setuptools进行分发和发布到PyPI。它涉及设置pyproject.toml或setup.py、管理依赖、版本控制、包结构优化、测试安装和故障排除,是Python开发中实现标准化打包和高效项目分发的关键环节。关键词:Python打包,配置,元数据,setuptools,UV,PyPI,分发,构建系统,依赖管理。

DevOps 0 次安装 0 次浏览 更新于 3/9/2026

名称: python-packaging 描述: 配置Python包的元数据、setup.py和pyproject.toml,使用UV或setuptools进行分发。适用于设置Python包、配置构建系统或准备项目发布到PyPI。

Python打包

配置Python包的元数据和构建配置以进行分发。

快速开始

创建pyproject.toml,使用UV或setuptools配置进行包分发。

说明

选择构建系统

使用UV与pyproject.toml(推荐)当:

  • 开始新项目
  • 希望快速、现代化的工具
  • 需要依赖管理+打包
  • 为PyPI构建库
  • 希望符合PEP 621标准

使用setuptools(pyproject.toml + setup.py)当:

  • 维护现有项目
  • 需要与旧工具兼容
  • 需要自定义构建步骤
  • 复杂C扩展

使用setuptools(仅pyproject.toml)当:

  • 现代setuptools-only方法
  • 无自定义构建逻辑
  • 希望声明式配置
  • 符合PEP 621标准

UV配置(推荐)

使用UV创建pyproject.toml(PEP 621标准):

[project]
name = "my-package"
version = "0.1.0"
description = "Package description"
readme = "README.md"
requires-python = ">=3.9"
license = {text = "MIT"}
authors = [
    {name = "Your Name", email = "you@example.com"}
]
keywords = ["keyword1", "keyword2"]
classifiers = [
    "Development Status :: 3 - Alpha",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
]
dependencies = [
    "requests>=2.28.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0.0",
    "black>=23.0.0",
    "mypy>=1.0.0",
]

[project.scripts]
my-cli = "my_package.cli:main"

[project.urls]
Homepage = "https://github.com/username/my-package"
Repository = "https://github.com/username/my-package"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

关键字段:

  • name: 包名称(使用连字符,导入时将转换为下划线)
  • version: 语义版本控制(MAJOR.MINOR.PATCH)
  • requires-python: Python版本约束
  • dependencies: 运行时依赖,带版本约束
  • optional-dependencies: 开发和可选依赖
  • scripts: 控制台脚本入口点

版本约束:

  • >=2.28.0,<3.0.0: 兼容版本
  • ~=2.28.0: >=2.28.0, <2.29.0(补丁更新)
  • >=2.28.0: 最低版本
  • ==2.28.0: 精确版本

Setuptools配置(现代)

使用setuptools创建pyproject.toml(PEP 621):

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

[project]
name = "my-package"
version = "0.1.0"
description = "Package description"
readme = "README.md"
requires-python = ">=3.9"
license = {text = "MIT"}
authors = [
    {name = "Your Name", email = "you@example.com"}
]
keywords = ["keyword1", "keyword2"]
classifiers = [
    "Development Status :: 3 - Alpha",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
]
dependencies = [
    "requests>=2.28.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0.0",
    "black>=23.0.0",
    "mypy>=1.0.0",
]

[project.scripts]
my-cli = "my_package.cli:main"

[project.urls]
Homepage = "https://github.com/username/my-package"
Repository = "https://github.com/username/my-package"

Setuptools配置(传统)

为需要自定义构建逻辑的项目创建setup.py

from setuptools import setup, find_packages

setup(
    name="my-package",
    version="0.1.0",
    description="Package description",
    long_description=open("README.md").read(),
    long_description_content_type="text/markdown",
    author="Your Name",
    author_email="you@example.com",
    url="https://github.com/username/my-package",
    packages=find_packages(where="src"),
    package_dir={"": "src"},
    python_requires=">=3.9",
    install_requires=[
        "requests>=2.28.0",
    ],
    extras_require={
        "dev": [
            "pytest>=7.0.0",
            "black>=23.0.0",
            "mypy>=1.0.0",
        ],
    },
    entry_points={
        "console_scripts": [
            "my-cli=my_package.cli:main",
        ],
    },
    classifiers=[
        "Development Status :: 3 - Alpha",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Programming Language :: Python :: 3",
    ],
)

何时使用setup.py:

  • 自定义构建步骤(编译C扩展)
  • 从git标签动态版本
  • 复杂包发现
  • 条件依赖

包结构

扁平布局:

my-package/
├── my_package/
│   ├── __init__.py
│   └── module.py
├── tests/
├── pyproject.toml
└── README.md

Src布局(推荐用于库):

my-package/
├── src/
│   └── my_package/
│       ├── __init__.py
│       └── module.py
├── tests/
├── pyproject.toml
└── README.md

对于src布局,配置包发现:

UV/Hatchling(pyproject.toml):

[tool.hatch.build.targets.wheel]
packages = ["src/my_package"]

Setuptools(pyproject.toml):

[tool.setuptools.packages.find]
where = ["src"]

Setuptools(setup.py):

packages=find_packages(where="src"),
package_dir={"": "src"},

版本管理

静态版本在pyproject.toml中:

[project]
version = "0.1.0"

从文件动态版本:

[project]
dynamic = ["version"]

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

然后在src/my_package/__init__.py中:

__version__ = "0.1.0"

从git标签动态版本(需要setup.py):

from setuptools import setup
from setuptools_scm import get_version

setup(
    use_scm_version=True,
    setup_requires=["setuptools_scm"],
)

入口点和脚本

控制台脚本创建命令行工具:

[project.scripts]
my-cli = "my_package.cli:main"
another-tool = "my_package.tools:run"

这创建调用指定函数的可执行文件。

入口点函数:

# my_package/cli.py
def main():
    print("Hello from my-cli!")
    
if __name__ == "__main__":
    main()

包含数据文件

包含包数据:

[tool.setuptools.package-data]
my_package = ["data/*.json", "templates/*.html"]

包含非包文件:

创建MANIFEST.in:

include README.md
include LICENSE
recursive-include src/my_package/data *

分类器

使用PyPI分类器分类您的包:

classifiers = [
    # 开发状态
    "Development Status :: 3 - Alpha",
    "Development Status :: 4 - Beta",
    "Development Status :: 5 - Production/Stable",
    
    # 受众
    "Intended Audience :: Developers",
    "Intended Audience :: Science/Research",
    
    # 许可证
    "License :: OSI Approved :: MIT License",
    
    # Python版本
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    
    # 主题
    "Topic :: Software Development :: Libraries",
    "Topic :: Internet :: WWW/HTTP",
]

完整列表:https://pypi.org/classifiers/

构建和发布

使用UV(推荐):

# 构建分发
uv build

# 发布到PyPI
uv publish

# 或使用twine
uv build
twine upload dist/*

使用setuptools:

# 安装构建工具
pip install build twine

# 构建分发
python -m build

# 发布到PyPI
twine upload dist/*

测试安装

发布前本地测试您的包:

# 使用UV在可编辑模式安装
uv pip install -e .

# 或使用pip
pip install -e .

# 测试包
python -c "import my_package; print(my_package.__version__)"

# 测试控制台脚本
my-cli --help

常见模式

多包项目

对于具有多个包的项目:

[tool.hatch.build.targets.wheel]
packages = ["src/package1", "src/package2"]

可选依赖

分组可选功能:

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

安装:pip install my-package[dev]pip install my-package[all]

平台特定依赖

[project]
dependencies = [
    "requests",
    "pywin32; platform_system=='Windows'",
    "python-daemon; platform_system=='Linux'",
]

验证

发布前验证:

  1. 包成功构建:

    uv build  # 或 python -m build
    
  2. 元数据正确:

    twine check dist/*
    
  3. 安装工作:

    uv pip install dist/*.whl
    
  4. 入口点工作:

    my-cli --version
    
  5. 导入工作:

    import my_package
    print(my_package.__version__)
    

故障排除

安装后找不到包:

  • 检查包名称与导入名称(连字符vs下划线)
  • 验证包发现配置
  • 确保包目录中存在__init__.py

入口点不工作:

  • 验证函数签名(应无参数或使用argparse)
  • 检查入口点语法:"script-name = "package.module:function"
  • 更改后重新安装包

数据文件未包含:

  • 添加到pyproject.toml中的package-data
  • 或创建MANIFEST.in
  • 验证:python -m tarfile -l dist/*.tar.gz

版本冲突:

  • 使用兼容版本约束(>=,<语法)
  • 测试不同依赖版本
  • UV自动为可重复性创建锁文件