[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M70NWD2ZXJCEFD67V3D8K8QC":3,"skill-same:01M70NWD2ZXJCEFD67V3D8K8QC":73},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":49,"commitSha":50,"skillDirectory":51,"forksCount":52,"repositoryHtmlUrl":53,"repositoryHomepageUrl":54,"ownerHtmlUrl":55,"ownerBlogUrl":56,"ownerDescription":57,"updatedAt":58,"install":59,"resources":72},"01M70NWD2ZXJCEFD67V3D8K8QC","python-packaging",null,"Create distributable Python packages with proper project structure, setup.py\u002Fpyproject.toml, and publishing to PyPI. Use when packaging Python libraries, creating CLI tools, or distributing Python code.","shengdabai\u002FTony-Claude-Code-Skills","shengdabai","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F116417419?v=4","01M70F6D2WY5PQV5A92BKYJQEW","Tony Sheng","01M70F6D3GAAAYZ5H4CC1G8VXM",3,"MIT","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fwshobson-agents\u002Fplugins\u002Fpython-development\u002Fskills\u002Fpython-packaging\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"python packaging","python","packaging","pypi","publishing","toml","packaging python libraries","pyproject.toml","Tools","setup.py","project structure","cli","structure","packages","python code","libraries","create","code","when","project","2026-11-10 10:12:30",false,"---\nname: python-packaging\ndescription: Create distributable Python packages with proper project structure, setup.py\u002Fpyproject.toml, and publishing to PyPI. Use when packaging Python libraries, creating CLI tools, or distributing Python code.\n---\n\n# Python Packaging\n\nComprehensive guide to creating, structuring, and distributing Python packages using modern packaging tools, pyproject.toml, and publishing to PyPI.\n\n## When to Use This Skill\n\n- Creating Python libraries for distribution\n- Building command-line tools with entry points\n- Publishing packages to PyPI or private repositories\n- Setting up Python project structure\n- Creating installable packages with dependencies\n- Building wheels and source distributions\n- Versioning and releasing Python packages\n- Creating namespace packages\n- Implementing package metadata and classifiers\n\n## Core Concepts\n\n### 1. Package Structure\n- **Source layout**: `src\u002Fpackage_name\u002F` (recommended)\n- **Flat layout**: `package_name\u002F` (simpler but less flexible)\n- **Package metadata**: pyproject.toml, setup.py, or setup.cfg\n- **Distribution formats**: wheel (.whl) and source distribution (.tar.gz)\n\n### 2. Modern Packaging Standards\n- **PEP 517\u002F518**: Build system requirements\n- **PEP 621**: Metadata in pyproject.toml\n- **PEP 660**: Editable installs\n- **pyproject.toml**: Single source of configuration\n\n### 3. Build Backends\n- **setuptools**: Traditional, widely used\n- **hatchling**: Modern, opinionated\n- **flit**: Lightweight, for pure Python\n- **poetry**: Dependency management + packaging\n\n### 4. Distribution\n- **PyPI**: Python Package Index (public)\n- **TestPyPI**: Testing before production\n- **Private repositories**: JFrog, AWS CodeArtifact, etc.\n\n## Quick Start\n\n### Minimal Package Structure\n\n```\nmy-package\u002F\n├── pyproject.toml\n├── README.md\n├── LICENSE\n├── src\u002F\n│   └── my_package\u002F\n│       ├── __init__.py\n│       └── module.py\n└── tests\u002F\n    └── test_module.py\n```\n\n### Minimal pyproject.toml\n\n```toml\n[build-system]\nrequires = [\"setuptools>=61.0\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"my-package\"\nversion = \"0.1.0\"\ndescription = \"A short description\"\nauthors = [{name = \"Your Name\", email = \"you@example.com\"}]\nreadme = \"README.md\"\nrequires-python = \">=3.8\"\ndependencies = [\n    \"requests>=2.28.0\",\n]\n\n[project.optional-dependencies]\ndev = [\n    \"pytest>=7.0\",\n    \"black>=22.0\",\n]\n```\n\n## Package Structure Patterns\n\n### Pattern 1: Source Layout (Recommended)\n\n```\nmy-package\u002F\n├── pyproject.toml\n├── README.md\n├── LICENSE\n├── .gitignore\n├── src\u002F\n│   └── my_package\u002F\n│       ├── __init__.py\n│       ├── core.py\n│       ├── utils.py\n│       └── py.typed          # For type hints\n├── tests\u002F\n│   ├── __init__.py\n│   ├── test_core.py\n│   └── test_utils.py\n└── docs\u002F\n    └── index.md\n```\n\n**Advantages:**\n- Prevents accidentally importing from source\n- Cleaner test imports\n- Better isolation\n\n**pyproject.toml for source layout:**\n```toml\n[tool.setuptools.packages.find]\nwhere = [\"src\"]\n```\n\n### Pattern 2: Flat Layout\n\n```\nmy-package\u002F\n├── pyproject.toml\n├── README.md\n├── my_package\u002F\n│   ├── __init__.py\n│   └── module.py\n└── tests\u002F\n    └── test_module.py\n```\n\n**Simpler but:**\n- Can import package without installing\n- Less professional for libraries\n\n### Pattern 3: Multi-Package Project\n\n```\nproject\u002F\n├── pyproject.toml\n├── packages\u002F\n│   ├── package-a\u002F\n│   │   └── src\u002F\n│   │       └── package_a\u002F\n│   └── package-b\u002F\n│       └── src\u002F\n│           └── package_b\u002F\n└── tests\u002F\n```\n\n## Complete pyproject.toml Examples\n\n### Pattern 4: Full-Featured pyproject.toml\n\n```toml\n[build-system]\nrequires = [\"setuptools>=61.0\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"my-awesome-package\"\nversion = \"1.0.0\"\ndescription = \"An awesome Python package\"\nreadme = \"README.md\"\nrequires-python = \">=3.8\"\nlicense = {text = \"MIT\"}\nauthors = [\n    {name = \"Your Name\", email = \"you@example.com\"},\n]\nmaintainers = [\n    {name = \"Maintainer Name\", email = \"maintainer@example.com\"},\n]\nkeywords = [\"example\", \"package\", \"awesome\"]\nclassifiers = [\n    \"Development Status :: 4 - Beta\",\n    \"Intended Audience :: Developers\",\n    \"License :: OSI Approved :: MIT License\",\n    \"Programming Language :: Python :: 3\",\n    \"Programming Language :: Python :: 3.8\",\n    \"Programming Language :: Python :: 3.9\",\n    \"Programming Language :: Python :: 3.10\",\n    \"Programming Language :: Python :: 3.11\",\n    \"Programming Language :: Python :: 3.12\",\n]\n\ndependencies = [\n    \"requests>=2.28.0,\u003C3.0.0\",\n    \"click>=8.0.0\",\n    \"pydantic>=2.0.0\",\n]\n\n[project.optional-dependencies]\ndev = [\n    \"pytest>=7.0.0\",\n    \"pytest-cov>=4.0.0\",\n    \"black>=23.0.0\",\n    \"ruff>=0.1.0\",\n    \"mypy>=1.0.0\",\n]\ndocs = [\n    \"sphinx>=5.0.0\",\n    \"sphinx-rtd-theme>=1.0.0\",\n]\nall = [\n    \"my-awesome-package[dev,docs]\",\n]\n\n[project.urls]\nHomepage = \"https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-awesome-package\"\nDocumentation = \"https:\u002F\u002Fmy-awesome-package.readthedocs.io\"\nRepository = \"https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-awesome-package\"\n\"Bug Tracker\" = \"https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-awesome-package\u002Fissues\"\nChangelog = \"https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-awesome-package\u002Fblob\u002Fmain\u002FCHANGELOG.md\"\n\n[project.scripts]\nmy-cli = \"my_package.cli:main\"\nawesome-tool = \"my_package.tools:run\"\n\n[project.entry-points.\"my_package.plugins\"]\nplugin1 = \"my_package.plugins:plugin1\"\n\n[tool.setuptools]\npackage-dir = {\"\" = \"src\"}\nzip-safe = false\n\n[tool.setuptools.packages.find]\nwhere = [\"src\"]\ninclude = [\"my_package*\"]\nexclude = [\"tests*\"]\n\n[tool.setuptools.package-data]\nmy_package = [\"py.typed\", \"*.pyi\", \"data\u002F*.json\"]\n\n# Black configuration\n[tool.black]\nline-length = 100\ntarget-version = [\"py38\", \"py39\", \"py310\", \"py311\"]\ninclude = '\\.pyi?$'\n\n# Ruff configuration\n[tool.ruff]\nline-length = 100\ntarget-version = \"py38\"\n\n[tool.ruff.lint]\nselect = [\"E\", \"F\", \"I\", \"N\", \"W\", \"UP\"]\n\n# MyPy configuration\n[tool.mypy]\npython_version = \"3.8\"\nwarn_return_any = true\nwarn_unused_configs = true\ndisallow_untyped_defs = true\n\n# Pytest configuration\n[tool.pytest.ini_options]\ntestpaths = [\"tests\"]\npython_files = [\"test_*.py\"]\naddopts = \"-v --cov=my_package --cov-report=term-missing\"\n\n# Coverage configuration\n[tool.coverage.run]\nsource = [\"src\"]\nomit = [\"*\u002Ftests\u002F*\"]\n\n[tool.coverage.report]\nexclude_lines = [\n    \"pragma: no cover\",\n    \"def __repr__\",\n    \"raise AssertionError\",\n    \"raise NotImplementedError\",\n]\n```\n\n### Pattern 5: Dynamic Versioning\n\n```toml\n[build-system]\nrequires = [\"setuptools>=61.0\", \"setuptools-scm>=8.0\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"my-package\"\ndynamic = [\"version\"]\ndescription = \"Package with dynamic version\"\n\n[tool.setuptools.dynamic]\nversion = {attr = \"my_package.__version__\"}\n\n# Or use setuptools-scm for git-based versioning\n[tool.setuptools_scm]\nwrite_to = \"src\u002Fmy_package\u002F_version.py\"\n```\n\n**In __init__.py:**\n```python\n# src\u002Fmy_package\u002F__init__.py\n__version__ = \"1.0.0\"\n\n# Or with setuptools-scm\nfrom importlib.metadata import version\n__version__ = version(\"my-package\")\n```\n\n## Command-Line Interface (CLI) Patterns\n\n### Pattern 6: CLI with Click\n\n```python\n# src\u002Fmy_package\u002Fcli.py\nimport click\n\n@click.group()\n@click.version_option()\ndef cli():\n    \"\"\"My awesome CLI tool.\"\"\"\n    pass\n\n@cli.command()\n@click.argument(\"name\")\n@click.option(\"--greeting\", default=\"Hello\", help=\"Greeting to use\")\ndef greet(name: str, greeting: str):\n    \"\"\"Greet someone.\"\"\"\n    click.echo(f\"{greeting}, {name}!\")\n\n@cli.command()\n@click.option(\"--count\", default=1, help=\"Number of times to repeat\")\ndef repeat(count: int):\n    \"\"\"Repeat a message.\"\"\"\n    for i in range(count):\n        click.echo(f\"Message {i + 1}\")\n\ndef main():\n    \"\"\"Entry point for CLI.\"\"\"\n    cli()\n\nif __name__ == \"__main__\":\n    main()\n```\n\n**Register in pyproject.toml:**\n```toml\n[project.scripts]\nmy-tool = \"my_package.cli:main\"\n```\n\n**Usage:**\n```bash\npip install -e .\nmy-tool greet World\nmy-tool greet Alice --greeting=\"Hi\"\nmy-tool repeat --count=3\n```\n\n### Pattern 7: CLI with argparse\n\n```python\n# src\u002Fmy_package\u002Fcli.py\nimport argparse\nimport sys\n\ndef main():\n    \"\"\"Main CLI entry point.\"\"\"\n    parser = argparse.ArgumentParser(\n        description=\"My awesome tool\",\n        prog=\"my-tool\"\n    )\n\n    parser.add_argument(\n        \"--version\",\n        action=\"version\",\n        version=\"%(prog)s 1.0.0\"\n    )\n\n    subparsers = parser.add_subparsers(dest=\"command\", help=\"Commands\")\n\n    # Add subcommand\n    process_parser = subparsers.add_parser(\"process\", help=\"Process data\")\n    process_parser.add_argument(\"input_file\", help=\"Input file path\")\n    process_parser.add_argument(\n        \"--output\", \"-o\",\n        default=\"output.txt\",\n        help=\"Output file path\"\n    )\n\n    args = parser.parse_args()\n\n    if args.command == \"process\":\n        process_data(args.input_file, args.output)\n    else:\n        parser.print_help()\n        sys.exit(1)\n\ndef process_data(input_file: str, output_file: str):\n    \"\"\"Process data from input to output.\"\"\"\n    print(f\"Processing {input_file} -> {output_file}\")\n\nif __name__ == \"__main__\":\n    main()\n```\n\n## Building and Publishing\n\n### Pattern 8: Build Package Locally\n\n```bash\n# Install build tools\npip install build twine\n\n# Build distribution\npython -m build\n\n# This creates:\n# dist\u002F\n#   my-package-1.0.0.tar.gz (source distribution)\n#   my_package-1.0.0-py3-none-any.whl (wheel)\n\n# Check the distribution\ntwine check dist\u002F*\n```\n\n### Pattern 9: Publishing to PyPI\n\n```bash\n# Install publishing tools\npip install twine\n\n# Test on TestPyPI first\ntwine upload --repository testpypi dist\u002F*\n\n# Install from TestPyPI to test\npip install --index-url https:\u002F\u002Ftest.pypi.org\u002Fsimple\u002F my-package\n\n# If all good, publish to PyPI\ntwine upload dist\u002F*\n```\n\n**Using API tokens (recommended):**\n```bash\n# Create ~\u002F.pypirc\n[distutils]\nindex-servers =\n    pypi\n    testpypi\n\n[pypi]\nusername = __token__\npassword = pypi-...your-token...\n\n[testpypi]\nusername = __token__\npassword = pypi-...your-test-token...\n```\n\n### Pattern 10: Automated Publishing with GitHub Actions\n\n```yaml\n# .github\u002Fworkflows\u002Fpublish.yml\nname: Publish to PyPI\n\non:\n  release:\n    types: [created]\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions\u002Fcheckout@v3\n\n      - name: Set up Python\n        uses: actions\u002Fsetup-python@v4\n        with:\n          python-version: \"3.11\"\n\n      - name: Install dependencies\n        run: |\n          pip install build twine\n\n      - name: Build package\n        run: python -m build\n\n      - name: Check package\n        run: twine check dist\u002F*\n\n      - name: Publish to PyPI\n        env:\n          TWINE_USERNAME: __token__\n          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}\n        run: twine upload dist\u002F*\n```\n\n## Advanced Patterns\n\n### Pattern 11: Including Data Files\n\n```toml\n[tool.setuptools.package-data]\nmy_package = [\n    \"data\u002F*.json\",\n    \"templates\u002F*.html\",\n    \"static\u002Fcss\u002F*.css\",\n    \"py.typed\",\n]\n```\n\n**Accessing data files:**\n```python\n# src\u002Fmy_package\u002Floader.py\nfrom importlib.resources import files\nimport json\n\ndef load_config():\n    \"\"\"Load configuration from package data.\"\"\"\n    config_file = files(\"my_package\").joinpath(\"data\u002Fconfig.json\")\n    with config_file.open() as f:\n        return json.load(f)\n\n# Python 3.9+\nfrom importlib.resources import files\n\ndata = files(\"my_package\").joinpath(\"data\u002Ffile.txt\").read_text()\n```\n\n### Pattern 12: Namespace Packages\n\n**For large projects split across multiple repositories:**\n\n```\n# Package 1: company-core\ncompany\u002F\n└── core\u002F\n    ├── __init__.py\n    └── models.py\n\n# Package 2: company-api\ncompany\u002F\n└── api\u002F\n    ├── __init__.py\n    └── routes.py\n```\n\n**Do NOT include __init__.py in the namespace directory (company\u002F):**\n\n```toml\n# company-core\u002Fpyproject.toml\n[project]\nname = \"company-core\"\n\n[tool.setuptools.packages.find]\nwhere = [\".\"]\ninclude = [\"company.core*\"]\n\n# company-api\u002Fpyproject.toml\n[project]\nname = \"company-api\"\n\n[tool.setuptools.packages.find]\nwhere = [\".\"]\ninclude = [\"company.api*\"]\n```\n\n**Usage:**\n```python\n# Both packages can be imported under same namespace\nfrom company.core import models\nfrom company.api import routes\n```\n\n### Pattern 13: C Extensions\n\n```toml\n[build-system]\nrequires = [\"setuptools>=61.0\", \"wheel\", \"Cython>=0.29\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[tool.setuptools]\next-modules = [\n    {name = \"my_package.fast_module\", sources = [\"src\u002Ffast_module.c\"]},\n]\n```\n\n**Or with setup.py:**\n```python\n# setup.py\nfrom setuptools import setup, Extension\n\nsetup(\n    ext_modules=[\n        Extension(\n            \"my_package.fast_module\",\n            sources=[\"src\u002Ffast_module.c\"],\n            include_dirs=[\"src\u002Finclude\"],\n        )\n    ]\n)\n```\n\n## Version Management\n\n### Pattern 14: Semantic Versioning\n\n```python\n# src\u002Fmy_package\u002F__init__.py\n__version__ = \"1.2.3\"\n\n# Semantic versioning: MAJOR.MINOR.PATCH\n# MAJOR: Breaking changes\n# MINOR: New features (backward compatible)\n# PATCH: Bug fixes\n```\n\n**Version constraints in dependencies:**\n```toml\ndependencies = [\n    \"requests>=2.28.0,\u003C3.0.0\",  # Compatible range\n    \"click~=8.1.0\",              # Compatible release (~= 8.1.0 means >=8.1.0,\u003C8.2.0)\n    \"pydantic>=2.0\",             # Minimum version\n    \"numpy==1.24.3\",             # Exact version (avoid if possible)\n]\n```\n\n### Pattern 15: Git-Based Versioning\n\n```toml\n[build-system]\nrequires = [\"setuptools>=61.0\", \"setuptools-scm>=8.0\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"my-package\"\ndynamic = [\"version\"]\n\n[tool.setuptools_scm]\nwrite_to = \"src\u002Fmy_package\u002F_version.py\"\nversion_scheme = \"post-release\"\nlocal_scheme = \"dirty-tag\"\n```\n\n**Creates versions like:**\n- `1.0.0` (from git tag)\n- `1.0.1.dev3+g1234567` (3 commits after tag)\n\n## Testing Installation\n\n### Pattern 16: Editable Install\n\n```bash\n# Install in development mode\npip install -e .\n\n# With optional dependencies\npip install -e \".[dev]\"\npip install -e \".[dev,docs]\"\n\n# Now changes to source code are immediately reflected\n```\n\n### Pattern 17: Testing in Isolated Environment\n\n```bash\n# Create virtual environment\npython -m venv test-env\nsource test-env\u002Fbin\u002Factivate  # Linux\u002FMac\n# test-env\\Scripts\\activate  # Windows\n\n# Install package\npip install dist\u002Fmy_package-1.0.0-py3-none-any.whl\n\n# Test it works\npython -c \"import my_package; print(my_package.__version__)\"\n\n# Test CLI\nmy-tool --help\n\n# Cleanup\ndeactivate\nrm -rf test-env\n```\n\n## Documentation\n\n### Pattern 18: README.md Template\n\n```markdown\n# My Package\n\n[![PyPI version](https:\u002F\u002Fbadge.fury.io\u002Fpy\u002Fmy-package.svg)](https:\u002F\u002Fpypi.org\u002Fproject\u002Fmy-package\u002F)\n[![Python versions](https:\u002F\u002Fimg.shields.io\u002Fpypi\u002Fpyversions\u002Fmy-package.svg)](https:\u002F\u002Fpypi.org\u002Fproject\u002Fmy-package\u002F)\n[![Tests](https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-package\u002Fworkflows\u002FTests\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-package\u002Factions)\n\nBrief description of your package.\n\n## Installation\n\n```bash\npip install my-package\n```\n\n## Quick Start\n\n```python\nfrom my_package import something\n\nresult = something.do_stuff()\n```\n\n## Features\n\n- Feature 1\n- Feature 2\n- Feature 3\n\n## Documentation\n\nFull documentation: https:\u002F\u002Fmy-package.readthedocs.io\n\n## Development\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-package.git\ncd my-package\npip install -e \".[dev]\"\npytest\n```\n\n## License\n\nMIT\n```\n\n## Common Patterns\n\n### Pattern 19: Multi-Architecture Wheels\n\n```yaml\n# .github\u002Fworkflows\u002Fwheels.yml\nname: Build wheels\n\non: [push, pull_request]\n\njobs:\n  build_wheels:\n    name: Build wheels on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, windows-latest, macos-latest]\n\n    steps:\n      - uses: actions\u002Fcheckout@v3\n\n      - name: Build wheels\n        uses: pypa\u002Fcibuildwheel@v2.16.2\n\n      - uses: actions\u002Fupload-artifact@v3\n        with:\n          path: .\u002Fwheelhouse\u002F*.whl\n```\n\n### Pattern 20: Private Package Index\n\n```bash\n# Install from private index\npip install my-package --index-url https:\u002F\u002Fprivate.pypi.org\u002Fsimple\u002F\n\n# Or add to pip.conf\n[global]\nindex-url = https:\u002F\u002Fprivate.pypi.org\u002Fsimple\u002F\nextra-index-url = https:\u002F\u002Fpypi.org\u002Fsimple\u002F\n\n# Upload to private index\ntwine upload --repository-url https:\u002F\u002Fprivate.pypi.org\u002F dist\u002F*\n```\n\n## File Templates\n\n### .gitignore for Python Packages\n\n```gitignore\n# Build artifacts\nbuild\u002F\ndist\u002F\n*.egg-info\u002F\n*.egg\n.eggs\u002F\n\n# Python\n__pycache__\u002F\n*.py[cod]\n*$py.class\n*.so\n\n# Virtual environments\nvenv\u002F\nenv\u002F\nENV\u002F\n\n# IDE\n.vscode\u002F\n.idea\u002F\n*.swp\n\n# Testing\n.pytest_cache\u002F\n.coverage\nhtmlcov\u002F\n\n# Distribution\n*.whl\n*.tar.gz\n```\n\n### MANIFEST.in\n\n```\n# MANIFEST.in\ninclude README.md\ninclude LICENSE\ninclude pyproject.toml\n\nrecursive-include src\u002Fmy_package\u002Fdata *.json\nrecursive-include src\u002Fmy_package\u002Ftemplates *.html\nrecursive-exclude * __pycache__\nrecursive-exclude * *.py[co]\n```\n\n## Checklist for Publishing\n\n- [ ] Code is tested (pytest passing)\n- [ ] Documentation is complete (README, docstrings)\n- [ ] Version number updated\n- [ ] CHANGELOG.md updated\n- [ ] License file included\n- [ ] pyproject.toml is complete\n- [ ] Package builds without errors\n- [ ] Installation tested in clean environment\n- [ ] CLI tools work (if applicable)\n- [ ] PyPI metadata is correct (classifiers, keywords)\n- [ ] GitHub repository linked\n- [ ] Tested on TestPyPI first\n- [ ] Git tag created for release\n\n## Resources\n\n- **Python Packaging Guide**: https:\u002F\u002Fpackaging.python.org\u002F\n- **PyPI**: https:\u002F\u002Fpypi.org\u002F\n- **TestPyPI**: https:\u002F\u002Ftest.pypi.org\u002F\n- **setuptools documentation**: https:\u002F\u002Fsetuptools.pypa.io\u002F\n- **build**: https:\u002F\u002Fpypa-build.readthedocs.io\u002F\n- **twine**: https:\u002F\u002Ftwine.readthedocs.io\u002F\n\n## Best Practices Summary\n\n1. **Use src\u002F layout** for cleaner package structure\n2. **Use pyproject.toml** for modern packaging\n3. **Pin build dependencies** in build-system.requires\n4. **Version appropriately** with semantic versioning\n5. **Include all metadata** (classifiers, URLs, etc.)\n6. **Test installation** in clean environments\n7. **Use TestPyPI** before publishing to PyPI\n8. **Document thoroughly** with README and docstrings\n9. **Include LICENSE** file\n10. **Automate publishing** with CI\u002FCD\n","# Python Packaging\n\nComprehensive guide to creating, structuring, and distributing Python packages using modern packaging tools, pyproject.toml, and publishing to PyPI.\n\n## When to Use This Skill\n\n- Creating Python libraries for distribution\n- Building command-line tools with entry points\n- Publishing packages to PyPI or private repositories\n- Setting up Python project structure\n- Creating installable packages with dependencies\n- Building wheels and source distributions\n- Versioning and releasing Python packages\n- Creating namespace packages\n- Implementing package metadata and classifiers\n\n## Core Concepts\n\n### 1. Package Structure\n- **Source layout**: `src\u002Fpackage_name\u002F` (recommended)\n- **Flat layout**: `package_name\u002F` (simpler but less flexible)\n- **Package metadata**: pyproject.toml, setup.py, or setup.cfg\n- **Distribution formats**: wheel (.whl) and source distribution (.tar.gz)\n\n### 2. Modern Packaging Standards\n- **PEP 517\u002F518**: Build system requirements\n- **PEP 621**: Metadata in pyproject.toml\n- **PEP 660**: Editable installs\n- **pyproject.toml**: Single source of configuration\n\n### 3. Build Backends\n- **setuptools**: Traditional, widely used\n- **hatchling**: Modern, opinionated\n- **flit**: Lightweight, for pure Python\n- **poetry**: Dependency management + packaging\n\n### 4. Distribution\n- **PyPI**: Python Package Index (public)\n- **TestPyPI**: Testing before production\n- **Private repositories**: JFrog, AWS CodeArtifact, etc.\n\n## Quick Start\n\n### Minimal Package Structure\n\n```\nmy-package\u002F\n├── pyproject.toml\n├── README.md\n├── LICENSE\n├── src\u002F\n│   └── my_package\u002F\n│       ├── __init__.py\n│       └── module.py\n└── tests\u002F\n    └── test_module.py\n```\n\n### Minimal pyproject.toml\n\n```toml\n[build-system]\nrequires = [\"setuptools>=61.0\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"my-package\"\nversion = \"0.1.0\"\ndescription = \"A short description\"\nauthors = [{name = \"Your Name\", email = \"you@example.com\"}]\nreadme = \"README.md\"\nrequires-python = \">=3.8\"\ndependencies = [\n    \"requests>=2.28.0\",\n]\n\n[project.optional-dependencies]\ndev = [\n    \"pytest>=7.0\",\n    \"black>=22.0\",\n]\n```\n\n## Package Structure Patterns\n\n### Pattern 1: Source Layout (Recommended)\n\n```\nmy-package\u002F\n├── pyproject.toml\n├── README.md\n├── LICENSE\n├── .gitignore\n├── src\u002F\n│   └── my_package\u002F\n│       ├── __init__.py\n│       ├── core.py\n│       ├── utils.py\n│       └── py.typed          # For type hints\n├── tests\u002F\n│   ├── __init__.py\n│   ├── test_core.py\n│   └── test_utils.py\n└── docs\u002F\n    └── index.md\n```\n\n**Advantages:**\n- Prevents accidentally importing from source\n- Cleaner test imports\n- Better isolation\n\n**pyproject.toml for source layout:**\n```toml\n[tool.setuptools.packages.find]\nwhere = [\"src\"]\n```\n\n### Pattern 2: Flat Layout\n\n```\nmy-package\u002F\n├── pyproject.toml\n├── README.md\n├── my_package\u002F\n│   ├── __init__.py\n│   └── module.py\n└── tests\u002F\n    └── test_module.py\n```\n\n**Simpler but:**\n- Can import package without installing\n- Less professional for libraries\n\n### Pattern 3: Multi-Package Project\n\n```\nproject\u002F\n├── pyproject.toml\n├── packages\u002F\n│   ├── package-a\u002F\n│   │   └── src\u002F\n│   │       └── package_a\u002F\n│   └── package-b\u002F\n│       └── src\u002F\n│           └── package_b\u002F\n└── tests\u002F\n```\n\n## Complete pyproject.toml Examples\n\n### Pattern 4: Full-Featured pyproject.toml\n\n```toml\n[build-system]\nrequires = [\"setuptools>=61.0\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"my-awesome-package\"\nversion = \"1.0.0\"\ndescription = \"An awesome Python package\"\nreadme = \"README.md\"\nrequires-python = \">=3.8\"\nlicense = {text = \"MIT\"}\nauthors = [\n    {name = \"Your Name\", email = \"you@example.com\"},\n]\nmaintainers = [\n    {name = \"Maintainer Name\", email = \"maintainer@example.com\"},\n]\nkeywords = [\"example\", \"package\", \"awesome\"]\nclassifiers = [\n    \"Development Status :: 4 - Beta\",\n    \"Intended Audience :: Developers\",\n    \"License :: OSI Approved :: MIT License\",\n    \"Programming Language :: Python :: 3\",\n    \"Programming Language :: Python :: 3.8\",\n    \"Programming Language :: Python :: 3.9\",\n    \"Programming Language :: Python :: 3.10\",\n    \"Programming Language :: Python :: 3.11\",\n    \"Programming Language :: Python :: 3.12\",\n]\n\ndependencies = [\n    \"requests>=2.28.0,\u003C3.0.0\",\n    \"click>=8.0.0\",\n    \"pydantic>=2.0.0\",\n]\n\n[project.optional-dependencies]\ndev = [\n    \"pytest>=7.0.0\",\n    \"pytest-cov>=4.0.0\",\n    \"black>=23.0.0\",\n    \"ruff>=0.1.0\",\n    \"mypy>=1.0.0\",\n]\ndocs = [\n    \"sphinx>=5.0.0\",\n    \"sphinx-rtd-theme>=1.0.0\",\n]\nall = [\n    \"my-awesome-package[dev,docs]\",\n]\n\n[project.urls]\nHomepage = \"https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-awesome-package\"\nDocumentation = \"https:\u002F\u002Fmy-awesome-package.readthedocs.io\"\nRepository = \"https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-awesome-package\"\n\"Bug Tracker\" = \"https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-awesome-package\u002Fissues\"\nChangelog = \"https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-awesome-package\u002Fblob\u002Fmain\u002FCHANGELOG.md\"\n\n[project.scripts]\nmy-cli = \"my_package.cli:main\"\nawesome-tool = \"my_package.tools:run\"\n\n[project.entry-points.\"my_package.plugins\"]\nplugin1 = \"my_package.plugins:plugin1\"\n\n[tool.setuptools]\npackage-dir = {\"\" = \"src\"}\nzip-safe = false\n\n[tool.setuptools.packages.find]\nwhere = [\"src\"]\ninclude = [\"my_package*\"]\nexclude = [\"tests*\"]\n\n[tool.setuptools.package-data]\nmy_package = [\"py.typed\", \"*.pyi\", \"data\u002F*.json\"]\n\n# Black configuration\n[tool.black]\nline-length = 100\ntarget-version = [\"py38\", \"py39\", \"py310\", \"py311\"]\ninclude = '\\.pyi?$'\n\n# Ruff configuration\n[tool.ruff]\nline-length = 100\ntarget-version = \"py38\"\n\n[tool.ruff.lint]\nselect = [\"E\", \"F\", \"I\", \"N\", \"W\", \"UP\"]\n\n# MyPy configuration\n[tool.mypy]\npython_version = \"3.8\"\nwarn_return_any = true\nwarn_unused_configs = true\ndisallow_untyped_defs = true\n\n# Pytest configuration\n[tool.pytest.ini_options]\ntestpaths = [\"tests\"]\npython_files = [\"test_*.py\"]\naddopts = \"-v --cov=my_package --cov-report=term-missing\"\n\n# Coverage configuration\n[tool.coverage.run]\nsource = [\"src\"]\nomit = [\"*\u002Ftests\u002F*\"]\n\n[tool.coverage.report]\nexclude_lines = [\n    \"pragma: no cover\",\n    \"def __repr__\",\n    \"raise AssertionError\",\n    \"raise NotImplementedError\",\n]\n```\n\n### Pattern 5: Dynamic Versioning\n\n```toml\n[build-system]\nrequires = [\"setuptools>=61.0\", \"setuptools-scm>=8.0\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"my-package\"\ndynamic = [\"version\"]\ndescription = \"Package with dynamic version\"\n\n[tool.setuptools.dynamic]\nversion = {attr = \"my_package.__version__\"}\n\n# Or use setuptools-scm for git-based versioning\n[tool.setuptools_scm]\nwrite_to = \"src\u002Fmy_package\u002F_version.py\"\n```\n\n**In __init__.py:**\n```python\n# src\u002Fmy_package\u002F__init__.py\n__version__ = \"1.0.0\"\n\n# Or with setuptools-scm\nfrom importlib.metadata import version\n__version__ = version(\"my-package\")\n```\n\n## Command-Line Interface (CLI) Patterns\n\n### Pattern 6: CLI with Click\n\n```python\n# src\u002Fmy_package\u002Fcli.py\nimport click\n\n@click.group()\n@click.version_option()\ndef cli():\n    \"\"\"My awesome CLI tool.\"\"\"\n    pass\n\n@cli.command()\n@click.argument(\"name\")\n@click.option(\"--greeting\", default=\"Hello\", help=\"Greeting to use\")\ndef greet(name: str, greeting: str):\n    \"\"\"Greet someone.\"\"\"\n    click.echo(f\"{greeting}, {name}!\")\n\n@cli.command()\n@click.option(\"--count\", default=1, help=\"Number of times to repeat\")\ndef repeat(count: int):\n    \"\"\"Repeat a message.\"\"\"\n    for i in range(count):\n        click.echo(f\"Message {i + 1}\")\n\ndef main():\n    \"\"\"Entry point for CLI.\"\"\"\n    cli()\n\nif __name__ == \"__main__\":\n    main()\n```\n\n**Register in pyproject.toml:**\n```toml\n[project.scripts]\nmy-tool = \"my_package.cli:main\"\n```\n\n**Usage:**\n```bash\npip install -e .\nmy-tool greet World\nmy-tool greet Alice --greeting=\"Hi\"\nmy-tool repeat --count=3\n```\n\n### Pattern 7: CLI with argparse\n\n```python\n# src\u002Fmy_package\u002Fcli.py\nimport argparse\nimport sys\n\ndef main():\n    \"\"\"Main CLI entry point.\"\"\"\n    parser = argparse.ArgumentParser(\n        description=\"My awesome tool\",\n        prog=\"my-tool\"\n    )\n\n    parser.add_argument(\n        \"--version\",\n        action=\"version\",\n        version=\"%(prog)s 1.0.0\"\n    )\n\n    subparsers = parser.add_subparsers(dest=\"command\", help=\"Commands\")\n\n    # Add subcommand\n    process_parser = subparsers.add_parser(\"process\", help=\"Process data\")\n    process_parser.add_argument(\"input_file\", help=\"Input file path\")\n    process_parser.add_argument(\n        \"--output\", \"-o\",\n        default=\"output.txt\",\n        help=\"Output file path\"\n    )\n\n    args = parser.parse_args()\n\n    if args.command == \"process\":\n        process_data(args.input_file, args.output)\n    else:\n        parser.print_help()\n        sys.exit(1)\n\ndef process_data(input_file: str, output_file: str):\n    \"\"\"Process data from input to output.\"\"\"\n    print(f\"Processing {input_file} -> {output_file}\")\n\nif __name__ == \"__main__\":\n    main()\n```\n\n## Building and Publishing\n\n### Pattern 8: Build Package Locally\n\n```bash\n# Install build tools\npip install build twine\n\n# Build distribution\npython -m build\n\n# This creates:\n# dist\u002F\n#   my-package-1.0.0.tar.gz (source distribution)\n#   my_package-1.0.0-py3-none-any.whl (wheel)\n\n# Check the distribution\ntwine check dist\u002F*\n```\n\n### Pattern 9: Publishing to PyPI\n\n```bash\n# Install publishing tools\npip install twine\n\n# Test on TestPyPI first\ntwine upload --repository testpypi dist\u002F*\n\n# Install from TestPyPI to test\npip install --index-url https:\u002F\u002Ftest.pypi.org\u002Fsimple\u002F my-package\n\n# If all good, publish to PyPI\ntwine upload dist\u002F*\n```\n\n**Using API tokens (recommended):**\n```bash\n# Create ~\u002F.pypirc\n[distutils]\nindex-servers =\n    pypi\n    testpypi\n\n[pypi]\nusername = __token__\npassword = pypi-...your-token...\n\n[testpypi]\nusername = __token__\npassword = pypi-...your-test-token...\n```\n\n### Pattern 10: Automated Publishing with GitHub Actions\n\n```yaml\n# .github\u002Fworkflows\u002Fpublish.yml\nname: Publish to PyPI\n\non:\n  release:\n    types: [created]\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions\u002Fcheckout@v3\n\n      - name: Set up Python\n        uses: actions\u002Fsetup-python@v4\n        with:\n          python-version: \"3.11\"\n\n      - name: Install dependencies\n        run: |\n          pip install build twine\n\n      - name: Build package\n        run: python -m build\n\n      - name: Check package\n        run: twine check dist\u002F*\n\n      - name: Publish to PyPI\n        env:\n          TWINE_USERNAME: __token__\n          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}\n        run: twine upload dist\u002F*\n```\n\n## Advanced Patterns\n\n### Pattern 11: Including Data Files\n\n```toml\n[tool.setuptools.package-data]\nmy_package = [\n    \"data\u002F*.json\",\n    \"templates\u002F*.html\",\n    \"static\u002Fcss\u002F*.css\",\n    \"py.typed\",\n]\n```\n\n**Accessing data files:**\n```python\n# src\u002Fmy_package\u002Floader.py\nfrom importlib.resources import files\nimport json\n\ndef load_config():\n    \"\"\"Load configuration from package data.\"\"\"\n    config_file = files(\"my_package\").joinpath(\"data\u002Fconfig.json\")\n    with config_file.open() as f:\n        return json.load(f)\n\n# Python 3.9+\nfrom importlib.resources import files\n\ndata = files(\"my_package\").joinpath(\"data\u002Ffile.txt\").read_text()\n```\n\n### Pattern 12: Namespace Packages\n\n**For large projects split across multiple repositories:**\n\n```\n# Package 1: company-core\ncompany\u002F\n└── core\u002F\n    ├── __init__.py\n    └── models.py\n\n# Package 2: company-api\ncompany\u002F\n└── api\u002F\n    ├── __init__.py\n    └── routes.py\n```\n\n**Do NOT include __init__.py in the namespace directory (company\u002F):**\n\n```toml\n# company-core\u002Fpyproject.toml\n[project]\nname = \"company-core\"\n\n[tool.setuptools.packages.find]\nwhere = [\".\"]\ninclude = [\"company.core*\"]\n\n# company-api\u002Fpyproject.toml\n[project]\nname = \"company-api\"\n\n[tool.setuptools.packages.find]\nwhere = [\".\"]\ninclude = [\"company.api*\"]\n```\n\n**Usage:**\n```python\n# Both packages can be imported under same namespace\nfrom company.core import models\nfrom company.api import routes\n```\n\n### Pattern 13: C Extensions\n\n```toml\n[build-system]\nrequires = [\"setuptools>=61.0\", \"wheel\", \"Cython>=0.29\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[tool.setuptools]\next-modules = [\n    {name = \"my_package.fast_module\", sources = [\"src\u002Ffast_module.c\"]},\n]\n```\n\n**Or with setup.py:**\n```python\n# setup.py\nfrom setuptools import setup, Extension\n\nsetup(\n    ext_modules=[\n        Extension(\n            \"my_package.fast_module\",\n            sources=[\"src\u002Ffast_module.c\"],\n            include_dirs=[\"src\u002Finclude\"],\n        )\n    ]\n)\n```\n\n## Version Management\n\n### Pattern 14: Semantic Versioning\n\n```python\n# src\u002Fmy_package\u002F__init__.py\n__version__ = \"1.2.3\"\n\n# Semantic versioning: MAJOR.MINOR.PATCH\n# MAJOR: Breaking changes\n# MINOR: New features (backward compatible)\n# PATCH: Bug fixes\n```\n\n**Version constraints in dependencies:**\n```toml\ndependencies = [\n    \"requests>=2.28.0,\u003C3.0.0\",  # Compatible range\n    \"click~=8.1.0\",              # Compatible release (~= 8.1.0 means >=8.1.0,\u003C8.2.0)\n    \"pydantic>=2.0\",             # Minimum version\n    \"numpy==1.24.3\",             # Exact version (avoid if possible)\n]\n```\n\n### Pattern 15: Git-Based Versioning\n\n```toml\n[build-system]\nrequires = [\"setuptools>=61.0\", \"setuptools-scm>=8.0\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"my-package\"\ndynamic = [\"version\"]\n\n[tool.setuptools_scm]\nwrite_to = \"src\u002Fmy_package\u002F_version.py\"\nversion_scheme = \"post-release\"\nlocal_scheme = \"dirty-tag\"\n```\n\n**Creates versions like:**\n- `1.0.0` (from git tag)\n- `1.0.1.dev3+g1234567` (3 commits after tag)\n\n## Testing Installation\n\n### Pattern 16: Editable Install\n\n```bash\n# Install in development mode\npip install -e .\n\n# With optional dependencies\npip install -e \".[dev]\"\npip install -e \".[dev,docs]\"\n\n# Now changes to source code are immediately reflected\n```\n\n### Pattern 17: Testing in Isolated Environment\n\n```bash\n# Create virtual environment\npython -m venv test-env\nsource test-env\u002Fbin\u002Factivate  # Linux\u002FMac\n# test-env\\Scripts\\activate  # Windows\n\n# Install package\npip install dist\u002Fmy_package-1.0.0-py3-none-any.whl\n\n# Test it works\npython -c \"import my_package; print(my_package.__version__)\"\n\n# Test CLI\nmy-tool --help\n\n# Cleanup\ndeactivate\nrm -rf test-env\n```\n\n## Documentation\n\n### Pattern 18: README.md Template\n\n```markdown\n# My Package\n\n[![PyPI version](https:\u002F\u002Fbadge.fury.io\u002Fpy\u002Fmy-package.svg)](https:\u002F\u002Fpypi.org\u002Fproject\u002Fmy-package\u002F)\n[![Python versions](https:\u002F\u002Fimg.shields.io\u002Fpypi\u002Fpyversions\u002Fmy-package.svg)](https:\u002F\u002Fpypi.org\u002Fproject\u002Fmy-package\u002F)\n[![Tests](https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-package\u002Fworkflows\u002FTests\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-package\u002Factions)\n\nBrief description of your package.\n\n## Installation\n\n```bash\npip install my-package\n```\n\n## Quick Start\n\n```python\nfrom my_package import something\n\nresult = something.do_stuff()\n```\n\n## Features\n\n- Feature 1\n- Feature 2\n- Feature 3\n\n## Documentation\n\nFull documentation: https:\u002F\u002Fmy-package.readthedocs.io\n\n## Development\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fusername\u002Fmy-package.git\ncd my-package\npip install -e \".[dev]\"\npytest\n```\n\n## License\n\nMIT\n```\n\n## Common Patterns\n\n### Pattern 19: Multi-Architecture Wheels\n\n```yaml\n# .github\u002Fworkflows\u002Fwheels.yml\nname: Build wheels\n\non: [push, pull_request]\n\njobs:\n  build_wheels:\n    name: Build wheels on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, windows-latest, macos-latest]\n\n    steps:\n      - uses: actions\u002Fcheckout@v3\n\n      - name: Build wheels\n        uses: pypa\u002Fcibuildwheel@v2.16.2\n\n      - uses: actions\u002Fupload-artifact@v3\n        with:\n          path: .\u002Fwheelhouse\u002F*.whl\n```\n\n### Pattern 20: Private Package Index\n\n```bash\n# Install from private index\npip install my-package --index-url https:\u002F\u002Fprivate.pypi.org\u002Fsimple\u002F\n\n# Or add to pip.conf\n[global]\nindex-url = https:\u002F\u002Fprivate.pypi.org\u002Fsimple\u002F\nextra-index-url = https:\u002F\u002Fpypi.org\u002Fsimple\u002F\n\n# Upload to private index\ntwine upload --repository-url https:\u002F\u002Fprivate.pypi.org\u002F dist\u002F*\n```\n\n## File Templates\n\n### .gitignore for Python Packages\n\n```gitignore\n# Build artifacts\nbuild\u002F\ndist\u002F\n*.egg-info\u002F\n*.egg\n.eggs\u002F\n\n# Python\n__pycache__\u002F\n*.py[cod]\n*$py.class\n*.so\n\n# Virtual environments\nvenv\u002F\nenv\u002F\nENV\u002F\n\n# IDE\n.vscode\u002F\n.idea\u002F\n*.swp\n\n# Testing\n.pytest_cache\u002F\n.coverage\nhtmlcov\u002F\n\n# Distribution\n*.whl\n*.tar.gz\n```\n\n### MANIFEST.in\n\n```\n# MANIFEST.in\ninclude README.md\ninclude LICENSE\ninclude pyproject.toml\n\nrecursive-include src\u002Fmy_package\u002Fdata *.json\nrecursive-include src\u002Fmy_package\u002Ftemplates *.html\nrecursive-exclude * __pycache__\nrecursive-exclude * *.py[co]\n```\n\n## Checklist for Publishing\n\n- [ ] Code is tested (pytest passing)\n- [ ] Documentation is complete (README, docstrings)\n- [ ] Version number updated\n- [ ] CHANGELOG.md updated\n- [ ] License file included\n- [ ] pyproject.toml is complete\n- [ ] Package builds without errors\n- [ ] Installation tested in clean environment\n- [ ] CLI tools work (if applicable)\n- [ ] PyPI metadata is correct (classifiers, keywords)\n- [ ] GitHub repository linked\n- [ ] Tested on TestPyPI first\n- [ ] Git tag created for release\n\n## Resources\n\n- **Python Packaging Guide**: https:\u002F\u002Fpackaging.python.org\u002F\n- **PyPI**: https:\u002F\u002Fpypi.org\u002F\n- **TestPyPI**: https:\u002F\u002Ftest.pypi.org\u002F\n- **setuptools documentation**: https:\u002F\u002Fsetuptools.pypa.io\u002F\n- **build**: https:\u002F\u002Fpypa-build.readthedocs.io\u002F\n- **twine**: https:\u002F\u002Ftwine.readthedocs.io\u002F\n\n## Best Practices Summary\n\n1. **Use src\u002F layout** for cleaner package structure\n2. **Use pyproject.toml** for modern packaging\n3. **Pin build dependencies** in build-system.requires\n4. **Version appropriately** with semantic versioning\n5. **Include all metadata** (classifiers, URLs, etc.)\n6. **Test installation** in clean environments\n7. **Use TestPyPI** before publishing to PyPI\n8. **Document thoroughly** with README and docstrings\n9. **Include LICENSE** file\n10. **Automate publishing** with CI\u002FCD\n",{"name":5,"description":7},"main","7850740bd837adb32f0a109ab2af82482196c6f2","skills\u002Fwshobson-agents\u002Fplugins\u002Fpython-development\u002Fskills\u002Fpython-packaging",1,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills","https:\u002F\u002Fzturnsgo.com","https:\u002F\u002Fgithub.com\u002Fshengdabai","https:\u002F\u002Fzturnsgo.com\u002F","AI × education creator — producer, not consumer. Taught 6,000+ learners; shipping learning tools & daily essays with Claude Code, practicing @xiaolai's way 🥋","2026-11-01 21:28:23",{"source":8,"skillName":5,"commands":60,"prompt":70,"zipAvailable":71},[61,64,67],{"tool":62,"command":63},"npx","npx skills add shengdabai\u002FTony-Claude-Code-Skills --skill python-packaging",{"tool":65,"command":66},"bunx","bunx skills add shengdabai\u002FTony-Claude-Code-Skills --skill python-packaging",{"tool":68,"command":69},"pnpm","pnpm dlx skills add shengdabai\u002FTony-Claude-Code-Skills --skill python-packaging","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fwshobson-agents\u002Fplugins\u002Fpython-development\u002Fskills\u002Fpython-packaging\u002FSKILL.md",true,[],[74,93,120,145,167,187],{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":85,"publishedAt":44},"01M70P17DAD4C1C47NPH6A96EM","xiaolai-methodology","以李笑来(Li Xiaolai)的思考方式、方法论与表达风格,为用户做全方位 1-on-1 教练指导,覆盖创业、赚钱、投资、学习、自学、读书写作、用 AI、以及人生心态与自我管理。当用户提到 \"李笑来\"、\"笑来\"、\"笑来老师\"、\"扮演李笑来\"、\"找笑来聊聊\"、\"笑来怎么看\"、\"xiaolai\"、\"把时间当作朋友\"、\"通往财富自由之路\"、\"定投改变命运\"、\"韭菜的自我修养\"、\"自学是门手艺\"、\"让时间陪你慢慢变富\"、\"七年就是一辈子\"、\"元认知\"、\"活在未来\"、\"复利\u002F长期主义\"、\"践行\"、\"痴迷改进\"、\"个人商业模式\u002F出售时间\"、\"睡后收入\"、\"定投\"、\"财富自由\"、\"操作系统升级\"、\"最少必要知识\"、\"北极星提示词\"、\"用 AI 该怎么学\u002F思考\" 等任一触发词,或当用户带着关于创业\u002F赚钱\u002F投资\u002F学习\u002F职业\u002F重大人生决策的困惑、希望被人用笑来式的「逻辑 + 大白话 + 类比 + 重新定义 + 践行导向」来点醒和指导时,自动进入李笑来教练模式。","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fxiaolai-methodology\u002FSKILL.md",[80],{"categoryNo":81,"categoryName":82,"taxonomyType":83,"taxonomyTypeDesc":84},"01JBSEEDCAT000000000000018","写作与文案","SCENARIO","使用场景",[86,87,88,89,90,91,92],"methodology","xiaolai","xiaolai methodology","朋友","投资","writing","收入",{"skillNo":94,"name":95,"nameZh":6,"description":96,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":97,"categories":98,"keywords":103,"publishedAt":44},"01M70P13NB9YP7ACJR1S861CDS","zread","Produce and consume a wiki-style knowledge base for a code repository via the `zread` CLI and its on-disk output under `.\u002F.zread\u002Fwiki\u002F`. Use this skill whenever the user wants to understand, onboard onto, explore, summarize, map, or get an overview of an unfamiliar codebase; asks for architecture docs, a project wiki, a repo walkthrough, module\u002Fpackage explanations, or \"what does this repo do\"; wants to generate, regenerate, resume, browse, or serve code documentation locally; or mentions zread \u002F zread.ai directly. Also use it proactively before diving into a large unknown repo — if `.\u002F.zread\u002Fwiki\u002Fcurrent` exists, read the generated pages instead of crawling source file-by-file; if it doesn't, consider offering to run `zread generate`. The trigger is the intent (understand a codebase through generated docs), not the literal word \"zread\".","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fzread\u002FSKILL.md",[99,102],{"categoryNo":100,"categoryName":101,"taxonomyType":83,"taxonomyTypeDesc":84},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[95,104,105,106,107,43,108,109,110,111,112,35,113,114,115,116,117,41,118,119],"knowledge","wiki","explore","walkthrough","get","knowledge base","run","generate","intent","map","documentation","project wiki","disk","architecture","unknown","generated",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":130,"publishedAt":44},"01M70P10S4SWMZQ8BJAFBFDRW3","youtube","Launch the YouTube Creator Agent to auto-generate videos.\nUse when: user types \u002Fyoutube, wants to create YouTube videos,\ngenerate video content, or upload to YouTube.\nKeywords: youtube, video, 视频, 创作视频, 发布视频","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fyoutube\u002FSKILL.md",[126,127],{"categoryNo":100,"categoryName":101,"taxonomyType":83,"taxonomyTypeDesc":84},{"categoryNo":128,"categoryName":129,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000036","内容创作者",[122,131,132,133,134,135,136,137,111,138,40,139,42,140,141,142,143,144],"user","content","视频","creator","generate video","videos","launch","video content","upload","use","auto","types","Video","创作",{"skillNo":146,"name":147,"nameZh":6,"description":148,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":149,"categories":150,"keywords":152,"publishedAt":44},"01M70P0YE95D8BACZCGV8BK90K","youtube-script-sync","Sync, update, or optimize Tony's GetNote knowledge base `Youtube视频逐字稿` by turning each parent recording or first-person idea note into an idempotent child note containing a directly recordable YouTube long-video or Shorts script. Use when the user says “更新\u002F同步\u002F优化 Youtube视频逐字稿知识库”, or says “更新\u002F同步\u002F优化该知识库” while this knowledge base is the active context.","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fyoutube-script-sync\u002FSKILL.md",[151],{"categoryNo":100,"categoryName":101,"taxonomyType":83,"taxonomyTypeDesc":84},[153,154,122,155,156,143,157,158,159,160,161,162,163,164,109,165,42,140,104,166],"sync","script","youtube script sync","recording","shorts","first","base","person","update","active","child","optimize","idempotent","long",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":177,"publishedAt":44},"01M70P0WMV5XT0EEC0N445PW07","writing-skills","How to write SKILL.md files that trigger reliably and teach effectively. Use when creating, improving, or reviewing Claude Code skills.","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fxiaolai\u002Fnlpm\u002Fskills\u002Fnlpm\u002Fwriting-skills\u002FSKILL.md",[173,174,175,176],{"categoryNo":81,"categoryName":82,"taxonomyType":83,"taxonomyTypeDesc":84},{"categoryNo":100,"categoryName":101,"taxonomyType":83,"taxonomyTypeDesc":84},{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":128,"categoryName":129,"taxonomyType":21,"taxonomyTypeDesc":22},[178,91,179,180,181,182,41,42,140,183,184,185,186],"writing skills","how","teach","write skill","write","claude code skills","files","how to","trigger",{"skillNo":188,"name":189,"nameZh":6,"description":190,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":191,"categories":192,"keywords":195,"publishedAt":44},"01M70P0SJFR4YVJQBGMHKGSKXT","writing-rules","How to write .claude\u002Frules\u002F files that Claude actually follows. Use when creating, improving, or reviewing project rules.","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fxiaolai\u002Fnlpm\u002Fskills\u002Fnlpm\u002Fwriting-rules\u002FSKILL.md",[193,194],{"categoryNo":81,"categoryName":82,"taxonomyType":83,"taxonomyTypeDesc":84},{"categoryNo":128,"categoryName":129,"taxonomyType":21,"taxonomyTypeDesc":22},[196,91,197,43,198,184,42,179,182,140,185],"Rules","writing rules","project rules"]