Complete uv Guide: Modern Python Package Management

Your comprehensive reference for using uv on MacBook Pro M4 with Sequoia 15.5+

Getting Started with uv

What is uv? A blazingly fast Python package manager (10-100x faster than pip) that replaces pip, virtualenv, poetry, and pyenv with a single modern tool.

Installation

# Option 1: Using Homebrew (recommended for Mac)
brew install uv

# Option 2: Using official installer
curl -LsSf https://astral.sh/uv/install.sh | sh

Verify Installation

uv --version

Should output something like uv 0.6.14 or higher.

Why Switch from pip?

Feature pip uv
Speed Baseline 10-100x faster
Virtual environments Manual activation Automatic
Dependency locking requirements.txt (manual) uv.lock (automatic)
Dependency resolution Backtracking SAT solver
Transitive dependency removal Manual Automatic
Python version management Requires pyenv Built-in

Key Concepts

Mental shift required: The biggest change is trusting uv run instead of manually activating environments. This eliminates "wrong environment" errors.

Setting Up New Projects

Create a New Project

# Navigate to your workspace
cd ~/Projects

# Create new project
uv init drug-analysis

# Move into project directory
cd drug-analysis

This creates the following structure:

drug-analysis/ ├── .python-version # Python version pin ├── pyproject.toml # Project metadata & dependencies ├── README.md └── hello.py # Sample script

Inspect Generated Files

pyproject.toml

[project]
name = "drug-analysis"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []

.python-version

Contains the pinned Python version (e.g., 3.12).

Recommended Project Structure

# Create organized structure
mkdir -p src/drug_analysis tests scripts data

# Create package structure
touch src/drug_analysis/__init__.py
touch tests/__init__.py

Final recommended structure:

drug-analysis/ ├── .venv/ # Auto-created, gitignored ├── data/ # Raw datasets ├── scripts/ # Analysis scripts ├── src/ │ └── drug_analysis/ # Main package │ ├── __init__.py │ └── main.py ├── tests/ │ ├── __init__.py │ └── test_main.py ├── .gitignore ├── .python-version ├── pyproject.toml ├── uv.lock └── README.md

Configure .gitignore

cat > .gitignore << 'EOF'
# Python
__pycache__/
*.py[cod]
*$py.class
.venv/
*.egg-info/

