dependency-management.md 6.5 KB

Python Dependency Management

Advanced patterns for managing Python dependencies with uv.

Project Lockfile (uv.lock) — preferred

For any project with a pyproject.toml, uv manages a uv.lock automatically. This is the reproducible, uv-native workflow — prefer it over a hand-managed requirements.txt.

uv add "flask>=2.0" sqlalchemy     # add runtime deps; uv.lock updated
uv add --dev pytest ruff mypy      # dev-only dependency group
uv remove flask                    # drop a dep
uv sync                            # install exactly from uv.lock
uv sync --frozen                   # CI: fail if uv.lock is stale, don't re-resolve
uv lock --upgrade                  # bump everything within constraints
uv lock --upgrade-package flask    # bump just one

requirements.txt Workflow (uv pip compile)

Use this only when you specifically need a requirements.txt — Docker layer caching, non-uv CI, or legacy tooling. Otherwise prefer uv.lock above.

Basic Lock Pattern

# requirements.in (loose constraints)
flask>=2.0
sqlalchemy>=2.0
pydantic>=2.0

# Generate locked requirements.txt
uv pip compile requirements.in -o requirements.txt

# Install exact versions
uv pip sync requirements.txt

Separate Dev Dependencies

# requirements.in
flask>=2.0
sqlalchemy>=2.0

# requirements-dev.in
-r requirements.in
pytest>=7.0
ruff>=0.1
mypy>=1.0

# Compile both
uv pip compile requirements.in -o requirements.txt
uv pip compile requirements-dev.in -o requirements-dev.txt

# Install for development
uv pip sync requirements-dev.txt

Update Workflow

# Update all packages to latest compatible versions
uv pip compile requirements.in -o requirements.txt --upgrade

# Update specific package
uv pip compile requirements.in -o requirements.txt --upgrade-package flask

# Update with constraints
uv pip compile requirements.in -o requirements.txt --upgrade --constraint constraints.txt

Constraint Files

# constraints.txt
# Pin versions that need to be consistent across projects
numpy==1.26.0
pandas==2.0.0

# Use constraints during compile
uv pip compile requirements.in -o requirements.txt --constraint constraints.txt

Multiple Environments

Python Version Specific

# Python 3.10
uv pip compile requirements.in -o requirements-py310.txt --python-version 3.10

# Python 3.11
uv pip compile requirements.in -o requirements-py311.txt --python-version 3.11

Platform Specific

# Linux
uv pip compile requirements.in -o requirements-linux.txt --platform linux

# macOS
uv pip compile requirements.in -o requirements-macos.txt --platform macos

# Windows
uv pip compile requirements.in -o requirements-windows.txt --platform windows

Workspace/Monorepo

Structure

my-monorepo/
├── pyproject.toml        # Root workspace config
├── packages/
│   ├── core/
│   │   └── pyproject.toml
│   ├── api/
│   │   └── pyproject.toml
│   └── cli/
│       └── pyproject.toml

Root pyproject.toml

[tool.uv.workspace]
members = ["packages/*"]

[tool.uv.sources]
my-core = { workspace = true }
my-api = { workspace = true }

Package pyproject.toml

# packages/core/pyproject.toml
[project]
name = "my-core"
version = "0.1.0"
dependencies = ["pydantic>=2.0"]

# packages/api/pyproject.toml
[project]
name = "my-api"
version = "0.1.0"
dependencies = ["my-core", "fastapi>=0.100"]

Workspace Commands

# Install all workspace members into one env (native — no editable pip installs)
uv sync

# Run a command in the workspace env
uv run pytest

# Operate on a specific member
uv run --package my-api pytest

Private Packages

Configure Index (pyproject.toml)

[[tool.uv.index]]
name = "private"
url = "https://pypi.private.com/simple/"
uv add my-private-package          # resolves against configured indexes

Authentication via environment

# Per-index credentials: UV_INDEX_<NAME>_USERNAME / _PASSWORD
export UV_INDEX_PRIVATE_USERNAME=user
export UV_INDEX_PRIVATE_PASSWORD=token
uv add my-private-package

requirements.txt workflow

--extra-index-url https://pypi.private.com/simple/
my-public-package>=1.0
my-private-package>=2.0

Git Dependencies

# In pyproject.toml
[project]
dependencies = [
    "my-package @ git+https://github.com/user/repo.git",
    "my-package @ git+https://github.com/user/repo.git@v1.0.0",
    "my-package @ git+https://github.com/user/repo.git@main",
    "my-package @ git+ssh://git@github.com/user/repo.git",
]
# requirements.in
git+https://github.com/user/repo.git@main#egg=my-package

Local Dependencies

# In pyproject.toml
[project]
dependencies = [
    "my-local @ file:///path/to/package",
]

# Relative path
[tool.uv.sources]
my-local = { path = "../my-local-package" }

Dependency Resolution

Resolver Options

# Use backtracking resolver (more thorough but slower)
uv pip compile requirements.in -o requirements.txt --resolver=backtracking

# Allow prereleases
uv pip compile requirements.in -o requirements.txt --prerelease=allow

# Exclude specific packages from upgrade
uv pip compile requirements.in -o requirements.txt --upgrade --no-upgrade-package numpy

Resolution Troubleshooting

# Show why a version was chosen
uv pip compile requirements.in --verbose

# Generate dependency tree
uv pip tree

# Check for conflicts
uv pip check

Caching

# Clear uv cache
uv cache clean

# Show cache location
uv cache dir

# Disable cache for one command
uv pip install --no-cache package-name

CI/CD Patterns

GitHub Actions

- name: Install uv
  uses: astral-sh/setup-uv@v5

- name: Install dependencies
  run: uv sync --frozen

- name: Run tests
  run: uv run pytest

Cache Dependencies

- name: Cache uv
  uses: actions/cache@v3
  with:
    path: ~/.cache/uv
    key: uv-${{ hashFiles('uv.lock') }}
    restore-keys: uv-

Lock File in CI

- name: Verify lock file is up to date
  run: uv lock --check

Best Practices

  1. Always use lock files in production - Reproducible builds
  2. Separate dev dependencies - Smaller production installs
  3. Use constraints for shared deps - Consistent versions across packages
  4. Pin Python version - Avoid compatibility surprises
  5. Run uv pip check - Catch conflicts early
  6. Cache in CI - Faster builds
  7. Review upgrades carefully - Don't blindly --upgrade