# Modern Python Tooling Checklist


Use this checklist when you start a Python project or standardize a team template. It covers the defaults most projects need and links to deeper handbook pages when a choice needs more context.

## Set the foundation

- [ ] [Install Python with uv](https://pydevtools.com/handbook/how-to/how-to-install-python-with-uv.md) unless your team already standardizes on another interpreter manager. See the [uv](https://pydevtools.com/handbook/reference/uv.md) reference for the full command set.
- [ ] Create the project with [uv init](https://pydevtools.com/handbook/tutorial/create-your-first-python-project.md) and pick the right [uv init project type](https://pydevtools.com/handbook/explanation/understanding-uv-init-project-types.md).
- [ ] Use a [`src` layout over a flat layout](https://pydevtools.com/handbook/explanation/src-layout-vs-flat-layout.md) for packages, so tests run against the installed code.
- [ ] Use [`pyproject.toml`](https://pydevtools.com/handbook/reference/pyproject.toml.md) for project metadata and dependencies.
- [ ] Commit [`uv.lock`](https://pydevtools.com/handbook/how-to/how-to-use-a-uv-lockfile-for-reproducible-python-environments.md) for applications, services, notebooks, and team projects that need reproducible installs. See [what a lockfile is](https://pydevtools.com/handbook/explanation/what-is-a-lock-file.md) if you're deciding whether to commit one.
- [ ] Keep `.venv/` out of version control. It's the project's [virtual environment](https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment.md), rebuilt from the lockfile.

## Manage dependencies

- [ ] Add runtime dependencies with `uv add`.
- [ ] Add development dependencies with `uv add --dev`.
- [ ] Use [dependency groups](https://pydevtools.com/handbook/explanation/understanding-dependency-groups-in-uv.md) for optional development workflows such as docs, linting, or tests.
- [ ] Prefer [`pyproject.toml` over `requirements.txt`](https://pydevtools.com/handbook/explanation/pyproject-vs-requirements.md) for new projects.
- [ ] Use [private package index settings](https://pydevtools.com/handbook/how-to/how-to-use-private-package-indexes-with-uv.md) only when the project needs them.

## Format and lint

- [ ] Use [Ruff](https://pydevtools.com/handbook/reference/ruff.md) for formatting and linting.
- [ ] Start with the recommended Ruff defaults before adding project-specific rules.
- [ ] [Sort imports with Ruff](https://pydevtools.com/handbook/how-to/how-to-sort-python-imports-with-ruff.md) instead of maintaining a separate isort setup.
- [ ] [Replace Black, isort, flake8, and pyupgrade with Ruff](https://pydevtools.com/handbook/how-to/how-to-replace-black-isort-flake8-pyupgrade-with-ruff.md) so one tool covers formatting and linting.
- [ ] Run Ruff locally and in CI.

## Run tests

- [ ] Use [pytest](https://pydevtools.com/handbook/reference/pytest.md) as the default test runner.
- [ ] Run tests through uv: `uv run pytest`.
- [ ] [Measure coverage with pytest-cov](https://pydevtools.com/handbook/how-to/how-to-measure-code-coverage-with-pytest-cov.md) once the project has enough tests for the number to mean something.
- [ ] [Test against multiple Python versions](https://pydevtools.com/handbook/how-to/how-to-test-against-multiple-python-versions-using-uv.md) with a CI matrix when you support more than one.

## Check types

- [ ] Type-check with [Pyrefly](https://pydevtools.com/handbook/reference/pyrefly.md) for the best current combination of speed and inference. Reach for [mypy](https://pydevtools.com/handbook/reference/mypy.md), [Pyright](https://pydevtools.com/handbook/reference/pyright.md), or [ty](https://pydevtools.com/handbook/reference/ty.md) if your team already standardizes on one; [compare the trade-offs](https://pydevtools.com/handbook/explanation/how-do-mypy-pyright-and-ty-compare.md) before you switch.
- [ ] Run the type checker in CI once the project has enough annotations to make the output useful.
- [ ] [Adopt type checking gradually](https://pydevtools.com/handbook/how-to/how-to-gradually-adopt-type-checking-in-an-existing-python-project.md) for existing codebases.

## Automate checks

- [ ] Add [pre-commit hooks](https://pydevtools.com/handbook/how-to/how-to-set-up-pre-commit-hooks-for-a-python-project.md) for formatting, linting, and cheap checks.
- [ ] Use [GitHub Actions with uv](https://pydevtools.com/handbook/tutorial/setting-up-github-actions-with-uv.md) for CI.
- [ ] [Cache uv downloads in CI](https://pydevtools.com/handbook/how-to/how-to-cache-uvx-tools-in-github-actions.md) to speed up runs.
- [ ] [Scan dependencies for vulnerabilities](https://pydevtools.com/handbook/how-to/how-to-scan-python-dependencies-for-vulnerabilities.md) in CI so a bad transitive dependency fails the build.
- [ ] Keep generated artifacts out of commits unless they are part of the release output.

## Publish packages

- [ ] Use [trusted publishing](https://pydevtools.com/handbook/how-to/how-to-publish-to-pypi-with-trusted-publishing.md) for PyPI releases, and read [why trusted publishing beats API tokens](https://pydevtools.com/handbook/explanation/why-use-trusted-publishing-for-pypi.md).
- [ ] [Build wheels in CI](https://pydevtools.com/handbook/how-to/how-to-build-multi-platform-wheels-with-cibuildwheel.md) for packages that other projects install; see [what a wheel is](https://pydevtools.com/handbook/reference/wheel.md).
- [ ] [Publish to TestPyPI](https://pydevtools.com/handbook/how-to/how-to-publish-to-testpypi-with-uv.md) before publishing a new release workflow to PyPI.
- [ ] Check the built wheel before release with [twine](https://pydevtools.com/handbook/reference/twine.md). The source tree can hide packaging mistakes.

## Set team defaults

- [ ] Document the supported Python versions with a [`.python-version` file](https://pydevtools.com/handbook/explanation/what-is-a-python-version-file.md).
- [ ] Document the project commands: install, test, lint, format, type check, build, publish.
- [ ] Keep tool choices boring unless the project has a concrete reason to differ.
- [ ] Revisit the template when Python, uv, Ruff, or the team's type checker changes in a way that affects defaults.

{{< newsletter >}}
