| name | python-project |
| description | Use when creating Python projects, managing dependencies with uv, configuring pyproject.toml, building packages, or publishing to PyPI - covers project initialization, dependency management, and distribution; NOT for testing or performance (plugin:python@dot-claude) |
| allowed-tools | Bash(uv:*), Bash(python:*), Read, Write, Edit |
Python Project Management
Modern Python project setup and dependency management with uv.
Before Writing Code
- Read
references/pythonic-style.mdfor style conventions - Check Python version:
pyproject.toml→.python-version→.claude/python-version - If unknown, ask user once and store in
.claude/python-version
Reference Files
| Topic | When to Load | File |
|---|---|---|
| Pythonic style, conventions | Before generating code | ../references/pythonic-style.md |
| Version-specific features | When adapting to Python version | ../references/version-features.md |
| GitHub Actions, Docker, monorepo | CI/CD and advanced workflows | references/ci-cd-workflows.md |
| Full pyproject.toml templates | Complete configuration examples | references/pyproject-templates.md |
Quick Start
# New project
uv init my-project && cd my-project
uv python pin 3.12
uv add fastapi pydantic
uv add --dev pytest ruff mypy
# Existing project
uv sync # Install from pyproject.toml
uv sync --all-extras # Include optional deps
Project Structure
Source Layout (Recommended)
my-package/
├── pyproject.toml
├── README.md
├── src/
│ └── my_package/
│ ├── __init__.py
│ ├── core.py
│ └── py.typed
├── tests/
│ └── test_core.py
└── .python-version
Why src/ layout: The src/ layout prevents accidental imports from the source tree during
testing. Without it, import my_package might resolve to the local directory instead of the
installed package, masking missing __init__.py files or build configuration errors.
Minimal pyproject.toml
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
version = "1.0.0"
requires-python = ">=3.10"
dependencies = ["requests>=2.28"]
[project.optional-dependencies]
dev = ["pytest>=7.0", "ruff>=0.1", "mypy>=1.0"]
[tool.setuptools.packages.find]
where = ["src"]
[tool.ruff]
line-length = 100
target-version = "py310"
[tool.ruff.lint]
select = ["E", "F", "I", "UP"]
Dependency Management
Adding Packages
uv add requests # Add to dependencies
uv add "django>=4.0,<5.0" # With version constraint
uv add --dev pytest ruff # Development dependencies
uv add --optional docs sphinx # Optional group
uv add -e ./local-package # Editable local
Updating Packages
uv add --upgrade requests # Upgrade specific
uv sync --upgrade # Upgrade all
uv tree --outdated # Show outdatable
Locking
uv lock # Generate uv.lock
uv lock --upgrade # Regenerate with latest
uv sync --frozen # Install exact versions (CI)
Python Version Management
uv python install 3.12 # Install Python
uv python pin 3.12 # Create .python-version
uv python list # List installed
Running Code
uv run python app.py # Run script
uv run pytest # Run tests
uv run ruff check . # Run linter
uv run --python 3.11 script.py # Specific version
CLI Entry Points
With Click
# src/my_package/cli.py
import click
@click.group()
@click.version_option()
def cli():
"""My CLI tool."""
@cli.command()
@click.argument("name")
def greet(name: str):
click.echo(f"Hello, {name}!")
def main():
cli()
# pyproject.toml
[project.scripts]
my-tool = "my_package.cli:main"
uv sync && uv run my-tool greet World
Building and Publishing
# Build
uv build # Creates dist/*.whl and dist/*.tar.gz
# Test on TestPyPI first
uv publish --repository testpypi
# Publish to PyPI
uv publish
API Token Setup
# ~/.pypirc
[pypi]
username = __token__
password = pypi-...your-token...
Publishing Checklist
Before publishing:
- Tests passing (
uv run pytest) - Version updated in pyproject.toml
- CHANGELOG updated
- Build succeeds (
uv build) - Install works in clean venv
- Tested on TestPyPI first
Common Issues
# Wrong Python version
uv python pin 3.12 && uv venv --python 3.12
# Dependency conflict
uv lock --verbose
# Cache issues
uv cache clean
# Lockfile out of sync
uv lock --upgrade
Workflow Integration
| Task | Skill |
|---|---|
| Writing tests | python:python-testing |
| Profiling, async | python:python-performance |
| Before claiming done | core:verification |
Best Practices
- Use
src/layout for libraries - Pin Python version with
.python-version - Commit
uv.lockfor reproducibility - Use
uv runinstead of manual activation - Test installation in clean venv before publishing
- Use TestPyPI before real PyPI
- Automate publishing with GitHub Actions
- Keep dependencies minimal
- Use optional groups for dev/docs deps
- Run
uv sync --frozenin CI