# Python Packaging

> Python project structure patterns — pyproject.toml for services and internal tools, source vs flat layout, CLI entry points with Click/argparse, dynamic versioning, and editable installs. Use when structuring a new Python project or building internal CLI tools.

- Skill: `kumaran-is/python-packaging` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add kumaran-is/python-packaging`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kumaran-is/python-packaging/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: kumaran-is (https://skillmd.com/u/kumaran-is)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kumaran-is/python-packaging

---


## Iron Law

**USE SOURCE LAYOUT (`src/`) FOR ALL SERVICES AND INSTALLABLE TOOLS — flat layout works for scripts but causes import confusion in larger projects and CI environments**

# Python Packaging

Project structure patterns for Python 3.14 services, internal tools, and CLI applications.

## Scope

This skill covers the **workspace-relevant** subset of Python packaging:
- `pyproject.toml` structure for FastAPI services and internal tools
- Source layout vs flat layout decision
- CLI entry points (Click, argparse) for internal tooling
- Dynamic versioning
- Editable installs for development

**Out of scope for this workspace:** PyPI publishing, wheels, namespace packages, C extensions, private package index. The workspace builds services and internal tools, not distributable libraries.

## Layout Decision

```
New project?
│
├── FastAPI service / internal service
│   └── Source layout: src/<package>/ ← default for all services
│
├── Internal CLI tool (deployment scripts, data tools)
│   └── Source layout with [project.scripts] entry point
│
└── Quick one-off script
    └── Flat layout (single .py file or simple directory)
```

## Reference File

Load `resources/implementation-playbook.md` for:
- Source layout pattern (Pattern 1) — full directory structure with __init__.py placement
- Flat layout pattern (Pattern 2) — when appropriate
- Full pyproject.toml template (Pattern 4) — with all modern metadata fields
- Dynamic versioning with `setuptools-scm` (Pattern 5)
- CLI with Click (Pattern 6) — entry points, commands, options
- CLI with argparse (Pattern 7) — subcommands, arguments
- Editable install (Pattern 16) — `uv pip install -e .` for development

## Key pyproject.toml Sections

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

[project]
name = "my-service"
version = "0.1.0"
requires-python = ">=3.14"
dependencies = [
    "fastapi>=0.135.2",
    "pydantic>=2.0.0",
]

[project.scripts]
my-cli = "my_package.cli:main"  # CLI entry point

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

## CLI Entry Point Pattern

```python
# src/my_tool/cli.py
import click

@click.group()
def main():
    """Internal deployment tool."""
    pass

@main.command()
@click.argument("environment")
@click.option("--dry-run", is_flag=True)
def deploy(environment: str, dry_run: bool):
    """Deploy to environment."""
    click.echo(f"Deploying to {environment} (dry_run={dry_run})")

if __name__ == "__main__":
    main()
```

Install and run: `uv pip install -e .` then `my-cli deploy staging --dry-run`

