Install Python and the modern toolchain (uv, ruff, mypy)
Bootstrap a machine with uv, ruff, and mypy, and understand what each tool owns.
Why this matters
In 2026, "I'm a Python developer" is not enough. You're expected to know uv for dependency management, ruff for linting/formatting, mypy / pyright for type checking, and pre-commit to enforce all of it. Teams that don't use this stack waste hours per week on environment bugs and bikeshedding style. This lesson installs the stack once so the rest of the course runs frictionlessly.
Learning objectives
- Install a modern Python (3.12+) on Windows / macOS / Linux.
- Use
uvfor everything (install, sync, run). - Configure
ruff,mypy,pre-commitin a fresh project. - Pick an editor (VS Code / Cursor / PyCharm) and configure it.
- Know the difference between user, system, and project Pythons.
1. Install Python via uv
The old advice ("install Python from python.org") is fine but increasingly replaced by tools like uv (Astral) which manage Pythons for you โ like Node's nvm or Rust's rustup.
Install uv
| OS | Command |
|---|---|
| Windows (winget) | winget install astral-sh.uv |
| Windows (PowerShell) | irm https://astral.sh/uv/install.ps1 | iex |
| macOS / Linux | curl -LsSf https://astral.sh/uv/install.sh | sh |
Verify:
uv --versionInstall Python with uv
uv python install 3.12 3.13
uv python listuv keeps the binaries in ~/.local/share/uv/python/ (Linux/macOS) or %LOCALAPPDATA%\uv\python\ (Windows). No PATH wrangling.
To "use" a Python version in a project, you don't change PATH; you run uv run python ... and uv selects the right one based on the project's .python-version file.
2. Three kinds of Python on your machine
This trips up everyone:
| Type | Where | When used |
|---|---|---|
| System Python | /usr/bin/python3, ships with OS | OS tools depend on it; never touch |
| User Python | installed by you with uv / pyenv / installer | Default REPL, scripts |
| Project Python | virtual environment inside the project | What uv sync activates |
The cardinal rule: one venv per project. Don't install third-party packages into your user or system Python.
uv makes this automatic: uv add httpx creates the venv if needed and installs into it.
3. Bootstrap your "lab" project
uv init py-lab --python 3.12
cd py-labThis creates:
py-lab/
โโโ .python-version # "3.12"
โโโ pyproject.toml # project metadata + deps
โโโ README.md
โโโ hello.py
โโโ .gitignoreAdd some packages:
uv add ruff mypy pytest pytest-cov hypothesis ipython
uv add --dev pre-commituv add updates pyproject.toml, locks resolved versions in uv.lock, and installs into .venv/.
Run anything in the env:
uv run python hello.py
uv run pytest
uv run ruff check .You almost never need to activate the venv explicitly with uv โ uv run handles it.
4. Configure ruff
ruff (Astral) replaces flake8, isort, black, pylint, pyupgrade โ one tool, written in Rust, ~100ร faster.
Add to pyproject.toml:
[tool.ruff]
line-length = 100
target-version = "py312"
[tool.ruff.lint]
# Pick a sensible default set; you can expand later
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort (import order)
"B", # flake8-bugbear
"UP", # pyupgrade (modernise syntax)
"C4", # comprehensions
"SIM", # simplify
"PTH", # use pathlib
"RUF", # ruff-specific
]
ignore = [
"E501", # line too long (use formatter)
]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"Use:
uv run ruff check . # lint
uv run ruff check . --fix # auto-fix
uv run ruff format . # format (replaces black)5. Configure mypy
Static type checker. Catches a class of bugs before runtime.
[tool.mypy]
python_version = "3.12"
strict = true
warn_unused_ignores = true
warn_return_any = true
plugins = ["pydantic.mypy"]
# Per-module overrides (e.g., for libraries without type stubs)
[[tool.mypy.overrides]]
module = ["some_untyped_lib.*"]
ignore_missing_imports = truestrict = true is the right default. It will complain at first โ that's working as intended. We cover typing in depth in Phase 3.5.
Run:
uv run mypy src/For a faster alternative, try pyright (Microsoft): uv add --dev pyright. Both are excellent; pyright is what most VS Code/Cursor extensions use.
6. Configure pre-commit
Run lint/format/type-check automatically on every git commit.
.pre-commit-config.yaml:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.0 # pin a version; bump periodically
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.13.0
hooks:
- id: mypy
additional_dependencies: [pydantic]
args: [--strict]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
args: [--maxkb=500]Install:
uv run pre-commit installNow every git commit runs the hooks. Bad commits get auto-fixed or blocked. The team's style stays consistent without anyone arguing about it.
7. Editor setup
VS Code / Cursor (recommended in 2026)
Install these extensions:
- Python (Microsoft)
- Pylance (Microsoft, includes pyright)
- Ruff (Astral)
- Jupyter (Microsoft) โ for notebooks
Workspace settings (.vscode/settings.json):
{
"python.defaultInterpreterPath": ".venv/bin/python",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.fixAll": "explicit"
},
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff"
},
"python.testing.pytestEnabled": true,
"python.analysis.typeCheckingMode": "strict"
}On Windows, use .venv\Scripts\python.exe for defaultInterpreterPath.
PyCharm
File โ Settings โ Project โ Python Interpreter โ point to .venv. Install the Ruff plugin.
Terminal / Vim / Neovim
Use pyright, ruff-lsp, and your usual setup. The CLI tools work identically.
8. Reference pyproject.toml
A complete starter โ copy into any new project:
[project]
name = "py-lab"
version = "0.1.0"
description = "Sandbox for the Python course"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"httpx>=0.27",
"pydantic>=2.7",
]
[project.optional-dependencies]
dev = [
"ruff>=0.7",
"mypy>=1.13",
"pytest>=8",
"pytest-cov>=5",
"hypothesis>=6",
"pre-commit>=3",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.ruff]
line-length = 100
target-version = "py312"
[tool.ruff.lint]
select = ["E", "W", "F", "I", "B", "UP", "C4", "SIM", "PTH", "RUF"]
ignore = ["E501"]
[tool.ruff.format]
quote-style = "double"
[tool.mypy]
python_version = "3.12"
strict = true
[tool.pytest.ini_options]
addopts = "-ra -q --cov=src"
testpaths = ["tests"]9. The "is my environment healthy?" command
Save as scripts/check.ps1 (or check.sh):
uv sync
uv run ruff check .
uv run ruff format --check .
uv run mypy src/
uv run pytestRun before every push. Same script runs in CI (Phase 6 + 9).
10. Common mistakes to avoid
pip install ...outside a venv โ pollutes user Python. Alwaysuv add.- Multiple Python versions on PATH โ run
python --versionandwhere python(Windows) /which python(macOS/Linux). Should be one. - Forgetting
uv syncafter pulling teammate's commits โ "but it works on my machine." - Committing
.venv/to git. Add to.gitignore(uv initdoes this). - Hand-editing
uv.lock. Never. Letuvmanage it.
Hands-on lab (1 hour)
- Install
uvand Python 3.12 viauv python install 3.12. uv init my-first-tool; cd in.- Add
httpx,ruff,mypy,pytest. - Create
src/my_first_tool/main.pythat fetcheshttps://httpbin.org/getand prints the JSON. - Add
ruffandmypyconfig topyproject.tomlfrom this lesson. - Run all four checks (ruff lint, ruff format, mypy, pytest) and fix any errors.
- Initialise git; install
pre-commit; make a commit. - Bonus: push to GitHub and add a GitHub Actions workflow that runs the same checks.
Self-check
- Why use
uvinstead ofpip+venv? - What is the difference between system, user, and project Python?
- What does
ruff formatreplace? - Why use
pre-commit? - What does
pyproject.tomldescribe?
References
uvdocumentation: https://docs.astral.sh/uv/ruffdocumentation: https://docs.astral.sh/ruff/mypydocumentation: https://mypy.readthedocs.io/pyrightdocumentation: https://microsoft.github.io/pyright/- PEP 621 โ
pyproject.tomlproject metadata. - Python Packaging User Guide: https://packaging.python.org/
Sign in to save your progress and earn badges.