Why These Tools?¶
This page explains the rationale behind the tools and patterns chosen for the copier-py template.
uv for dependency management¶
uv replaces pip, pip-tools, and virtualenv in a single tool written in Rust. It resolves and installs dependencies significantly faster than pip, supports lockfiles natively, and handles Python version management. The template uses uv as the primary package manager because it simplifies the developer experience — one tool handles what previously required three or four.
ruff for linting and formatting¶
ruff consolidates flake8, isort, pyflakes, pycodestyle, and black into a single Rust-based tool. It runs orders of magnitude faster than the Python-based tools it replaces and enforces consistent style without requiring developers to configure multiple tools separately. The template uses ruff for linting, formatting, and import sorting.
tox for test automation¶
tox provides reproducible test environments across multiple Python versions. While uv handles dependency management, tox manages the matrix of Python versions and test configurations (unit tests, coverage, linting, docs). This separation keeps pyproject.toml focused on project metadata and lets tox orchestrate the full test and quality pipeline.
pytest with hypothesis and mutmut¶
pytest is the standard Python testing framework. The template adds hypothesis for property-based testing — it generates test cases automatically to find edge cases that example-based tests miss. mutmut provides mutation testing, which verifies that your tests actually catch bugs by introducing small changes to source code and checking that tests fail. Together, these tools provide confidence beyond line coverage.
The template also includes pytest-xdist for parallel test execution and pytest-randomly to randomize test order, exposing hidden dependencies between tests.
mypy for type checking¶
mypy catches type errors before runtime. Python’s type system is optional, but mypy makes it useful — it finds bugs that tests might miss, like passing a string where an integer is expected. The template configures mypy in strict mode to maximize the value of type annotations.
sphinx with MyST parser¶
Sphinx is the established documentation tool for Python projects. The template adds MyST parser to support writing documentation in Markdown alongside reStructuredText. This lowers the barrier for contributors who are more familiar with Markdown while retaining Sphinx’s powerful cross-referencing, autodoc, and theme ecosystem.
The template offers 17 Sphinx themes. Furo is the default because it provides a clean, modern design with dark mode support, good mobile responsiveness, and minimal configuration.
pre-commit for automated checks¶
pre-commit runs checks before each commit, catching issues early in the development cycle. The template configures hooks for:
ruff — linting and formatting
mypy — type checking
detect-secrets — prevents accidental credential commits
commitlint — enforces Conventional Commits for consistent, parseable commit messages
bashate — lints shell scripts
typos — catches spelling mistakes in code and docs
deptry — detects unused, missing, or transitive dependencies
Running these checks locally means developers get fast feedback without waiting for CI.
src layout¶
The template uses a src layout where package code lives under src/. This prevents accidental imports of the development version during testing — when you run pytest, Python imports from the installed package, not from the local directory. This catches packaging issues early that a flat layout would hide.
Dockerfile with multi-stage build¶
The generated Dockerfile uses a multi-stage build with separate stages for development, testing, and production. This keeps the production image small (no dev dependencies) while providing full tooling in development. The final stage runs as a non-root user for security.
GitHub Actions workflow design¶
The template generates separate workflows for distinct concerns rather than a single monolithic workflow:
CI handles testing and quality checks on every push
Publish handles package distribution on releases
Security workflows (CodeQL, trufflehog) run on their own schedules
This separation means a failing security scan doesn’t block CI, and CI failures don’t prevent documentation builds. Each workflow uses GitHub environments for deployment protection where appropriate.