python-packaging

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Python Packaging

Python包打包与分发

Configure Python package metadata and build configuration for distribution.
配置用于分发的Python包元数据和构建配置。

Quick Start

快速开始

Create pyproject.toml with UV or setuptools configuration for package distribution.
创建包含UV或setuptools配置的pyproject.toml文件,用于包分发。

Instructions

操作指南

Choosing Build System

选择构建系统

Use UV with pyproject.toml (recommended) when:
  • Starting new projects
  • Want fast, modern tooling
  • Need dependency management + packaging
  • Building libraries for PyPI
  • Want PEP 621 compliance
Use setuptools (pyproject.toml + setup.py) when:
  • Maintaining existing projects
  • Need compatibility with older tools
  • Require custom build steps
  • Complex C extensions
Use setuptools (pyproject.toml only) when:
  • Modern setuptools-only approach
  • No custom build logic
  • Want declarative configuration
  • PEP 621 compliance
推荐在以下场景使用UV + pyproject.toml:
  • 启动新项目
  • 想要快速、现代化的工具链
  • 需要依赖管理 + 包打包能力
  • 为PyPI构建库
  • 希望符合PEP 621标准
在以下场景使用setuptools(pyproject.toml + setup.py):
  • 维护现有项目
  • 需要与旧工具兼容
  • 自定义构建步骤
  • 复杂的C扩展
在以下场景使用setuptools(仅pyproject.toml):
  • 现代化的纯setuptools方案
  • 无需自定义构建逻辑
  • 希望使用声明式配置
  • 符合PEP 621标准

UV Configuration (Recommended)

UV配置(推荐)

