uvOne fast tool for Python versions, projects, packages, and virtual environments — reproducible by default.
uv per-user, without admin rightsuv pythonuv init and read its pyproject.tomluv.lockGlobal Python, clashing packages, and “works on my machine”.
pip install pandas into the one shared Pythonpandas 1.5; project B needs pandas 2.2 — only one can winIf you can’t say exactly which package versions produced last quarter’s reserve numbers, you can’t reproduce them for an auditor.
.venv\.venv\.venv\.venv) holding a Python interpreter link plus that project’s packages.venv and rebuild it in secondsHistorically you juggled python -m venv, activate, pip, pip freeze, pyenv… uv replaces the lot.
| Job | Old tool(s) | uv |
|---|---|---|
| Install Python itself | python.org installer, pyenv | uv python install |
| Create environments | venv, virtualenv | automatic |
| Install packages | pip | uv add |
| Pin exact versions | pip-tools, pip freeze | uv.lock |
| Run in the environment | activate + python | uv run |
| Global CLI tools | pipx | uv tool install |
Made by Astral, who also make the ruff linter we’ll use in Module 7.
Per-user, no admin, no installer wizards.
uv on Windowspowershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
powershell-ExecutionPolicy ByPassirm URL| iexInstalls uv.exe to ~\.local\bin and adds that folder to your User PATH (Module 3!). Then: new terminal → uv --version.
irm … | iex runs code from the internet. Only do it for sources you trust — or use winget install --id astral-sh.uv -e instead.
uv python list # available & installed versions
uv python install 3.12 # download a standalone Python
uv python install 3.13 3.11 # several at once
uv python pin 3.12 # this folder uses 3.12
# (writes .python-version)
uv python dir # where they're stored
uv run python --version # check what a project gets
| python.org installer | uv python | |
|---|---|---|
| Wizard | Yes | No |
| Admin rights | Often | Never |
| PATH edits | Checkbox roulette | None needed |
| Multiple versions | Painful | Trivial |
| Remove a version | Control Panel | uv python uninstall |
You rarely need to install Python explicitly — if a project asks for 3.12 and it’s missing, uv downloads it automatically.
uv init, uv add, uv run — and the lock file that makes it reproducible.
PS C:\actuarial_work> uv init lapse_analytics
Initialized project `lapse-analytics`
at `C:\actuarial_work\lapse_analytics`
PS C:\actuarial_work> cd lapse_analytics
PS C:\actuarial_work\lapse_analytics> ls -Force
lapse_analytics\
├── .gitignore files Git should ignore
├── .python-version e.g. 3.12
├── main.py starter script
├── pyproject.toml the project's "passport"
└── README.md describe your project
If Git is installed, uv init also creates a Git repository (.git\). We’ll install Git in Module 5.
[project]
name = "lapse-analytics"
version = "0.1.0"
description = "Lapse experience study"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"numpy>=2.1.3",
"openpyxl>=3.1.5",
"pandas>=2.2.3",
]
[dependency-groups]
dev = [
"jupyterlab>=4.3.4",
]
requires-python: which Pythons are alloweddependencies: what the project needs — with minimum versionsdev group: tools for you, not for the analysis itselfLet uv add / uv remove edit this file for you.
PS C:\actuarial_work\lapse_analytics> uv add pandas numpy openpyxl
Using CPython 3.12.8
Creating virtual environment at: .venv
Resolved 9 packages in 412ms
Prepared 7 packages in 1.93s
Installed 7 packages in 588ms
+ et-xmlfile==2.0.0
+ numpy==2.1.3
+ openpyxl==3.1.5
+ pandas==2.2.3
...
pyproject.toml & write uv.lock.venv\ (created if missing)Version numbers on these slides are illustrative — yours will be whatever is current.
uv run python main.py # run a script
uv run main.py # same thing, shorter
uv run python # interactive Python
uv run python -c "import pandas; print(pandas.__version__)"
uv run checks the environment matches the lock file (fixing it if not), then runs your command inside .venv.
No “activate” step to forget. No accidentally running the wrong Python. The command is the same on every machine.
You can still activate the old way — .venv\Scripts\activate — which needs the execution policy from Module 3. Type deactivate to leave.
pyproject.toml vs. uv.lockpyproject.toml — what you asked forpandas>=2.2.3
Loose ranges. Written by you (via uv add).
uv.lock — what you actually gotpandas==2.2.3 + every sub-dependency + file hashes
Exact, for every platform. Written by uv. Never edit by hand.
uv add …pyproject.toml + uv.lockuv sync → identical environmentCommit uv.lock. Never commit .venv\ — it’s rebuilt from the lock file (Module 5).
| Command | Does |
|---|---|
uv init name | New project folder |
uv add pkg / uv add "pkg>=2,<3" | Add a dependency (optionally with a version range) |
uv add --dev pkg | Add a development-only tool |
uv remove pkg | Remove a dependency |
uv sync | Make .venv match uv.lock exactly |
uv lock --upgrade-package pandas | Deliberately move to a newer pandas |
uv tree | Show the dependency tree |
uv run cmd | Run anything inside the environment |
uv self update | Update uv itself |
uv add --dev jupyterlab
uv run jupyter lab
import pandas just workshttp://localhost:8888/labThe terminal is now busy running the Jupyter server. Leave it open while you work.
To stop: go back to the terminal and press Ctrl+C (Module 2’s emergency brake). Open a second tab (Ctrl+Shift+T) for other commands.
We’ll explore notebooks properly in Module 6.
uv; confirm with uv --version in a new terminaluv python install 3.12C:\actuarial_work\lapse_analytics with uv initpandas, numpy, openpyxl — and jupyterlab as a dev toolpyproject.toml and find pandas’ exact version in uv.lockcheck_env.py.venvuv --version
uv python install 3.12
cd C:\actuarial_work
uv init lapse_analytics --python 3.12
cd lapse_analytics
uv add pandas numpy openpyxl
uv add --dev jupyterlab
cat pyproject.toml
Select-String 'name = "pandas"' uv.lock -Context 0,1
notepad check_env.py
uv run check_env.py
# check_env.py — which Python, which packages?
import sys
import numpy as np
import pandas as pd
print("Python :", sys.version.split()[0])
print("From :", sys.executable)
print("pandas :", pd.__version__)
print("numpy :", np.__version__)
# A tiny mortality table
df = pd.DataFrame({"age": [30, 40, 50],
"qx": [0.0008, 0.0016, 0.0041]})
df["px"] = 1 - df["qx"]
print(df)
# Outside the project, pandas doesn't exist:
cd ~
uv run --no-project python -c "import pandas"
# ModuleNotFoundError: No module named 'pandas'
# Inside, it does — and sys.executable points into .venv:
cd C:\actuarial_work\lapse_analytics
uv run check_env.py
rm .venv -Recurse -Force # destroy the environment
uv sync # rebuild from uv.lock
uv run check_env.py # same versions, same output
The environment is disposable; the lock file is the source of truth. That’s the whole idea.
.venv folderuv --version works in a new terminaluv pythonuv runpyproject.toml (what I asked for) vs. uv.lock (what I got)uv run jupyter lab — and stop it with Ctrl+CAn infinite undo button for your projects — and the end of model_v2_final_FINAL.xlsx.