Managing Python Versions and Virtual Environments with uv

Most projects we work on require Python 3.9 or greater. Many require a later version. In either case it is necessary to be able to have multiple versions of Python installed and easily switch between them, as well as manage project-specific dependencies. We use uv to handle both Python version management and virtual environments.

Installing uv

Follow uv's recommended installation methods. The quickest way is usually:

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

Or on macOS with Homebrew:

brew install uv

To verify that the installation was successful run the following and ensure that it prints out a version number:

uv --version

Installing Python Versions

uv can install and manage Python versions directly. To see available Python versions:

uv python list --all-versions

To install a specific Python version:

uv python install 3.11

Or install the latest patch version of a minor release:

uv python install 3.11  # Installs latest 3.11.x

To see which Python versions are currently installed:

uv python list

Selecting a Python Version for Your Project

When creating a new project, you can specify which Python version to use:

uv init --python 3.11 my-project
cd my-project

For existing projects, uv will use the Python version specified in the pyproject.toml file's requires-python field. You can also specify a Python version when syncing:

uv sync --python 3.11

Or pin a specific Python version for your project:

uv python pin 3.11

This creates a .python-version file in your project directory that uv will respect.

Managing Virtual Environments

uv automatically creates and manages virtual environments for your projects. By default, it creates them in a .venv directory within your project folder.

Creating Virtual Environments

For a new project:

uv init my-project
cd my-project
uv sync

You can also create a project with a specific structure:

uv init --package my-project  # Creates a package structure
uv init --app my-project      # Creates an application structure

For an existing project with a pyproject.toml file:

uv sync

This will:

  • Create a virtual environment in .venv
  • Install the Python version specified in pyproject.toml
  • Install all project dependencies

Adding Dependencies

Use uv add to add new dependencies to your project:

uv add requests

This updates your pyproject.toml and uv.lock files and installs the package.

For development dependencies:

uv add --dev pytest black mypy

For optional dependency groups:

uv add --group docs sphinx sphinx-rtd-theme

Updating Dependencies

Update a specific package:

uv add requests@latest

Update to a specific version:

uv add requests==2.31.0

Update all packages to their latest compatible versions:

uv sync --upgrade

Update only specific packages:

uv sync --upgrade-package requests --upgrade-package urllib3

Inspecting Dependencies

View the dependency tree:

uv tree

Show outdated packages:

uv pip list --outdated

Running Commands

Run commands in the project's virtual environment:

uv run python src/main.py
uv run pytest
uv run black .

For interactive sessions, you can activate the virtual environment:

source .venv/bin/activate  # On Unix/macOS
# or
.venv\Scripts\activate     # On Windows

python src/main.py  # Uses the virtual environment's Python
deactivate          # Exit the virtual environment

Advanced Features

Running Tools Without Installation

Run Python tools without installing them globally:

uv tool run black .
uv tool run --from ruff ruff check
uv tool run --python 3.12 mypy src/

Installing Global Tools

Install tools globally for command-line use:

uv tool install black
uv tool install ruff

Working with Scripts

Run Python scripts with inline dependencies:

uv run --with pandas,matplotlib analysis.py

Create self-contained scripts with dependency declarations:

# /// script
# requires-python = ">=3.11"
# dependencies = [
#     "requests",
#     "rich",
# ]
# ///

import requests
from rich import print

response = requests.get("https://api.github.com")
print(response.json())

Then run it with:

uv run script.py

Working with Requirements Files

Export dependencies to a requirements file:

uv pip compile pyproject.toml -o requirements.txt

Install from a requirements file:

uv pip sync requirements.txt

Migrating from Other Tools

From pip/venv

If you have a requirements.txt file:

uv init
uv pip sync requirements.txt
uv add --dev <your-dev-packages>

From Poetry

uv can read pyproject.toml files created by Poetry. Simply run:

uv sync

To fully migrate, you may want to:

  1. Remove the [tool.poetry] sections from pyproject.toml
  2. Delete poetry.lock
  3. Run uv sync to generate uv.lock

Further Reading

Edit