Python Virtual Environments with uv

Comprehensive guide to creating and managing Python virtual environments using uv, a fast and modern Python package manager.

uv is a fast, modern Python package and project manager that simplifies virtual environment creation and dependency management. This guide covers installation, environment setup, package management, and integration with common development workflows for research and data science projects.

What is uv?

uv is a fast Python package installer and resolver written in Rust. It serves as a drop-in replacement for pip and pip-tools, while also providing unified project management capabilities.

Why use uv?

  • Speed: Fast package installation and resolution
  • Simplicity: Single tool for managing Python versions, virtual environments, and packages
  • Modern workflow: Built-in support for pyproject.toml and modern Python packaging standards
  • Reliability: Deterministic dependency resolution and lockfiles
  • Compatibility: Works with existing pip and requirements.txt workflows

uv vs Other Tools

Feature uv pip conda
Speed Extremely fast (Rust-based) Moderate Slow to moderate
Virtual environments Built-in (uv venv) Requires separate venv module Built-in
Dependency resolution Advanced, deterministic Basic Advanced
Python version management Yes No Yes
Non-Python packages No No Yes
Best for Python-only projects, modern workflows Simple projects, compatibility Multi-language scientific computing

For Python-only or Python-plus-Stata research and data science projects, uv provides the best balance of speed, simplicity, and modern features.

Installing uv

Installation by Platform

# Install uv using winget
winget install astral-sh.uv
# Install uv using Homebrew
brew install uv
# Install uv using Homebrew
brew install uv

Or use the standalone installer:

# Install using the official installer script
curl -LsSf https://astral.sh/uv/install.sh | sh

Verify Installation

After installation, verify that uv is available:

# Check uv version
uv --version

You should see output like uv 0.x.x indicating the installed version.

Creating Virtual Environments

Basic Environment Creation

Create a virtual environment in the current directory:

# Create a virtual environment named .venv
uv venv

This creates a .venv directory containing the isolated Python environment.

Custom Environment Names

Specify a custom name for your environment:

# Create environment with custom name
uv venv myproject-env

Specifying Python Version

Create an environment with a specific Python version:

# Create environment with Python 3.11
uv venv --python 3.12

# Or specify the full version
uv venv --python 3.12.5

If the specified Python version is not installed, uv will automatically download and install it.

Activating Virtual Environments

After creating an environment, activate it to use it:

On Windows:

# Powershell
.venv\Scripts\activate

# NuShell
overlay using .venv/Scripts/activate.nu

On macOS/Linux:

# bash
source .venv/bin/activate

# NuShell
overlay using .venv/Scripts/activate.nu

When activated, your command prompt will show the environment name, typically as (.venv) or (myproject-env).

Deactivating Environments

To exit the virtual environment:

# Deactivate the current environment
deactivate

Managing Packages

Installing Packages

uv provides multiple ways to install packages:

Using uv pip

Drop-in replacement for pip:

# Install a single package
uv pip install pandas

# Install multiple packages
uv pip install pandas numpy matplotlib seaborn

# Install with specific version
uv pip install pandas==2.0.0

# Install from requirements.txt
uv pip install -r requirements.txt

Using uv add (Project Mode)

For project-based workflows with pyproject.toml:

# Add package to project dependencies
uv add pandas

# Add multiple packages
uv add pandas numpy matplotlib seaborn jupyterlab

# Add development dependencies
uv add --dev pytest ruff black

This command:

  1. Installs the package in the active environment
  2. Adds it to pyproject.toml dependencies
  3. Updates the lockfile for reproducibility

Upgrading Packages

Update packages to the latest versions:

# Upgrade a specific package
uv pip install --upgrade pandas

# Upgrade all packages in requirements.txt
uv pip install --upgrade -r requirements.txt

Listing Installed Packages

View packages in the current environment:

# List all installed packages
uv pip list

# Show package details
uv pip show pandas

Uninstalling Packages

Remove packages from the environment:

# Uninstall a package
uv pip uninstall pandas

# Uninstall multiple packages
uv pip uninstall pandas numpy

Working with pyproject.toml

pyproject.toml is the modern standard for Python project configuration. uv integrates seamlessly with it.

Basic Project Structure

[project]
name = "my-research-project"
version = "0.1.0"
description = "Analysis of survey data"
requires-python = ">=3.10"
dependencies = [
    "pandas>=2.0.0",
    "numpy>=1.24.0",
    "matplotlib>=3.7.0",
    "seaborn>=0.12.0",
]

[dependency-groups]
dev = [
    "pytest>=7.0.0",
    "ruff>=0.1.0",
    "jupyterlab>=4.0.0",
]

Creating a New Project

Initialize a new project with uv:

# Create a new project directory and pyproject.toml
uv init my-project
cd my-project

This creates a basic project structure with pyproject.toml.

Installing from pyproject.toml

Install all dependencies defined in pyproject.toml:

# Install project dependencies
uv sync

# Install with optional dependency groups
uv sync --extra dev

