BuildBot

Python by Contrast

Tooling that finally makes sense — uv & virtualenvs

Lesson 2 of 5

What you'll learn

  • Understand why virtual environments exist, contrasted with node_modules
  • Drive a project with uv — init, add, run, sync
  • Map pyproject.toml and uv.lock onto package.json and its lockfile

In Node, npm install drops dependencies into ./node_modules, so isolation is the default — two projects can pin different versions and never meet. Python is the other way around: pip install puts packages into the site-packages of an interpreter, shared by everything that runs on that interpreter. A virtual environment (venv) restores per-project isolation by giving the project its own lightweight interpreter with its own site-packages.

python -m venv .venv          # the classic way: create the env...
source .venv/bin/activate     # ...then activate it, so "python" means this project's

uv, the one-tool answer

Historically you juggled pip, venv, pip-tools, and pyenv. uv (from Astral, the ruff team) replaces the stack with one fast Rust binary that manages the venv for you — you never activate anything:

uv init myapp        # scaffold pyproject.toml (like npm init)
uv add httpx         # add a dep, update uv.lock, sync .venv (like npm install <pkg>)
uv run main.py       # run inside the project's env, no activate step
uv sync              # recreate the env exactly from the lockfile (like npm ci)

pyproject.toml is your package.json

One file declares the project, its Python floor, and its dependencies; uv.lock pins the full resolved tree, exactly like a lockfile in Node.

[project]
name = "myapp"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["httpx>=0.27"]
{
  "name": "myapp",
  "version": "0.1.0",
  "engines": { "node": ">=22" },
  "dependencies": { "undici": "^6.0.0" }
}

Don't pip install into the system Python

Modern macOS and Linux mark their bundled interpreter as externally managed, and a bare pip install will refuse to run — correctly. Every project gets its own environment; with uv that isolation costs you nothing.

The challenge is a JS model of environment resolution: a shared global site-packages versus two per-project venvs holding conflicting pins side by side.

Venv isolation (JS model)

Run it. This models Python package lookup: each venv resolves its own pinned version, which one shared site-packages could never do.

Loading editor…
Knowledge check

Why do Python projects need virtual environments when Node projects don't?

Next: Python's core containers, comprehensions, and the dunder methods that power the whole language.

Saved on this device. Sign in to sync your progress everywhere.