Python Project Setup (2026 Edition)

A few years back I linked to Alex Mitelman’s Python best practices post as my go-to reference for new project setup. The tooling has moved on quite a bit since then, so here’s my updated take.

The new stack is three tools, all from Astral: uv, ruff, and ty. They’re fast, they integrate cleanly with each other, and they collapse a lot of the old toolchain into a much simpler setup.

uv — dependency management, environments, everything

uv replaces pyenv + pip + venv in one shot. It handles Python version management, virtual environments, dependency locking, and running commands in the right environment.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# install uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# start a new project
uv init my-project
cd my-project

# add dependencies
uv add requests
uv add --dev ruff ty pytest

The uv run command is the other key habit to pick up — it activates the right environment automatically so you don’t have to think about it:

1
2
uv run python my_script.py
uv run pytest

ruff — linting and formatting

ruff replaces flake8, isort, black, and a handful of other linters, and it does it fast. The --fix flag handles most issues automatically.

1
2
uv run ruff check --fix .
uv run ruff format .

Configure it in pyproject.toml:

1
2
3
4
5
6
[tool.ruff]
line-length = 88
target-version = "py312"

[tool.ruff.lint]
select = ["E", "F", "I"]  # pycodestyle, pyflakes, isort

ty — type checking

ty is Astral’s new type checker. It’s still early but it’s fast and editor-friendly. Drop it into the same uv run workflow:

1
uv run ty check
1
2
[tool.ty]
# pyproject.toml config here when needed

The short version

1
2
3
uv init my-project && cd my-project
uv add --dev ruff ty pytest
uv run ruff check --fix . && uv run ruff format . && uv run ty check

Everything lives in pyproject.toml, no separate config files needed. It’s a much cleaner setup than what I was doing a few years ago.


comments powered by Disqus