Adding Dependencies

Add packages and automatically update pyproject.toml:

# Add to main dependencies
uv add pandas numpy

# Add to development dependencies
uv add --dev pytest ruff

Lockfiles for Reproducibility

uv creates uv.lock to pin exact versions:

# Generate/update lockfile
uv lock

# Install from lockfile (exact versions)
uv sync

Commit uv.lock to version control to ensure everyone uses identical package versions.

Common Workflows

Starting a New Project

Complete workflow for a new research project:

# Create project directory
mkdir my-analysis
cd my-analysis

# Initialize uv project
uv init

# Create virtual environment
uv venv

# Activate environment (Windows PowerShell)
.venv\Scripts\activate

# Activate environment (NuShell)
# overlay using .venv\Scripts\activate.nu

# Activate environment (bash)
# source .venv/bin/activate

# Add dependencies
uv add pandas numpy matplotlib seaborn jupyterlab

# Add development tools
uv add --dev pytest ruff

# Start working
jupyter lab
# or uv run jupyter lab

Cloning an Existing Project

Set up an environment from a project with pyproject.toml:

# Clone the repository
git clone https://github.com/organization/project.git
cd project

# Create virtual environment
uv venv

# Activate environment
.venv\Scripts\activate # or source .venv/bin/activate  in bash

# Install all dependencies from lockfile
uv sync

Updating Dependencies

Keep project dependencies current:

# Update all dependencies to latest compatible versions
uv lock --upgrade

# Update specific package
uv lock --upgrade-package pandas

# Install updated dependencies
uv sync

Sharing Environments

For collaborators not using uv:

# Export to requirements.txt for pip compatibility
uv pip freeze > requirements.txt

Others can then use:

pip install -r requirements.txt

Troubleshooting

Environment Not Activating

Problem: Activation script not found or permission errors.

Solution:

  1. Verify environment was created: Check that .venv directory exists
  2. Use full path to activation script:
# Windows
C:\path\to\project\.venv\Scripts\activate

# macOS/Linux
source /path/to/project/.venv/bin/activate
  1. On Windows, if you get execution policy errors:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Path Conflicts with Multiple Python Installations

Problem: Wrong Python version being used.

Solution:

  1. Specify Python version explicitly when creating environment:
uv venv --python 3.12
  1. Check which Python is being used:
# In activated environment
which python  # bash, NuShell
where python  # Windows PowerShell

Version Conflicts

Problem: Incompatible package versions.

Solution:

  1. Use uv’s dependency resolver:
uv pip install package1 package2 --resolution highest
  1. Check conflict details:
uv pip install --dry-run package1 package2
  1. Pin specific versions in pyproject.toml:
dependencies = [
    "package1>=1.0,<2.0",
    "package2==3.5.0",
]

Integration with IDEs

VS Code

  1. Select Python Interpreter:
    • Press Ctrl+Shift+P (Windows/Linux) or Cmd+Shift+P (macOS)
    • Type “Python: Select Interpreter”
    • Choose the .venv/bin/python (or .venv\Scripts\python.exe on Windows)
  2. Automatic Activation:
    • VS Code automatically activates the environment in integrated terminal
    • Create .vscode/settings.json:
{
    "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python"
}
  1. Recommended Extensions:
    • Python extension (Microsoft)
    • Pylance (Microsoft)
    • Jupyter (Microsoft)

JupyterLab

  1. Install Jupyter in Environment:
uv add jupyterlab ipykernel
  1. Register Environment as Kernel:
# Activate environment first
python -m ipykernel install --user --name=myproject --display-name="Python (myproject)"
  1. Launch JupyterLab:
uv run jupyter lab
  1. Select Kernel: In JupyterLab, choose “Python (myproject)” from the kernel menu.

Best Practices

Project Organization

Keep a clean project structure:

my-project/
├── .venv/                 # Virtual environment (don't commit)
├── data/                  # Data files (don't commit)
├── notebooks/             # Jupyter notebooks
├── src/                   # Source code
│   └── my_project/
├── tests/                 # Test files
├── .gitignore            # Ignore .venv, data/, etc.
├── pyproject.toml        # Project configuration
├── uv.lock              # Lockfile (commit this)
└── README.md            # Project documentation

Environment Naming

Use consistent naming:

  • .venv for standard virtual environments (recommended, works with most IDEs)
  • projectname-env for named environments
  • Avoid spaces in environment names

Dependency Management

  • Pin major versions: pandas>=2.0,<3.0 for stability
  • Use lockfiles: Commit uv.lock for reproducibility
  • Separate dev dependencies: Keep development tools separate from runtime dependencies
  • Document unusual dependencies: Add comments in pyproject.toml explaining non-obvious packages

Regular Maintenance

  • Update regularly: Run uv lock --upgrade monthly to get security patches
  • Test after updates: Run tests after upgrading dependencies
  • Review dependencies: Periodically audit and remove unused packages

Learning Resources

For general Python setup and data science workflows, see:

Back to top