Skip to content

Manage Python Dependencies with uv

uv is a fast Python package and project manager that consolidates pip, virtualenv, and pip-tools into a single tool. This guide covers installing uv locally and on the cluster, managing project dependencies, running scripts reproducibly, and submitting Slurm batch jobs.

Before you begin

  • Get Started with the Cluster


    Obtain a Mila account, enable cluster access and MFA, install uv and milatools, configure SSH access and connect to the cluster for the first time.

 

What this guide covers

  • Install uv on a local machine and on the Mila cluster
  • Create a project and declare dependencies in pyproject.toml
  • Add, update, and remove packages
  • Understand how uv resolves dependencies safely
  • Reproduce the environment on a new node using uv.lock
  • Run standalone scripts with inline dependencies
  • Submit a Slurm job that runs your script with uv run python
  • Install CLI tools system-wide with uv tool

Install uv

On a local machine

Run the following command in a terminal:

curl -LsSf https://astral.sh/uv/install.sh | sh
downloading uv 0.10.10 x86_64-unknown-linux-gnu
no checksums to verify
installing to /home/username/.local/bin
  uv
  uvx
everything's installed!

Verify the installation:

uv --version
uv 0.10.10

If uv is not found

If uv --version returns command not found, close and reopen your terminal to apply the updated PATH.

On the cluster

Connect to a login node:

ssh mila

Then run the install command:

curl -LsSf https://astral.sh/uv/install.sh | sh

If uv is not found

If uv --version returns command not found, exit the SSH session and reconnect to apply the updated PATH.

Create a project

Initialize a new project with a pinned Python version:

uv init my-project --python=3.12
cd my-project
Initialized project `my-project` at `my-project`

The command creates the following files:

1
2
3
4
5
my-project/
β”œβ”€β”€ pyproject.toml    # project metadata and dependencies
β”œβ”€β”€ .python-version   # pinned Python version
β”œβ”€β”€ hello.py          # sample entry point
└── README.md

The virtual environment (.venv/) and lockfile (uv.lock) are created the first time uv add or uv run is called.

Initialize a project in an existing directory

Run uv init without a directory name from inside an existing directory to initialize a project in place.

Manage dependencies

Add packages

uv add installs a package, updates pyproject.toml, and synchronizes the virtual environment in a single step:

uv add torch
Resolved 7 packages in 1.23s
Prepared 5 packages in 45.67s
Installed 5 packages in 1.23s
 + torch==2.5.1

Specify version constraints using PEP 440 syntax:

uv add "numpy>=2.0"

How uv resolves dependencies

pip installs packages one command at a time and only checks constraints for the packages in that command β€” it can silently break packages that are already installed:

"when you run a pip install command, pip only considers the packages you are installing in that command, and may break already-installed packages." β€” pip documentation

uv add resolves the entire dependency graph before writing anything to disk. If adding a new package would conflict with an existing one, uv reports the conflict and aborts rather than leaving the environment in a broken state.

Add development dependencies

Development dependencies β€” testing tools, linters, formatters β€” are only needed during local development, not when running your research code. Add them with --dev:

uv add --dev pytest

Remove packages

uv remove torch

Reproduce the environment

Why pin exact versions

Without a lockfile, two installs of the same pyproject.toml can produce different package versions β€” a transitive dependency may have released a new patch between installs. This can silently change model behaviour or break code across nodes and collaborators.

uv.lock records the exact resolved version of every dependency, direct and transitive. Committing this file to version control guarantees that uv sync installs a bit-for-bit identical environment on any machine.

Sync the environment

uv sync
Resolved 7 packages in 0.08s
Audited 7 packages in 0.01s

Free disk space by clearing the cache

If your home directory is running low on space, first remove stale entries with:

uv cache prune
Pruning cache at: /home/mila/u/username/.cache/uv
Removed 21109 files (3.3GiB)

This removes outdated entries while keeping packages still used by your projects. If you need to reclaim more space, remove the entire cache with:

uv cache clean
Clearing cache at: /home/mila/u/username/.cache/uv
Cleaning [========>           ] 45%
Removed 20518 files (7.1GiB)

uv will re-download packages automatically the next time they are needed.

Run code

Within a project

