mcpField
P
packaging-python-libraries

packaging-python-libraries

github.com/wdm0006开发109101 次安装2 天前更新
代码仓库

关于 packaging-python-libraries

面向 Python 库开发者的打包与发布指南,覆盖 `pyproject.toml`、构建、PyPI 发布和依赖配置。特别强调检查 wheel 内容,并从干净环境验证安装产物。

主要功能

  1. 01配置 `pyproject.toml`
  2. 02使用 `uv` 构建发行包
  3. 03检查 PyPI 发布元数据
  4. 04配置依赖与包数据
  5. 05检查 wheel 文件内容
  6. 06从干净环境验证安装

适用场景

  1. 01为 Python 库准备发布配置
  2. 02构建并检查 sdist 和 wheel
  3. 03排查发行包遗漏子包或数据文件
  4. 04发布前验证安装包中的真实模块

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wdm0006/python-skills --skill packaging-python-libraries

安装后在 Claude Code 中输入/packaging-python-libraries确认已加载。

附带文件CONDA.md

详细介绍

Python 库打包

pyproject.toml 基础知识

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

[project]
name = "my-package"
version = "1.0.0"
description = "Short description"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT"}
dependencies = []

[project.optional-dependencies]
dev = ["pytest>=7.0", "ruff>=0.1", "mypy>=1.0"]

[project.urls]
Homepage = "https://github.com/user/package"
Documentation = "https://package.readthedocs.io"

[project.scripts]
mycli = "my_package.cli:main"

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

构建

uv build                     # Creates sdist + wheel in dist/
uvx twine check dist/*       # Validate metadata

发布到 PyPI

优先通过 CI 使用可信发布(无需存储令牌)——请参阅下文的 CI 部分。手动发布时,请通过 uvx 使用 twine 上传:

uvx twine upload --repository testpypi dist/*  # Test first
uvx twine upload dist/*                         # Production (uses a PyPI token)

GitHub Actions(可信发布)

发布由 managing-python-releases 技能中的规范标签触发发布工作流自动完成——一个流水线使用 uv 构建,并通过可信发布进行发布。请参阅 ../release-management/AUTOMATION.md;不要在此处维护第二份副本。

依赖项最佳实践

# DO: Minimum versions
dependencies = ["requests>=2.28", "click>=8.0"]

# DON'T: Exact pins (locks users)
dependencies = ["requests==2.28.1"]

# DO: Optional for features
[project.optional-dependencies]
cli = ["click>=8.0"]

包含包数据

[tool.setuptools.package-data]
my_package = ["py.typed", "data/*.json"]
from importlib.resources import files
data = files("my_package.data").joinpath("file.json").read_text()

直接引用依赖项需要实际构建

像 toolkit @ https://example.com/toolkit.whl 这样的依赖项,在安装试运行时可能无需调用构建后端就能解析。使用 Hatchling 时,实际构建 wheel 会失败,除非明确允许直接引用:

[project]
dependencies = [
    "toolkit @ https://example.com/releases/toolkit.whl",
]

[tool.hatch.metadata]
allow-direct-references = true

在这种情况下,不要使用 uv pip install --dry-run . 作为打包检查。它可能在没有构建项目的情况下报告成功。请运行 uv build(或实际执行 uv pip install .),让已配置的后端验证元数据:

uv build
uvx twine check dist/*

如需详细模板,请参阅:

验证构建产物(构建成功不代表 wheel 正确)

uv build 成功只说明后端运行了,并不代表 wheel 包含了你的代码。构建后端通过配置选择文件——hatchling 的 [tool.hatch.build.targets.wheel](only-include / packages / include),setuptools 的 [tool.setuptools.packages.find]。配置错误时,后端会毫无提示地打包出缺少子包或数据文件的 wheel。twine check 也无法发现问题——它验证的是元数据,而不是内容。

发布前务必检查 wheel,并在干净环境中安装:

uv build
uv run python -m zipfile -l dist/*.whl # list every file the wheel contains
# ^ confirm ALL your subpackages (my_pkg/, my_pkg/sub/) and data files are there,
#   not just the top-level module.

最常见的陷阱是文件选择范围过窄。以下配置只会打包 server.py,并悄悄丢弃整个 server/ 包和 data/:

# DON'T — over-narrow include drops everything else
[tool.hatch.build]
only-include = ["server.py"]

# DO — include the package (and any data dirs); let the backend walk it
[tool.hatch.build.targets.wheel]
packages = ["src/my_pkg"]

名称冲突陷阱: 绝不要同时打包顶层模块 foo.py 和包目录 foo/。包会遮蔽模块,因此 import foo 会解析到(通常几乎为空的)foo/__init__.py;而控制台入口 foo = "foo:main" 会因该包没有 main 而失败。二选一——通常保留包——并删除另一个。

然后在干净安装环境中验证,而不是在源码树中验证:

uv venv /tmp/verify && uv pip install --python /tmp/verify/bin/python dist/*.whl
cd /tmp && /tmp/verify/bin/python -c "import my_pkg; my_pkg.submodule.real_func"
mycli --help                           # exercise each console script too

请从仓库根目录以外的目录运行——否则 import my_pkg 会从 sys.path 中的源码树加载,即使 wheel 为空也会“正常运行”。并断言一个真实符号(my_pkg.submodule.real_func),绝不要只检查顶层名称能否导入:import foo 可能从一个遮蔽模块的空包中成功导入,无法证明任何问题。只执行 import foo; print("ok") 的 CI 冒烟测试会误报成功——无论分发的包是否可用,它都会通过。

检查清单

Before Release:
- [ ] pyproject.toml valid
- [ ] README.md informative
- [ ] LICENSE file exists
- [ ] Version set correctly
- [ ] twine check passes
- [ ] `uv run python -m zipfile -l dist/*.whl` shows every subpackage + data file
- [ ] Direct-reference dependencies pass a real backend build (not only install dry-run)
- [ ] No module/package name collision (no foo.py AND foo/)
- [ ] Installed the wheel into a clean venv and imported a real submodule
      symbol from a directory outside the repo (not just the top-level name)
- [ ] Each console script runs after a clean install

After Release:
- [ ] pip install works
- [ ] Import works
- [ ] GitHub release created

了解更多

此技能基于 Will McGinnis 撰写的 《高质量 Python 库开发指南》中的 Distribution(分发)部分。如需深入了解,请参阅以下文章:

评论

支持 Markdown