Note on tooling: Reproducible, robust, and yet simple development setup for Python. Developing in VSCode Dev Containers.
- Clone or Use Template:
# Clone the repo
git clone <this-repo> <your-project-name>
cd <your-project-name>
# Or use GitHub's "Use this template" button
# Or use GitHub CLI: gh repo create <your-project-name> --template <this-repo>
# just ensure to `git init`, otherwise pre-commit fails- Configure Environment
# Copy sample environment file
cp .env.sample .env
# Edit .env if needed (e.g., set DEVELOPMENT=False)- Replace Placeholders
- Search and replace
my-projectindocker-compose.ymlandpython-project-templateinpyproject.tomlwith your project name - Update
name,versioninpyproject.toml - Update the year and copyright holder in
LICENSE - update this
README.mdfor your project.
- Open in VS Code & Dev Container
# Open project folder in VS Code
code .
# When prompted, or using the Command Palette (Ctrl+Shift+P), select:
# > Dev Containers: Open Folder in Container (or similar)- Develop
- Add dependencies:
uv add <package-name>(runs inside the container) pre-commit(linting, formatting, testing) runs automatically on commit
This template uses VSCode's Dev Containers (devcontainers) to provide a consistent, isolated development environment. The setup leverages Docker Compose with an extension pattern:
docker-compose.ymldefines the base service configuration.devcontainer/docker-compose.extend.ymlextends the base configuration specifically for development- The extension mounts your local project directory to
/appin the container, enabling real-time file synchronization - This allows you to work on code locally in VSCode while running it in a container environment
This approach ensures that all developers work with identical dependencies and configurations, regardless of their local setup, while maintaining the ability to edit files directly on the host system.
- Simplicity first: keep functions small, clear, and free of bloat.
- Clarity > cleverness: readable names and explicit logic beat tricks.
- YAGNI: implement only today’s requirements; postpone “nice-to-haves.”
- Single responsibility: one purpose per module, class, and function.
- Composition over inheritance: favour plain objects; if an interface is needed, use an
ABC, not aProtocol. - Pythonic, not painful: embrace idioms without overcomplicating code.
- Fail fast & loud: validate inputs early and raise clear errors.
- Typed & documented: PEP 484 type hints + Google-style docstrings.
- Testable by design: write pytest-ready, side-effect-free units.
- Immutable by default: fewer surprises, safer concurrency.
- Dependency discipline: keep
pyproject.tomllean and current. - Secure defaults: load secrets from env vars; least-privilege access.
- Measure before tuning: profile first, optimise real hotspots only.
- Continuous refactor: pay technical-debt in small, frequent steps.
uvfor dependency management- VS Code devcontainers with
docker compose-file - Multi-stage build with
builder, also used for development, andproduction - debugging:
debugpy - testing:
pytest - linting & formatting:
ruff - type-checking:
mypy - environment variables:
python-dotenv pre-commithooks
- write commits following The seven rules of a great commit message: *What- and *why- in imperative mood instead of how
- follow 12-factor principles
- agree on git workflow, for example trunk-based development
- Use multi-stage builds to structure docker images and only include the needed runtime dependencies for smaller image size and faster builds
- Follow a styleguide like Google Python Style Guide
- Tag releases with SemVer:2.0.0 or CalVer
- For a changelog, adapt principles of common-changelog, written by humans for humans, a clean git history as foundation
- release with tags and changelog using
git-release