# Data
data/*.csv
data/*.xlsx

# IDE
.DS_Store
.vscode/
.idea/

# Keep uv files
!uv.lock
!pyproject.toml
EOF
Critical: Always commit both pyproject.toml and uv.lock to Git for reproducibility.

Initialize Existing Project

If you already have code and don't want sample files:

cd existing-project
uv init --bare

Managing Dependencies

Adding Packages

Production Dependencies

# Add single package
uv add pandas

# Add multiple packages
uv add pandas numpy scipy scikit-learn
This automatically:
  • Updates dependencies = [] in pyproject.toml
  • Creates .venv/ virtual environment (first time)
  • Generates/updates uv.lock with exact versions
  • Installs packages into .venv

Development Dependencies

# Add dev tools
uv add --dev pytest ruff mypy ipykernel

# Add to specific group
uv add --group docs sphinx mkdocs

Dev dependencies appear in [dependency-groups]:

[dependency-groups]
dev = [
    "pytest>=8.0.0",
    "ruff>=0.7.0",
    "mypy>=1.13.0",
    "ipykernel>=6.29.0",
]

Viewing Dependencies

# List all installed packages
uv pip list

# Show dependency tree
uv tree

# Show specific package details
uv pip show pandas

Removing Packages

uv remove requests

This removes the package from pyproject.toml, updates uv.lock, uninstalls from environment, and removes orphaned transitive dependencies.

Updating Dependencies

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

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

# Apply changes to environment
uv sync

Syncing Environment

uv sync
Use uv sync when:
  • After cloning a project
  • After pulling code changes
  • After manually editing pyproject.toml
  • Switching branches

uv sync installs the exact Python version, creates .venv, installs all dependencies from uv.lock, and removes packages not in lockfile.

Working with Dependency Groups

# Install specific groups only
uv sync --group docs

# Exclude dev dependencies
uv sync --no-dev
Never manually edit uv.lock—it's generated automatically and manual changes break integrity.

Working with requirements.txt

When Cursor AI or other tools generate requirements.txt, you have two approaches.

Method 1: Quick Install (No Migration)

Install packages without updating pyproject.toml:

uv pip install -r requirements.txt
Limitation: Doesn't update pyproject.toml or create lockfile. Use for quick testing only.

Method 2: Migrate to uv Project (Recommended)

Step 1: Initialize project (if needed)

# Create new project
uv init

# Or for existing code
uv init --bare

Step 2: Import requirements

# Add all requirements as dependencies
uv add -r requirements.txt
This automatically:
  • Reads every package from requirements.txt
  • Adds to pyproject.toml dependencies
  • Creates/updates uv.lock with exact versions
  • Creates .venv and installs packages

Step 3: Handle dev dependencies (optional)

# If you have separate dev requirements
uv add --dev -r requirements-dev.txt

Step 4: Verify and clean up

# Verify installation
uv tree

# Remove old requirements file
rm requirements.txt

Practical Example

# Cursor generated requirements.txt:
# pandas==2.1.0
# numpy==1.24.3
# scikit-learn==1.3.0

# Convert to uv project
uv init
uv add -r requirements.txt

# Result in pyproject.toml:
# [project]
# dependencies = [
#     "pandas>=2.1.0",
#     "numpy>=1.24.3",
#     "scikit-learn>=1.3.0",
# ]

Edge Cases

Complex Version Constraints

# requirements.txt:
# requests>=2.28.0,<3.0.0
# flask==2.3.2

# uv preserves these constraints
uv add -r requirements.txt

Git-Based Dependencies

# requirements.txt:
# git+https://github.com/user/repo.git@main

# uv converts to tool.uv.sources format
uv add -r requirements.txt

Preserving Exact Pins

Version flexibility: requirements.txt often has exact pins (==), but uv add may convert to minimum versions (>=).
# Lock to exact versions from requirements.txt
uv lock --constraints requirements.txt

Exporting to requirements.txt

If you need requirements.txt for deployment:

# Export all dependencies
uv pip freeze > requirements.txt

# Export only production deps
uv export --no-dev --format requirements-txt > requirements.txt

Comparison Table

Approach Command Updates pyproject.toml Creates lockfile Best for
Direct install uv pip install -r requirements.txt ❌ No ❌ No Quick testing
Import to project uv add -r requirements.txt ✅ Yes ✅ Yes Production work

Daily Development Workflow

Running Your Code

uv run python script.py
Always use uv run: Never run python script.py directly—you'll use system Python instead of your project environment.

Common Commands

# Run Python scripts
uv run python analyze.py

# Run tests
uv run pytest

# Run linter
uv run ruff check .

# Run type checker
uv run mypy .

# Open Python REPL
uv run python

# Run module
uv run -m flask run

# One-off tool (no installation)
uvx black script.py

Complete Example Workflow

# 1. Create project
cd ~/Projects
uv init protein-folding
cd protein-folding

# 2. Add dependencies
uv add pandas numpy scipy biopython
uv add --dev pytest ruff ipykernel

# 3. Create your code
cat > analyze.py << 'EOF'
import pandas as pd
import numpy as np

def main():
    print("Running analysis...")
    # Your code here

if __name__ == '__main__':
    main()
EOF

# 4. Run your code
uv run python analyze.py

# 5. Run tests
uv run pytest

# 6. Lint code
uv run ruff check .

# 7. Commit to Git
git init
git add .
git commit -m "Initial project setup"

Cloning and Running Existing Projects

# 1. Clone repository
git clone <repo-url>
cd project-name

# 2. Sync environment (installs everything)
uv sync

# 3. Run the project
uv run python main.py
uv sync ensures:
  • Exact Python version installed
  • .venv created
  • All dependencies from uv.lock installed
  • Identical environment across all machines

Interactive Development in Cursor

For Shift+Enter code execution:

# Ensure ipykernel is installed
uv add --dev ipykernel

Cursor automatically detects and uses the .venv created by uv—no manual kernel configuration needed.

Typical Day Workflow

  1. Pull latest code: git pull
  2. Sync dependencies: uv sync
  3. Add new package if needed: uv add package-name
  4. Write/modify code in Cursor
  5. Run code: uv run python script.py
  6. Run tests: uv run pytest
  7. Commit changes: git add . && git commit -m "message"
  8. Push: git push

Command Reference

Quick Reference

Task Command
Create project uv init project-name
Add package uv add package-name
Add dev tool uv add --dev pytest
Import requirements uv add -r requirements.txt
Install from requirements uv pip install -r requirements.txt
Remove package uv remove package-name
Run script uv run python script.py
Run tests uv run pytest
Sync environment uv sync
Update all deps uv lock --upgrade
Update specific package uv lock --upgrade-package pandas
List packages uv pip list
View dependency tree uv tree
Show package info uv pip show package-name
Export requirements uv pip freeze > requirements.txt
Run one-off tool uvx tool-name

pip vs uv Command Mapping

Old Way (pip) New Way (uv)
python -m venv .venv Automatic with uv add
source .venv/bin/activate Never needed—use uv run
pip install pandas uv add pandas
pip install -r requirements.txt uv add -r requirements.txt
pip uninstall pandas uv remove pandas
pip list uv pip list
pip freeze > requirements.txt Automatic in uv.lock
python script.py uv run python script.py

Python Version Management

Task Command
Install Python version uv python install 3.12
List installed versions uv python list
Pin project to version uv python pin 3.12
Remove Python version uv python uninstall 3.11

Risks and Limitations

Common mistakes:
  • ❌ Running python script.py directly (uses system Python)
  • ❌ Manually activating .venv with source .venv/bin/activate
  • ❌ Editing uv.lock manually
  • ❌ Forgetting to commit uv.lock to Git
  • ❌ Using pip install in uv projects
Best practices:
  • ✅ Always use uv run for execution
  • ✅ Always use uv add for packages
  • ✅ Commit both pyproject.toml and uv.lock
  • ✅ Run uv sync after pulling changes
  • ✅ Let uv manage virtual environments

Cursor AI Integration

Configure Cursor to understand your uv-based workflow.

Minimal Cursor Rule

Create a global rule in Cursor (Settings → Rules → New Cursor Rule):

Rule Configuration

Rule Content

# Project Uses uv

This project uses uv for Python package management and execution.

## Code Generation Guidelines

- Assume all dependencies are managed via pyproject.toml
- Dependencies are locked in uv.lock
- Virtual environment exists at .venv/
- Code will be executed using `uv run python script.py`

## When Suggesting Commands

If asked about running code, suggest: `uv run python <script>`
If asked about dependencies, mention: Check pyproject.toml

## Import Statements

Generate import statements assuming all dependencies in
pyproject.toml are installed. No need to check if packages
are available—assume they're in the locked environment.

## Interactive Execution

For Shift+Enter code execution in Cursor:
- ipykernel links to .venv automatically
- No special configuration needed

Project-Specific Rule

Create .cursorrules in your project root:

# Project Configuration

This project uses uv for dependency management.

Dependencies are defined in pyproject.toml and locked in uv.lock.
Code execution uses `uv run python <script>`.
Virtual environment is at .venv/

## Project Context
Biology/drug discovery project analyzing compound properties.

## Standard Dependencies
- Core: pandas, numpy, scikit-learn, rdkit
- Testing: pytest, pytest-cov
- Code quality: ruff, mypy

Preventing requirements.txt Generation

Add to your Cursor rules:

Never generate requirements.txt.
Use `uv add <package>` commands instead.
Dependencies are managed in pyproject.toml.

Handling Cursor-Generated requirements.txt

If Cursor still generates requirements.txt:

# Quick workflow
uv add -r requirements.txt
rm requirements.txt
git add pyproject.toml uv.lock
git commit -m "Add dependencies from Cursor"

Interactive Development Setup

For Shift+Enter code execution in Cursor:

# Ensure ipykernel is in your dev dependencies
uv add --dev ipykernel

Cursor automatically detects the .venv and links the Jupyter kernel—no manual configuration required.

Verification

Test your Cursor rules with these prompts:

  1. "How do I run analysis.py?" → Should suggest uv run python analysis.py
  2. "Add pandas as a dependency" → Should suggest uv add pandas
  3. "Where are my dependencies?" → Should mention pyproject.toml/uv.lock

Biology/AI Engineering Workflow

For your Anduril Limited projects:

# Standard setup for new drug discovery project
uv init protein-analysis
cd protein-analysis

uv add pandas numpy scipy scikit-learn rdkit biopython
uv add --dev pytest ruff mypy ipykernel jupyter

# Create project structure
mkdir -p data notebooks scripts src/protein_analysis tests

# Start developing in Cursor
cursor .
MacBook Pro M4 Note: uv handles ARM64 architecture automatically. No special configuration needed for Apple Silicon—compiled packages are managed transparently.