| name | python-development |
| description | Python development โ use when the user works with .py files, pyproject.toml, uv, ruff, mypy, pytest, async/await, MicroPython, CLI tools, or PyPI publishing. Covers modern tooling, best practices, library architecture, functional patterns, and production workflows. NOT for TypeScript or JavaScript development (use typescript-development), NOT for React component patterns (use react-development). |
Python Development - Comprehensive Skill
Expert guidance for modern Python development (Python 3.11-3.14+), covering everything from simple scripts to production-grade systems, library architecture, and embedded development.
When to Use This Skill
Activate this skill when:
- Working with
.py files, pyproject.toml, or uv.lock
- Writing, testing, or reviewing Python code
- Managing Python dependencies or virtual environments
- Using commands like
uv, pytest, ruff, or mypy
- Building CLI applications with Typer/Click
- Designing Python libraries or packages
- Working with async/await patterns
- Developing for embedded systems (MicroPython, RP2350)
- Setting up CI/CD for Python projects
- Publishing packages to PyPI
When NOT to Use This Skill
- TypeScript or JavaScript development โ use
typescript-development
- React component patterns or hooks โ use
react-development
- TDD methodology (Red-Green-Refactor cycle) โ use
test-driven-development (this skill covers pytest patterns but not the full TDD workflow)
- Django/Flask framework-specific patterns โ this skill covers Python fundamentals; dedicated framework plugins provide deeper coverage
Decision Trees
Tier Selection
What are you building?
โ
โโ Single-file script, one-off utility, quick data processing
โ โโ MINIMAL tier: PEP 723 inline metadata, no project scaffolding
โ
โโ Multi-file project, team development, anything with tests
โ โโ STANDARD tier (default): src/ layout + uv + ruff + mypy + pytest
โ
โโ PyPI package, production system requiring CI/CD
โโ FULL tier: Complete tooling + bandit + CI/CD + release workflow
Default to Standard โ it covers most use cases.
Async vs Sync Decision
Does the task involve I/O-bound operations (HTTP, DB, file, network)?
โ
โโ No โ Use synchronous code (simpler, easier to debug)
โ
โโ Yes โ Are operations concurrent (many requests at once)?
โ
โโ No โ Simple async/await with httpx.AsyncClient
โ
โโ Yes โ asyncio.Semaphore per resource + httpx.AsyncClient
with connection pooling + retry logic
Protocol vs ABC Decision
Do you need structural subtyping (duck typing with type safety)?
โ
โโ Yes โ Protocol
โ โโ Enables dependency injection, avoids inheritance coupling
โ
โโ No โ Do you need runtime type checking or enforced method implementation?
โ
โโ Yes โ ABC with @abstractmethod
โ
โโ No โ Protocol (lighter weight, preferred default)
Library vs Application Architecture Decision
Will this code be imported by other projects?
โ
โโ Yes โ Library architecture:
โ - Protocol-based API surface
โ - py.typed marker
โ - Minimal public exports (__all__)
โ - Stable deprecation policy
โ - pyproject.toml with [project.optional-dependencies]
โ
โโ No โ Application architecture:
- Direct implementation (no Protocol overhead)
- Simpler project structure
- pyproject.toml with [project.scripts]
Quick Start
Standard Project Setup
curl -LsSf https://astral.sh/uv/install.sh | sh
uv init my-project
cd my-project
uv add requests pydantic httpx
uv add --dev pytest pytest-cov ruff mypy
uv run ruff check .
uv run ruff format .
uv run mypy .
uv run pytest --cov
Core Principles
- Use uv for everything: 10-100x faster than pip, all-in-one tool
- Type hints everywhere: Use type annotations for all functions and classes
- Ruff for quality: Single tool for linting and formatting (replaces Black, flake8, isort)
- Test with pytest: Comprehensive tests with fixtures and parametrization
- Lock dependencies: Always maintain
uv.lock for reproducible builds
- PEP 723 for scripts: Use inline script metadata for single-file scripts
Modern Python Toolchain
Package Management: uv
Use current tool documentation when exact flags matter; uv, ruff, mypy, and pytest move quickly. The defaults below are stable project-starting patterns, not a substitute for checking release notes during migrations.
uv init my-project && cd my-project
uv add requests pandas numpy
uv add --dev pytest ruff mypy
uv sync
uv lock --upgrade
uv run python script.py
uv run pytest
Code Quality: ruff
ruff check .
ruff check --fix .
ruff format .
Type Checking: mypy
mypy .
mypy --strict .
Project Structure
myproject/
โโโ src/
โ โโโ myproject/
โ โโโ __init__.py
โ โโโ main.py
โ โโโ utils.py
โโโ tests/
โ โโโ __init__.py
โ โโโ conftest.py
โ โโโ test_main.py
โ โโโ test_utils.py
โโโ docs/
โโโ .gitignore
โโโ .python-version
โโโ pyproject.toml
โโโ uv.lock
โโโ README.md
pyproject.toml Configuration
[project]
name = "myproject"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = ["requests>=2.31.0"]
[project.optional-dependencies]
dev = ["pytest>=8.0.0", "ruff>=0.8.0", "mypy>=1.13.0"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "B", "Q"]
[tool.mypy]
python_version = "3.11"
strict = true
[tool.pytest.ini_options]
testpaths = ["tests"]
Anti-Patterns to Avoid
| Anti-Pattern | Problem | Solution |
|---|
Mutable default args def f(lst=[]) | Default value is shared across all calls; mutations persist unexpectedly | def f(lst: list | None = None) then lst = lst or [] inside |
requests.get in async | Blocks the event loop; all concurrent tasks stall | httpx.AsyncClient for async HTTP; requests only in sync code |
| Classes for data bags | Boilerplate __init__, mutable by default, no equality | @dataclass(frozen=True) for immutable value objects, or NamedTuple for lightweight records |
| Deep inheritance hierarchies | Tight coupling, fragile base class, hard to test | Protocol + composition; define behavior by what it does, not what it is |
| Mutating function args | Side effects make code unpredictable and hard to test | Return new values; use frozen dataclasses; prefer pure functions |
try/except Exception | Swallows all errors including KeyboardInterrupt, SystemExit | Catch specific types: except (ValueError, KeyError) |
| Blocking in async | time.sleep(), requests.get(), subprocess.run() freeze the event loop | await asyncio.to_thread(fn) or asyncio.sleep() for non-blocking alternatives |
from module import * | Pollutes namespace, makes dependencies invisible, breaks linters | Explicit imports: from module import ClassA, func_b |
Bare except: | Catches everything including SystemExit/KeyboardInterrupt; hides bugs | except (SpecificError, AnotherError): |
Using List[str] etc. | Legacy typing; deprecated since Python 3.9 | Use modern syntax: list[str], dict[str, int], tuple[int, ...] |
| Ignoring mypy errors | Type errors at compile time become runtime crashes | Fix the type; use # type: ignore[specific-code] with comment explaining why |
| Testing with production URLs | Tests hit real APIs, flaky, slow, depend on network | Mock HTTP calls with pytest-httpx or respx; test against fixtures |
Quality Gates
Every Python task must pass:
- Format-first:
uv run ruff format .
- Linting:
uv run ruff check .
- Type checking:
uv run mypy .
- Tests:
uv run pytest (>80% coverage)
- Modern patterns: No legacy typing (use
list[str] not List[str])
For critical code (payments, auth, security):
- Coverage >95%
- Security scan:
uv run bandit -r src/
See Extended Patterns for detailed code examples, testing patterns, async patterns, itertools/functools usage, library architecture, workflow routing, and complete reference file listings.
Official Documentation