A modern Python project template with CI/CD ready for production.
You need uv. Nothing else.
uvx copier copy gh:leynier/python-template my-projectAnswer the prompts and you get a working project: dependencies installed, git initialised, tests passing.
To pull later improvements to this template into a project you already generated:
cd my-project
uvx copier updateThat last command is the reason this template uses Copier instead of Cookiecutter — Cookiecutter has no way to update a project after generating it.
One prompt, project_type, replaces what used to be three separate branches:
project_type |
What it generates |
|---|---|
library |
An importable package |
cli |
A command line app built with Typer |
api |
A web API built with FastAPI |
- uv for dependencies, with a committed
uv.lock, PEP 621 metadata and PEP 735 dependency groups. - Ruff for linting and formatting — one tool in place of flake8, black, isort and pyupgrade.
- ty for type checking.
- deptry for undeclared and unused dependencies.
- pre-commit wiring all of the above into git hooks.
src/layout with apy.typedmarker.
- Test matrix across Linux, macOS and Windows × every supported Python version.
- Least-privilege
permissions:on every workflow, concurrency groups, and actions pinned to full commit SHAs. - PyPI publishing with Trusted Publishing — OIDC, no API tokens, with Sigstore attestations. The workflow refuses to publish if the git tag does not match the project version.
- CodeQL scanning and zizmor auditing the workflows themselves.
- Dependabot covering
uv,github-actionsand Docker.
Built with Zensical, the successor to Material for
MkDocs from the same team, with mkdocstrings
generating an API reference from your docstrings. Deployed to GitHub Pages via
OIDC on every push to main.
A multi-stage Dockerfile running as a non-root user, a VS Code devcontainer,
and an AGENTS.md so AI coding agents pick up the project conventions.
This template adopts two tools that are not yet 1.0. Both are used in a way that fails soft:
- ty is at
0.0.xand has no plugin system. CI runsty checkwithcontinue-on-error: true, so it reports findings without gating your build. When ty reaches 1.0, drop that line from.github/workflows/ci.yml. - Zensical is at
0.0.xand does not yet have full plugin parity with Material for MkDocs. mkdocstrings is verified to work — the test suite asserts the API reference is really rendered, not passed through — but other plugins may not be. Zensical readsmkdocs.yml, so moving back is cheap.
If you would rather not take those bets, answer use_docs: false and swap
ty for mypy in pyproject.toml.
Generated projects use lowercase filenames (readme.md), except for files that
GitHub or tooling matches by exact name, which stay uppercase: LICENSE,
CONTRIBUTING.md, CODE_OF_CONDUCT.md, SECURITY.md, AGENTS.md,
Dockerfile and .github/ISSUE_TEMPLATE/.
uv sync --all-groups
uv run pytest -m "not slow" # structural tests: what gets rendered
uv run pytest -m slow # generates each variant and runs its toolchain
uv run pytest # everythingThe slow suite is the important one: it generates every project type and runs
uv sync, Ruff, pytest, deptry, ty, uv build and the docs build inside each
generated project. The previous version of this template had no tests at all,
which is how it managed to sit broken for years without anyone noticing.
This project is collaborative and open source under the MIT license. Contributions are super appreciated.