These are my defaults for a new project.
- Toolchain: Use
uvfor dependencies, interpreters, tools, scripts, and builds. - Formatting & Linting: Use
rufffor both linting and formatting. - Data Modeling: Use
Pydanticat I/O boundaries; nativedataclassesorattrsinternally. - Configuration: Use
pydantic-settingsfor configuration, validated strictly at startup. - Project Metadata: Everything configured in
pyproject.toml; dev dependencies managed via standard[dependency-groups]. - Project Structure: Use
src/layout, commit your lockfile, and enforceuv lock --checkin CI. - Type Checking: Run a type checker in CI, strict on new code (
pyright, orpyreflyon large codebases). - Logging: Structured logging configured once at the application entry point—never inside reusable libraries.
- Concurrency: Use
TaskGroupandasyncio.timeoutfor async I/O; processes for CPU-bound tasks. - Testing: Use
pytestwith fixtures and parametrization;Hypothesisfor property-based invariants;Testcontainersinstead of database mocks. - CLIs & Tooling: Use
TyperorCycloptsfor production CLIs;# /// scriptinline metadata for single-file tools. - Performance: Profile before optimizing using
py-spy,scalene, ormemray. - Security & CI/CD: Pin GitHub Actions to commit SHAs; publish packages to PyPI via Trusted Publishers (OIDC).