Create
pyproject.toml
with UV (PEP 621 standard):
toml
[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"
Key fields:
  • name
    : Package name (use hyphens, will be converted to underscores for import)
  • version
    : Semantic versioning (MAJOR.MINOR.PATCH)
  • requires-python
    : Python version constraint
  • dependencies
    : Runtime dependencies with version constraints
  • optional-dependencies
    : Development and optional dependencies
  • scripts
    : Console script entry points
Version constraints:
  • >=2.28.0,<3.0.0
    : Compatible versions
  • ~=2.28.0
    : >=2.28.0, <2.29.0 (patch updates)
  • >=2.28.0
    : Minimum version
  • ==2.28.0
    : Exact version
创建符合PEP 621标准的UV配置文件
pyproject.toml
toml
[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
    :语义化版本号(主版本.次版本.修订版本)
  • 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 Configuration (Modern)

Setuptools配置(现代化方案)

Create
pyproject.toml
with setuptools (PEP 621):
toml
[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"
创建符合PEP 621标准的setuptools配置文件
pyproject.toml
toml
[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 Configuration (Legacy)

Setuptools配置(传统方案)

Create
setup.py
for projects requiring custom build logic:
python
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",
    ],
)
When to use setup.py:
  • Custom build steps (compiling C extensions)
  • Dynamic version from git tags
  • Complex package discovery
  • Conditional dependencies
为需要自定义构建逻辑的项目创建
setup.py
python
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标签动态获取版本号
  • 复杂的包发现逻辑
  • 条件依赖

Package Structure

包结构

Flat layout:
my-package/
├── my_package/
│   ├── __init__.py
│   └── module.py
├── tests/
├── pyproject.toml
└── README.md
Src layout (recommended for libraries):
my-package/
├── src/
│   └── my_package/
│       ├── __init__.py
│       └── module.py
├── tests/
├── pyproject.toml
└── README.md
For src layout, configure package discovery:
UV/Hatchling (pyproject.toml):
toml
[tool.hatch.build.targets.wheel]
packages = ["src/my_package"]
Setuptools (pyproject.toml):
toml
[tool.setuptools.packages.find]
where = ["src"]
Setuptools (setup.py):
python
packages=find_packages(where="src"),
package_dir={"": "src"},
扁平化结构:
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):
toml
[tool.hatch.build.targets.wheel]
packages = ["src/my_package"]
Setuptools(pyproject.toml):
toml
[tool.setuptools.packages.find]
where = ["src"]
Setuptools(setup.py):
python
packages=find_packages(where="src"),
package_dir={"": "src"},

Version Management

版本管理

Static version in pyproject.toml:
toml
[project]
version = "0.1.0"
Dynamic version from file:
toml
[project]
dynamic = ["version"]

[tool.setuptools.dynamic]
version = {attr = "my_package.__version__"}
Then in
src/my_package/__init__.py
:
python
__version__ = "0.1.0"
Dynamic version from git tags (requires setup.py):
python
from setuptools import setup
from setuptools_scm import get_version

setup(
    use_scm_version=True,
    setup_requires=["setuptools_scm"],
)
在pyproject.toml中设置静态版本号:
toml
[project]
version = "0.1.0"
从文件中动态获取版本号:
toml
[project]
dynamic = ["version"]

[tool.setuptools.dynamic]
version = {attr = "my_package.__version__"}
然后在
src/my_package/__init__.py
中添加:
python
__version__ = "0.1.0"
从Git标签动态获取版本号(需使用setup.py):
python
from setuptools import setup
from setuptools_scm import get_version

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

Entry Points and Scripts

入口点与脚本

Console scripts create command-line tools:
toml
[project.scripts]
my-cli = "my_package.cli:main"
another-tool = "my_package.tools:run"
This creates executables that call the specified functions.
Entry point function:
python
undefined
控制台脚本用于创建命令行工具:
toml
[project.scripts]
my-cli = "my_package.cli:main"
another-tool = "my_package.tools:run"
这会生成可执行文件,调用指定的函数。
入口点函数示例:
python
undefined

my_package/cli.py

my_package/cli.py

def main(): print("Hello from my-cli!")
if name == "main": main()
undefined
def main(): print("Hello from my-cli!")
if name == "main": main()
undefined

Including Data Files

包含数据文件

Include package data:
toml
[tool.setuptools.package-data]
my_package = ["data/*.json", "templates/*.html"]
Include non-package files:
Create
MANIFEST.in
:
include README.md
include LICENSE
recursive-include src/my_package/data *
包含包内数据文件:
toml
[tool.setuptools.package-data]
my_package = ["data/*.json", "templates/*.html"]
包含非包内文件:
创建
MANIFEST.in
文件:
include README.md
include LICENSE
recursive-include src/my_package/data *

Classifiers

分类器

Use PyPI classifiers to categorize your package:
toml
classifiers = [
    # Development status
    "Development Status :: 3 - Alpha",
    "Development Status :: 4 - Beta",
    "Development Status :: 5 - Production/Stable",
    
    # Audience
    "Intended Audience :: Developers",
    "Intended Audience :: Science/Research",
    
    # License
    "License :: OSI Approved :: MIT License",
    
    # Python versions
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    
    # Topics
    "Topic :: Software Development :: Libraries",
    "Topic :: Internet :: WWW/HTTP",
]
使用PyPI分类器对包进行分类:
toml
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/

Building and Publishing

构建与发布

With UV (recommended):
bash
undefined
使用UV(推荐):
bash
undefined

Build distribution

构建分发包

uv build
uv build

Publish to PyPI

发布到PyPI

uv publish
uv publish

Or use twine

或使用twine

uv build twine upload dist/*

**With setuptools:**
```bash
uv build twine upload dist/*

**使用setuptools:**
```bash

Install build tools

安装构建工具

pip install build twine
pip install build twine

Build distribution

构建分发包

python -m build
python -m build

Publish to PyPI

发布到PyPI

twine upload dist/*
undefined
twine upload dist/*
undefined

Testing Installation

测试安装

Test your package locally before publishing:
bash
undefined
在发布前本地测试包:
bash
undefined

Install in editable mode with UV

使用UV以可编辑模式安装

uv pip install -e .
uv pip install -e .

Or with pip

或使用pip

pip install -e .
pip install -e .

Test the package

测试包

python -c "import my_package; print(my_package.version)"
python -c "import my_package; print(my_package.version)"

Test console scripts

测试控制台脚本

my-cli --help
undefined
my-cli --help
undefined

Common Patterns

常见模式

Multi-Package Project

多包项目

For projects with multiple packages:
toml
[tool.hatch.build.targets.wheel]
packages = ["src/package1", "src/package2"]
对于包含多个包的项目:
toml
[tool.hatch.build.targets.wheel]
packages = ["src/package1", "src/package2"]

Optional Dependencies

可选依赖

Group optional features:
toml
[project.optional-dependencies]
dev = ["pytest", "black", "mypy"]
docs = ["sphinx", "sphinx-rtd-theme"]
aws = ["boto3"]
all = ["pytest", "black", "mypy", "sphinx", "boto3"]
Install with:
pip install my-package[dev]
or
pip install my-package[all]
对可选功能进行分组:
toml
[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]

Platform-Specific Dependencies

平台特定依赖

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

Validation

验证

Before publishing, verify:
  1. Package builds successfully:
    bash
    uv build  # or python -m build
  2. Metadata is correct:
    bash
    twine check dist/*
  3. Installation works:
    bash
    uv pip install dist/*.whl
  4. Entry points work:
    bash
    my-cli --version
  5. Imports work:
    python
    import my_package
    print(my_package.__version__)
发布前,请验证以下内容:
  1. 包构建成功:
    bash
    uv build  # 或 python -m build
  2. 元数据正确:
    bash
    twine check dist/*
  3. 安装正常:
    bash
    uv pip install dist/*.whl
  4. 入口点正常工作:
    bash
    my-cli --version
  5. 导入正常:
    python
    import my_package
    print(my_package.__version__)

Troubleshooting

故障排除

Package not found after installation:
  • Check package name vs. import name (hyphens vs. underscores)
  • Verify package discovery configuration
  • Ensure
    __init__.py
    exists in package directory
Entry points not working:
  • Verify function signature (should take no arguments or use argparse)
  • Check entry point syntax:
    "script-name = "package.module:function"
  • Reinstall package after changes
Data files not included:
  • Add to
    package-data
    in pyproject.toml
  • Or create MANIFEST.in
  • Verify with:
    python -m tarfile -l dist/*.tar.gz
Version conflicts:
  • Use compatible version constraints (
    >=,<
    syntax)
  • Test with different dependency versions
  • UV automatically creates lock files for reproducibility
安装后找不到包:
  • 检查包名称与导入名称的区别(连字符 vs 下划线)
  • 验证包发现配置是否正确
  • 确保包目录中存在
    __init__.py
    文件
入口点无法工作:
  • 验证函数签名(应无参数或使用argparse)
  • 检查入口点语法:
    "脚本名称 = 包.模块:函数"
  • 修改后重新安装包
数据文件未被包含:
  • 在pyproject.toml中添加到
    package-data
  • 或创建MANIFEST.in文件
  • 使用以下命令验证:
    python -m tarfile -l dist/*.tar.gz
版本冲突:
  • 使用兼容的版本约束(
    >=,<
    语法)
  • 测试不同的依赖版本
  • UV会自动生成锁文件以确保可复现性