p6nbrain
4 min read

Setting Up a Modern Python Environment with uv

A practical guide to setting up a fast, reproducible Python development environment using uv : the Rust-based package manager that replaces pip, virtualenv, and pyenv.

PythonDevOpsBest Practices
Mar 21, 20264 min read

Why uv?

If you have been using Python for machine learning, you have probably dealt with the pain of managing virtual environments, slow pip installs, and version conflicts. uv solves all of this.

uv is a Rust-based Python package manager that is 10-100x faster than pip. It handles virtual environments, Python version management, and dependency resolution in a single tool.

Key Takeaway

uv replaces pip, virtualenv, pyenv, and pip-tools with a single, blazing-fast tool.

Installing uv

The fastest way to install uv on macOS or Linux:

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

On Windows:

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

Verify the installation:

uv --version

Creating a New Project

uv has a built-in project scaffolding command:

uv init my-ml-project
cd my-ml-project

This creates a clean project structure:

my-ml-project/
├── .python-version
├── pyproject.toml
├── README.md
└── src/
    └── my_ml_project/
        └── __init__.py

Managing Python Versions

One of the best features of uv is built-in Python version management. No more pyenv:

# Install a specific Python version
uv python install 3.12
 
# Pin the project to a specific version
uv python pin 3.12
 
# List available versions
uv python list

Automatic Downloads

uv automatically downloads the correct Python version when you run commands. You do not need to pre-install Python.

Adding Dependencies

Adding packages is fast and simple:

# Add a package
uv add numpy pandas scikit-learn
 
# Add a dev dependency
uv add --dev pytest ruff mypy
 
# Add with version constraints
uv add "torch>=2.0"

uv generates a uv.lock lockfile for reproducible installs : similar to package-lock.json in Node.js.

Virtual Environments

uv manages virtual environments automatically. When you run uv add or uv sync, it creates a .venv in your project root:

# Sync all dependencies from pyproject.toml
uv sync
 
# Run a command inside the virtual environment
uv run python train.py
 
# Run pytest
uv run pytest

No Manual Activation Needed

You do not need to activate the virtual environment. Use uv run to execute commands within it. This ensures reproducibility.

Best Practices for ML Projects

Here is a recommended pyproject.toml for an ML project:

[project]
name = "my-ml-project"
version = "0.1.0"
description = "A machine learning project"
requires-python = ">=3.11"
dependencies = [
    "numpy>=1.26",
    "pandas>=2.0",
    "scikit-learn>=1.4",
    "matplotlib>=3.8",
]
 
[dependency-groups]
dev = [
    "pytest>=8.0",
    "ruff>=0.3",
    "mypy>=1.8",
    "jupyter>=1.0",
]
 
[tool.ruff]
line-length = 88
target-version = "py311"
 
[tool.mypy]
python_version = "3.11"
strict = true

Tips

  1. Always use uv.lock : commit it to version control for reproducible builds
  2. Separate dev dependencies : use dependency groups to keep production lean
  3. Pin Python version : use .python-version file for consistency across machines
  4. Use uv run : avoid activating venvs manually for cleaner workflows

Comparing uv to Traditional Tools

Featurepip + venvuv
Install speedSlow10-100x faster
LockfileNo (needs pip-tools)Built-in
Python managementNo (needs pyenv)Built-in
Dependency resolutionBasicAdvanced (PubGrub)
Single toolNoYes

Conclusion

uv is the modern way to manage Python environments for ML projects. It is fast, reproducible, and eliminates the need for multiple tools. If you are starting a new project, there is no reason not to use it.