Course 0W · Module 4 Next-Gen Python Tooling with uv
Python for Actuarial Students · Course 0W
Module 4

Next-Gen Python Tooling with uv

One fast tool for Python versions, projects, packages, and virtual environments — reproducible by default.

Module 4 · OverviewBy the end of this module you can…

  • Explain why “global Python” causes trouble, and what a virtual environment fixes
  • Install uv per-user, without admin rights
  • Install and switch Python versions with uv python
  • Create a project with uv init and read its pyproject.toml
  • Add packages, run code, and reproduce environments with uv.lock
  • Launch Jupyter Lab inside a project environment
45 min
Concepts & demos
45 min
Build an analytics project
Part 1

Why This Used to Hurt

Global Python, clashing packages, and “works on my machine”.

The old wayOne global Python for everything

  • Download an installer, tick (or forget!) “Add python.exe to PATH”
  • pip install pandas into the one shared Python
  • Project A needs pandas 1.5; project B needs pandas 2.2 — only one can win
  • Upgrade Python → every package disappears
  • Colleague installs “the same” packages → gets different versions → different numbers
Project Awants pandas 1.5
↓ ↑
Global Pythonpandas 2.2 (last one installed wins)
↓ ↑
Project Bwants pandas 2.2

If you can’t say exactly which package versions produced last quarter’s reserve numbers, you can’t reproduce them for an auditor.

The fixVirtual environments: one sandbox per project

pricing_2026\.venv\
Python 3.12
pandas 2.2 · numpy 2.1
reserving\.venv\
Python 3.11
pandas 1.5 · openpyxl
exam_prep\.venv\
Python 3.13
scipy · matplotlib
  • A virtual environment is just a folder (.venv) holding a Python interpreter link plus that project’s packages
  • Projects can’t break each other
  • Disposable: delete .venv and rebuild it in seconds

Historically you juggled python -m venv, activate, pip, pip freeze, pyenv… uv replaces the lot.

Meet uvOne tool instead of six

JobOld tool(s)uv
Install Python itselfpython.org installer, pyenvuv python install
Create environmentsvenv, virtualenvautomatic
Install packagespipuv add
Pin exact versionspip-tools, pip freezeuv.lock
Run in the environmentactivate + pythonuv run
Global CLI toolspipxuv tool install
10–100×
faster than pip (written in Rust, aggressive caching)

Made by Astral, who also make the ruff linter we’ll use in Module 7.

Part 2

Installing uv & Python

Per-user, no admin, no installer wizards.

InstallInstalling uv on Windows

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

powershell

Start a helper PowerShell…

-ExecutionPolicy ByPass

…allowed to run a script, for this one command only

irm URL

Invoke-RestMethod: download the install script

| iex

Invoke-Expression: run what was downloaded

Installs 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 pythonManaging Python runtimes

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 installeruv python
WizardYesNo
Admin rightsOftenNever
PATH editsCheckbox rouletteNone needed
Multiple versionsPainfulTrivial
Remove a versionControl Paneluv python uninstall

You rarely need to install Python explicitly — if a project asks for 3.12 and it’s missing, uv downloads it automatically.

Part 3

Projects & Environments

uv init, uv add, uv run — and the lock file that makes it reproducible.

uv initStarting a project

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.

pyproject.tomlThe project’s passport

[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",
]
  • A plain-text, standard file (TOML format) — readable by humans and by every modern Python tool
  • requires-python: which Pythons are allowed
  • dependencies: what the project needs — with minimum versions
  • dev group: tools for you, not for the analysis itself

Let uv add / uv remove edit this file for you.

uv addAdding packages

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
 ...
Resolvefind versions that all work together
→
Recordupdate pyproject.toml & write uv.lock
→
Installinto .venv\ (created if missing)

Version numbers on these slides are illustrative — yours will be whatever is current.

uv runRunning code inside the environment

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.

Reproducibilitypyproject.toml vs. uv.lock

pyproject.toml — what you asked for

pandas>=2.2.3

Loose ranges. Written by you (via uv add).

uv.lock — what you actually got

pandas==2.2.3 + every sub-dependency + file hashes

Exact, for every platform. Written by uv. Never edit by hand.

Youuv add …
commit →
Gitpyproject.toml + uv.lock
clone →
Colleague / auditor / future youuv sync → identical environment

Commit uv.lock. Never commit .venv\ — it’s rebuilt from the lock file (Module 5).

ReferenceThe commands you’ll actually use

CommandDoes
uv init nameNew project folder
uv add pkg / uv add "pkg>=2,<3"Add a dependency (optionally with a version range)
uv add --dev pkgAdd a development-only tool
uv remove pkgRemove a dependency
uv syncMake .venv match uv.lock exactly
uv lock --upgrade-package pandasDeliberately move to a newer pandas
uv treeShow the dependency tree
uv run cmdRun anything inside the environment
uv self updateUpdate uv itself

JupyterJupyter Lab, the uv way

uv add --dev jupyterlab
uv run jupyter lab
  • Jupyter is a dev dependency: you use it to explore; the analysis doesn’t need it to run
  • Jupyter runs inside the project environment, so import pandas just works
  • It opens your browser at http://localhost:8888/lab

The 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.

Hands-on Lab · 45 minA reproducible analytics project

  1. Install uv; confirm with uv --version in a new terminal
  2. Install Python 3.12 with uv python install 3.12
  3. Create C:\actuarial_work\lapse_analytics with uv init
  4. Add pandas, numpy, openpyxl — and jupyterlab as a dev tool
  5. Inspect pyproject.toml and find pandas’ exact version in uv.lock
  6. Write and run check_env.py
  7. Prove nothing leaked into the global system — then destroy and rebuild .venv

Lab · Steps 1–6Build it

uv --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)

Lab · Step 7Prove it’s isolated — and reproducible

Isolated

# 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

Reproducible

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.

RecapModule 4 checklist

  • I can explain why a shared global Python causes conflicts
  • I know a virtual environment is just a disposable .venv folder
  • uv --version works in a new terminal
  • I can install and pin Python versions with uv python
  • I can create a project, add packages, and run scripts with uv run
  • I can explain pyproject.toml (what I asked for) vs. uv.lock (what I got)
  • I can launch Jupyter Lab with uv run jupyter lab — and stop it with Ctrl+C
Up next
Module 5

Source Control with Git

An infinite undo button for your projects — and the end of model_v2_final_FINAL.xlsx.