Skip to main content 首页 创作者 arustydev agents python-packaging
python-packaging Create distributable Python packages with proper project structure, setup.py/pyproject.toml, and publishing to PyPI. Use when packaging Python libraries, creating CLI tools, or distributing Python code.
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/aRustyDev/agents --skill python-packaging命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... Strategic search planning for agent-driven research. Generates structured search-term matrices with tiered fallback strategies, engine-specific operators, and grading criteria before executing any searches. Use this skill whenever research requires more than a single search query — comparing technologies, verifying claims across sources, surveying a landscape, investigating a multi-faceted question, or building evidence for a decision. Do NOT use for quick factual lookups, fetching a single known URL, or questions answerable from a single source. Covers tech, academic, regulatory, and general domains. Think of it as "research planning" — the matrix is the plan, execution comes after.
name python-packaging description Create distributable Python packages with proper project structure, setup.py/pyproject.toml, and publishing to PyPI. Use when packaging Python libraries, creating CLI tools, or distributing Python code.
Python Packaging
Comprehensive guide to creating, structuring, and distributing Python packages using modern packaging tools, pyproject.toml, and publishing to PyPI.
When to Use This Skill
Creating Python libraries for distribution
Building command-line tools with entry points
Publishing packages to PyPI or private repositories
Setting up Python project structure
Creating installable packages with dependencies
Building wheels and source distributions
Versioning and releasing Python packages
Creating namespace packages
Implementing package metadata and classifiers
Core Concepts
1. Package Structure
Source layout : src/package_name/ (recommended)
Flat layout : package_name/ (simpler but less flexible)
Package metadata : pyproject.toml, setup.py, or setup.cfg
Distribution formats : wheel (.whl) and source distribution (.tar.gz)
2. Modern Packaging Standards
PEP 517/518 : Build system requirements
PEP 621 : Metadata in pyproject.toml
PEP 660 : Editable installs
pyproject.toml : Single source of configuration
3. Build Backends
setuptools : Traditional, widely used
hatchling : Modern, opinionated
flit : Lightweight, for pure Python
poetry : Dependency management + packaging
4. Distribution
PyPI : Python Package Index (public)
TestPyPI : Testing before production
Private repositories : JFrog, AWS CodeArtifact, etc.
Quick Start
Minimal Package Structure my-package/
├── pyproject.toml
├── README.md
├── LICENSE
├── src/
│ └── my_package/
│ ├── __init__.py
│ └── module.py
└── tests/
└── test_module.py
Minimal pyproject.toml [build-system]
requires = ["setuptools>=61.0" ]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
version = "0.1.0"
description = "A short description"
authors = [{name = "Your Name" , email = "you@example.com" }]
readme = "README.md"
requires-python = ">=3.8"
dependencies = [
"requests>=2.28.0" ,
]
[project.optional-dependencies]
dev = [
"pytest>=7.0" ,
"black>=22.0" ,
]
Package Structure Patterns
Pattern 1: Source Layout (Recommended) my-package/
├── pyproject.toml
├── README.md
├── LICENSE
├── .gitignore
├── src/
│ └── my_package/
│ ├── __init__.py
│ ├── core.py
│ ├── utils.py
│ └── py.typed # For type hints
├── tests/
│ ├── __init__.py
│ ├── test_core.py
│ └── test_utils.py
└── docs/
└── index.md
Prevents accidentally importing from source
Cleaner test imports
Better isolation
pyproject.toml for source layout:
[tool.setuptools.packages.find]
where = ["src" ]
Pattern 2: Flat Layout my-package/
├── pyproject.toml
├── README.md
├── my_package/
│ ├── __init__.py
│ └── module.py
└── tests/
└── test_module.py
Can import package without installing
Less professional for libraries
Pattern 3: Multi-Package Project project/
├── pyproject.toml
├── packages/
│ ├── package-a/
│ │ └── src/
│ │ └── package_a/
│ └── package-b/
│ └── src/
│ └── package_b/
└── tests/
Complete pyproject.toml Examples
Pattern 4: Full-Featured pyproject.toml [build-system]
requires = ["setuptools>=61.0" , "wheel" ]
build-backend = "setuptools.build_meta"
[project]
name = "my-awesome-package"
version = "1.0.0"
description = "An awesome Python package"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT" }
authors = [
{name = "Your Name" , email = "you@example.com" },
]
maintainers = [
{name = "Maintainer Name" , email = "maintainer@example.com" },
]
keywords = ["example" , "package" , "awesome" ]
classifiers = [
"Development Status :: 4 - Beta" ,
"Intended Audience :: Developers" ,
"License :: OSI Approved :: MIT License" ,
"Programming Language :: Python :: 3" ,
"Programming Language :: Python :: 3.8" ,
"Programming Language :: Python :: 3.9" ,
"Programming Language :: Python :: 3.10" ,
"Programming Language :: Python :: 3.11" ,
"Programming Language :: Python :: 3.12" ,
]
dependencies = [
"requests>=2.28.0,<3.0.0" ,
"click>=8.0.0" ,
"pydantic>=2.0.0" ,
]
[project.optional-dependencies]
dev = [
"pytest>=7.0.0" ,
"pytest-cov>=4.0.0" ,
"black>=23.0.0" ,
"ruff>=0.1.0" ,
"mypy>=1.0.0" ,
]
docs = [
"sphinx>=5.0.0" ,
"sphinx-rtd-theme>=1.0.0" ,
]
all = [
"my-awesome-package[dev,docs]" ,
]
[project.urls]
Homepage = "https://github.com/username/my-awesome-package"
Documentation = "https://my-awesome-package.readthedocs.io"
Repository = "https://github.com/username/my-awesome-package"
"Bug Tracker" = "https://github.com/username/my-awesome-package/issues"
Changelog = "https://github.com/username/my-awesome-package/blob/main/CHANGELOG.md"
[projectcli]
my-cli = "my_package.cli:main"
awesome-tool = "my_package.tools:run"
[project.entry-points."my_package.plugins"]
plugin1 = "my_package.plugins:plugin1"
[tool.setuptools]
package-dir = {"" = "src" }
zip-safe = false
[tool.setuptools.packages.find]
where = ["src" ]
include = ["my_package*" ]
exclude = ["tests*" ]
[tool.setuptools.package-data]
my_package = ["py.typed" , "*.pyi" , "data/*.json" ]
[tool.black]
line-length = 100
target-version = ["py38" , "py39" , "py310" , "py311" ]
include = '\.pyi?$'
[tool.ruff]
line-length = 100
target-version = "py38"
[tool.ruff.lint]
select = ["E" , "F" , "I" , "N" , "W" , "UP" ]
[tool.mypy]
python_version = "3.8"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
[tool.pytest.ini_options]
testpaths = ["tests" ]
python_files = ["test_*.py" ]
addopts = "-v --cov=my_package --cov-report=term-missing"
[tool.coverage.run]
source = ["src" ]
omit = ["*/tests/*" ]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover" ,
"def __repr__" ,
"raise AssertionError" ,
"raise NotImplementedError" ,
]
Pattern 5: Dynamic Versioning [build-system]
requires = ["setuptools>=61.0" , "setuptools-scm>=8.0" ]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
dynamic = ["version" ]
description = "Package with dynamic version"
[tool.setuptools.dynamic]
version = {attr = "my_package.__version__" }
[tool.setuptools_scm]
write_to = "src/my_package/_version.py"
__version__ = "1.0.0"
from importlib.metadata import version
__version__ = version("my-package" )
Command-Line Interface (CLI) Patterns
Pattern 6: CLI with Click
import click
@click.group()
@click.version_option()
def cli ():
"""My awesome CLI tool."""
pass
@cli.command()
@click.argument("name" )
@click.option("--greeting" , default="Hello" , help ="Greeting to use" )
def greet (name: str , greeting: str ):
"""Greet someone."""
click.echo(f"{greeting} , {name} !" )
@cli.command()
@click.option("--count" , default=1 , help ="Number of times to repeat" )
def repeat (count: int ):
"""Repeat a message."""
for i in range (count):
click.echo(f"Message {i + 1 } " )
def main ():
"""Entry point for CLI."""
cli()
if __name__ == "__main__" :
main()
Register in pyproject.toml:
[projectcli]
my-tool = "my_package.cli:main"
pip install -e .
my-tool greet World
my-tool greet Alice --greeting="Hi"
my-tool repeat --count=3
Pattern 7: CLI with argparse
import argparse
import sys
def main ():
"""Main CLI entry point."""
parser = argparse.ArgumentParser(
description="My awesome tool" ,
prog="my-tool"
)
parser.add_argument(
"--version" ,
action="version" ,
version="%(prog)s 1.0.0"
)
subparsers = parser.add_subparsers(dest="command" , help ="Commands" )
process_parser = subparsers.add_parser("process" , help ="Process data" )
process_parser.add_argument("input_file" , help ="Input file path" )
process_parser.add_argument(
"--output" , "-o" ,
default="output.txt" ,
help ="Output file path"
)
args = parser.parse_args()
if args.command == "process" :
process_data(args.input_file, args.output)
else :
parser.print_help()
sys.exit(1 )
def process_data (input_file: str , output_file: str ):
"""Process data from input to output."""
print (f"Processing {input_file} -> {output_file} " )
if __name__ == "__main__" :
main()
Building and Publishing
Pattern 8: Build Package Locally
pip install build twine
python -m build
twine check dist/*
Pattern 9: Publishing to PyPI
pip install twine
twine upload --repository testpypi dist/*
pip install --index-url https://test.pypi.org/simple/ my-package
twine upload dist/*
Using API tokens (recommended):
[distutils]
index-servers =
pypi
testpypi
[pypi]
username = __token__
password = pypi-...your-token...
[testpypi]
username = __token__
password = pypi-...your-test-token...
Pattern 10: Automated Publishing with GitHub Actions
name: Publish to PyPI
on:
release:
types: [created ]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: Install dependencies
run: |
pip install build twine
- name: Build package
run: python -m build
- name: Check package
run: twine check dist/*
- name: Publish to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: twine upload dist/*
Advanced Patterns
Pattern 11: Including Data Files [tool.setuptools.package-data]
my_package = [
"data/*.json" ,
"templates/*.html" ,
"static/css/*.css" ,
"py.typed" ,
]
from importlib.resources import files
import json
def load_config ():
"""Load configuration from package data."""
config_file = files("my_package" ).joinpath("data/config.json" )
with config_file.open () as f:
return json.load(f)
from importlib.resources import files
data = files("my_package" ).joinpath("data/file.txt" ).read_text()
Pattern 12: Namespace Packages For large projects split across multiple repositories:
# Package 1: company-core
company/
└── core/
├── __init__.py
└── models.py
# Package 2: company-api
company/
└── api/
├── __init__.py
└── routes.py
Do NOT include init .py in the namespace directory (company/):
[project]
name = "company-core"
[tool.setuptools.packages.find]
where = ["." ]
include = ["company.core*" ]
[project]
name = "company-api"
[tool.setuptools.packages.find]
where = ["." ]
include = ["company.api*" ]
from company.core import models
from company.api import routes
Pattern 13: C Extensions [build-system]
requires = ["setuptools>=61.0" , "wheel" , "Cython>=0.29" ]
build-backend = "setuptools.build_meta"
[tool.setuptools]
ext-modules = [
{name = "my_package.fast_module" , sources = ["src/fast_module.c" ]},
]
from setuptools import setup, Extension
setup(
ext_modules=[
Extension(
"my_package.fast_module" ,
sources=["src/fast_module.c" ],
include_dirs=["src/include" ],
)
]
)
Version Management
Pattern 14: Semantic Versioning Version constraints in dependencies:
dependencies = [
"requests>=2.28.0,<3.0.0" ,
"click~=8.1.0" ,
"pydantic>=2.0" ,
"numpy==1.24.3" ,
]
Pattern 15: Git-Based Versioning [build-system]
requires = ["setuptools>=61.0" , "setuptools-scm>=8.0" ]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
dynamic = ["version" ]
[tool.setuptools_scm]
write_to = "src/my_package/_version.py"
version_scheme = "post-release"
local_scheme = "dirty-tag"
1.0.0 (from git tag)
1.0.1.dev3+g1234567 (3 commits after tag)
Testing Installation
Pattern 16: Editable Install
pip install -e .
pip install -e ".[dev]"
pip install -e ".[dev,docs]"
Pattern 17: Testing in Isolated Environment
python -m venv test-env
source test-env/bin/activate
pip install dist/my_package-1.0.0-py3-none-any.whl
python -c "import my_package; print(my_package.__version__)"
my-tool --help
deactivate
rm -rf test-env
Documentation
Pattern 18: README.md Template # My Package
[](https://pypi.org/project/my-package/ )
[](https://pypi.org/project/my-package/ )
[](https://github.com/username/my-package/actions )
Brief description of your package.
## Installation
```bash
pip install my-package
Quick Start from my_package import something
result = something.do_stuff()
Features
Feature 1
Feature 2
Feature 3
Documentation
Development git clone https://github.com/username/my-package.git
cd my-package
pip install -e ".[dev]"
pytest
License
## Common Patterns
### Pattern 19: Multi-Architecture Wheels
```yaml
# .github/workflows/wheels.yml
name: Build wheels
on: [push, pull_request]
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v3
- name: Build wheels
uses: pypa/cibuildwheel@v2.16.2
- uses: actions/upload-artifact@v3
with:
path: ./wheelhouse/*.whl
Pattern 20: Private Package Index
pip install my-package --index-url https://private.pypi.org/simple/
[global]
index-url = https://private.pypi.org/simple/
extra-index-url = https://pypi.org/simple/
twine upload --repository-url https://private.pypi.org/ dist/*
File Templates
.gitignore for Python Packages # Build artifacts
build/
dist/
*.egg-info/
*.egg
.eggs/
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
# Virtual environments
venv/
env/
ENV/
# IDE
.vscode/
.idea/
*.swp
# Testing
.pytest_cache/
.coverage
htmlcov/
# Distribution
*.whl
*.tar.gz
MANIFEST.in # MANIFEST.in
include README.md
include LICENSE
include pyproject.toml
recursive-include src/my_package/data *.json
recursive-include src/my_package/templates *.html
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
Checklist for Publishing
Resources
Best Practices Summary
Use src/ layout for cleaner package structure
Use pyproject.toml for modern packaging
Pin build dependencies in build-system.requires
Version appropriately with semantic versioning
Include all metadata (classifiers, URLs, etc.)
Test installation in clean environments
Use TestPyPI before publishing to PyPI
Document thoroughly with README and docstrings
Include LICENSE file
Automate publishing with CI/CD