uv run executes a command inside the project environment. Before running, uv checks whether the lockfile matches pyproject.toml and updates the virtual environment if needed. No manual activation of the virtual environment is required.

Run a tool registered in the environment:

uv run pytest

Run a Python script with the project environment loaded:

uv run python train.py

Use uv in a Slurm job

Declare the training script's dependencies in pyproject.toml using uv add:

uv add "torch>=2.5"
train.py
import torch
# ... training code
job.sh
#!/bin/bash
#SBATCH --job-name=train
#SBATCH --ntasks=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=4
#SBATCH --gpus-per-task=l40s:1
#SBATCH --mem=16G
#SBATCH --time=1:00:00

srun uv run python train.py

Submit the job from the project root directory:

sbatch job.sh
sbatch: --------------------------------------------------------------------------------------------------
sbatch: # Using default long partition
sbatch: --------------------------------------------------------------------------------------------------
Submitted batch job 8888888

uv run syncs the environment against uv.lock before executing train.py, so the job always uses the pinned dependencies regardless of which compute node runs it.

Install CLI tools with uv tool

uv tool install installs a package's CLI executables into a persistent, isolated environment and adds them to PATH. Use this for command-line tools needed across projects β€” separate from uv add, which adds packages imported in project code.

Install a tool

Install wandb to access the Weights & Biases CLI:

uv tool install wandb
Resolved 20 packages in 371ms
Prepared 20 packages in 1.87s
Installed 20 packages in 2.16s
 + annotated-types==0.7.0
 + certifi==2026.2.25
 [...]
 + urllib3==2.6.3
 + wandb==0.25.1
Installed 2 executables: wandb, wb

The wandb command is now available system-wide.

List installed tools

uv tool list
milatools v0.4.1
- mila
wandb v0.19.1
- wandb

Upgrade tools

Upgrade a single tool:

uv tool upgrade wandb
Updated wandb v0.19.1 -> v0.19.2
Installed 2 executables: wandb, wb

Upgrade all installed tools at once:

uv tool upgrade --all
Updated wandb v0.19.1 -> v0.19.2

Uninstall a tool

uv tool uninstall wandb
Uninstalled 1 executable: wandb

Standalone scripts with inline dependencies

For one-off scripts or utilities that do not belong to a project, PEP 723 metadata lets you declare dependencies directly inside the script file.

Use uv add --script to add dependencies to the script. uv will write the # /// script metadata block automatically:

uv add --script experiment.py numpy matplotlib

The resulting script looks like:

experiment.py
# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "matplotlib",
#   "numpy",
# ]
# ///

import numpy as np
import matplotlib.pyplot as plt

data = np.random.randn(1000)
plt.hist(data)
plt.savefig("hist.png")

Run the script with:

uv run --script experiment.py

uv reads the metadata block, creates a temporary isolated environment with those exact dependencies, runs the script, and discards the environment. The project's pyproject.toml is not modified.


Key concepts

pyproject.toml
The project configuration file. Lists runtime and development dependencies, the required Python version, and project metadata. Updated automatically by uv add and uv remove.
uv.lock
A lockfile generated by uv that records the exact resolved version of every dependency. Commit this file to version control to guarantee reproducible environments across nodes and collaborators.
uv run
Executes a command inside the project's virtual environment. Use uv run python <file> to run a project script. Pass --script <file> only for standalone scripts with PEP 723 inline metadata. Syncs the environment against uv.lock before running, making manual activation unnecessary.
virtual environment (.venv/)
An isolated directory containing the Python interpreter and installed packages for the project. Created and managed automatically by uv.
dependency group
A named set of dependencies in pyproject.toml. The default development group (--dev) holds tools like pytest that are only needed during local development, not when running your research code on the cluster.
uv tool install
Installs a CLI tool into a persistent isolated environment and adds its executables to PATH. Use for command-line tools needed across projects (e.g. wandb, mila). For packages imported in code, use uv add instead.
tool environment
A persistent isolated virtual environment created by uv tool install, stored separately from any project's .venv. Removed with uv tool uninstall.
PEP 723 script metadata
A # /// script block at the top of a .py file that declares the script's Python version and dependencies. Used for one-off scripts that do not belong to a project. uv add --script writes this block automatically; uv run --script reads it and creates a temporary isolated environment, leaving pyproject.toml unchanged.

Comments

Ask AI