UV Package Manager Guide
This project uses uv - an ultra-fast Python package installer and resolver written in Rust. It’s 10-100x faster than pip and provides modern workspace management for our monorepo.
Why UV?
- ⚡ Speed: 10-100x faster than pip
- 🔒 Deterministic: Lock file ensures reproducible builds across all environments
- 🏢 Workspace Support: Unified dependency management for multiple packages
- 🎯 Modern: Uses latest Python packaging standards (PEP 621)
- 🔄 Compatible: Works with existing pip packages and requirements.txt
Quick Start
Installation
# macOS and Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Or using pip
pip install uv
# Or using pipx
pipx install uv
# Windows (PowerShell)
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
Add uv to your PATH (add to ~/.bashrc or ~/.zshrc for persistence):
export PATH="$HOME/.local/bin:$PATH"
Verify installation:
uv --version
First-Time Setup
# Clone the repository
git clone <repository-url>
cd mlops-with-mlflow
# Sync all dependencies (creates .venv and installs everything)
uv sync
# This creates a virtual environment and installs:
# - All workspace dependencies
# - All workspace member packages in development mode
# - Dev dependencies (pytest, ruff, etc.)
That’s it! You’re ready to develop.
Daily Development Workflow
Activating the Environment (Optional)
Most uv commands work without activating the virtual environment, but if you prefer:
# Activate
source .venv/bin/activate # Linux/macOS
.venv\Scripts\activate # Windows
# Deactivate
deactivate
Building and Testing
# Build all packages
make build
# Run all tests
make test
# Build and test everything
make all
# Clean build artifacts and .venv
make clean
Running Python Scripts
# Using uv run (no activation needed)
uv run python my_script.py
# Run pytest
uv run pytest
# Run a specific test file
uv run pytest tests/test_feature.py
# Run with coverage
uv run pytest --cov=src --cov-report=html
Running Commands in Specific Packages
# Navigate to package
cd src/doe-library
# Run tests for just this package
uv run pytest tests/
# Run a script using this package
uv run python -c "import doe_library; print(doe_library.__version__)"
Dependency Management
Adding Dependencies
Root Project Dependencies
# Add a runtime dependency
uv add numpy
# Add with version constraint
uv add "pandas>=2.1.0"
# Add multiple packages
uv add matplotlib seaborn plotly
# Add a development dependency
uv add --dev pytest-mock
# Add from git
uv add git+https://github.com/user/repo.git
Package-Specific Dependencies
# Navigate to the package
cd src/doe-library
# Add dependency to this package
uv add scipy
# Add dev dependency
uv add --dev pytest-benchmark
This updates the package’s pyproject.toml and regenerates uv.lock.
Removing Dependencies
# Remove a dependency
uv remove numpy
# Remove from specific package
cd src/doe-library
uv remove scipy
Updating Dependencies
# Update all dependencies to latest compatible versions
uv sync --upgrade
# Update specific package
uv add numpy@latest
# Update only lock file (don't install)
uv lock --upgrade
Viewing Dependencies
# List installed packages
uv pip list
# Show details about a package
uv pip show mlflow
# Show dependency tree
uv tree
# Show outdated packages
uv pip list --outdated
Working with Workspaces
This project uses uv’s workspace feature to manage multiple Python packages in a monorepo.
Workspace Structure
mlops-with-mlflow/
├── pyproject.toml # Root workspace configuration
├── uv.lock # Locked dependencies (shared by all packages)
├── .python-version # Python version (3.13)
├── .venv/ # Shared virtual environment
└── src/
├── doe-library/ # Workspace member
│ ├── pyproject.toml
│ └── doe_library/
├── io-library/ # Workspace member
│ ├── pyproject.toml
│ └── io_library/
└── ...
Workspace Members
Current workspace members (defined in root pyproject.toml):
src/doe-library- Design of Experiments utilitiessrc/io-library- I/O utilitiessrc/metrics-library- ML metricssrc/feature-library- Feature engineeringsrc/plot-library- Plotting utilitiessrc/hurricane-landfall- Hurricane prediction pipelinesrc/mlflow-tf- MLflow + TensorFlow integration
Adding a New Package to Workspace
- Create the package structure:
mkdir -p src/my-new-package/my_new_package
cd src/my-new-package
- Create
pyproject.toml:
[project]
name = "my_new_package"
version = "0.1.0"
description = "My new package"
requires-python = ">=3.13"
dependencies = [
# Add dependencies here
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
- Add to workspace in root
pyproject.toml:
[tool.uv.workspace]
members = [
"src/doe-library",
# ...existing members...
"src/my-new-package", # Add this line
]
- Sync the workspace:
uv sync
Benefits of Workspaces
- Shared Environment: All packages share the same virtual environment
- Faster Installs: Dependencies are deduplicated across packages
- Consistent Versions: One lock file ensures all packages use compatible versions
- Easy Cross-Package Development: Edit multiple packages simultaneously
- Simplified CI/CD: One command to install everything
Python Version Management
Viewing Available Python Versions
# List all available Python versions
uv python list
# List installed Python versions
uv python list --only-installed
Installing Python Versions
# Install Python 3.13 (if not already installed)
uv python install 3.13
# Install specific version
uv python install 3.13.7
# Install multiple versions
uv python install 3.12 3.13
Pinning Python Version
# Pin to Python 3.13 (creates/updates .python-version)
uv python pin 3.13
# Pin to specific version
uv python pin 3.13.7
The .python-version file is committed to git, ensuring all developers use the same Python version.
Lock File Management
Understanding uv.lock
The uv.lock file:
- Contains exact versions of all dependencies (including transitive ones)
- Ensures reproducible builds across all environments
- Should be committed to version control
- Is automatically updated when you add/remove dependencies
Regenerating Lock File
# Regenerate lock file without installing
uv lock
# Regenerate and sync environment
uv sync
# Upgrade all dependencies and regenerate lock
uv lock --upgrade
Using Lock File in CI/CD
# Install exactly what's in the lock file (fast, reproducible)
uv sync --frozen
# Fail if lock file is out of date
uv sync --locked
Building and Publishing Packages
Building a Package
# Navigate to package
cd src/doe-library
# Build wheel and source distribution
uv build
# Output in dist/
ls -l dist/
# doe_library-0.1.0-py3-none-any.whl
# doe_library-0.1.0.tar.gz
Publishing to PyPI
# Install twine (if not already installed)
uv pip install twine
# Build the package
uv build
# Upload to PyPI
twine upload dist/*
# Upload to Test PyPI
twine upload --repository testpypi dist/*
Advanced Usage
Custom Scripts and Tools
Create scripts in pyproject.toml:
[project.scripts]
my-tool = "my_package.cli:main"
Run with:
uv run my-tool --help
Environment Variables
# Prefer copying over hardlinking (useful for different filesystems)
export UV_LINK_MODE=copy
# Use specific Python version
export UV_PYTHON=3.13
# Custom cache location
export UV_CACHE_DIR=/path/to/cache
# Offline mode (only use cache)
export UV_OFFLINE=1
Using uv with Docker
FROM python:3.13-slim
# Install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
# Copy project files
WORKDIR /app
COPY pyproject.toml uv.lock ./
COPY src/ ./src/
# Install dependencies
RUN uv sync --frozen --no-dev
# Run application
CMD ["uv", "run", "python", "main.py"]
Integration with IDEs
VS Code
Add to .vscode/settings.json:
{
"python.defaultInterpreterPath": ".venv/bin/python",
"python.terminal.activateEnvironment": false,
"python.testing.pytestEnabled": true,
"python.testing.pytestPath": ".venv/bin/pytest"
}
PyCharm
- Go to Settings → Project → Python Interpreter
- Click the gear icon → Add
- Select “Existing environment”
- Choose
.venv/bin/python
Troubleshooting
UV Command Not Found
# Add to PATH
export PATH="$HOME/.local/bin:$PATH"
# Add to shell config for persistence
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Python Version Not Found
# Install the required Python version
uv python install 3.13
# Verify it's available
uv python list --only-installed
Sync Fails
# Clear cache and try again
uv cache clean
uv sync
# Force reinstall
rm -rf .venv
uv sync
Lock File Out of Date
# Regenerate lock file
uv lock
# Then sync
uv sync
Dependency Conflicts
# See conflict details
uv sync --verbose
# Try upgrading conflicting packages
uv sync --upgrade
Package Not Found After Install
# Ensure you're using the uv environment
uv run python -c "import package_name"
# Or activate the environment first
source .venv/bin/activate
python -c "import package_name"
Cross-Filesystem Issues (Hardlink Warnings)
# Use copy mode instead of hardlinks
export UV_LINK_MODE=copy
uv sync
# Or set permanently
echo 'export UV_LINK_MODE=copy' >> ~/.bashrc
Performance Tips
- Use
uv runinstead of activating: Faster and no activation needed - Keep the lock file: Enables very fast installs (10-100x faster than pip)
- Use
--frozenin CI: Skip dependency resolution for maximum speed - Cache is your friend: uv’s cache makes repeated installs instant
- Workspace benefits: Shared dependencies across packages reduce duplication
Comparison with pip/venv
| Task | pip/venv | uv |
|---|---|---|
| Create environment | python -m venv .venv | uv sync |
| Activate | source .venv/bin/activate | Not needed |
| Install deps | pip install -r requirements.txt | uv sync |
| Add package | pip install package | uv add package |
| Remove package | pip uninstall package | uv remove package |
| Run script | python script.py | uv run python script.py |
| Lock dependencies | pip freeze > requirements.txt | Automatic |
| Speed | Baseline | 10-100x faster |
Best Practices
- Always commit
uv.lock: Ensures reproducible builds - Use
uv syncregularly: Keep environment in sync with lock file - Pin Python version: Use
.python-versionfor consistency - Use
uv runin scripts: Ensures correct environment - Clean builds in CI: Use
uv sync --frozenfor reproducibility - Update dependencies intentionally: Use
uv lock --upgradewhen ready - Document custom dependencies: Comment in
pyproject.tomlwhy added
Resources
Getting Help
- Project documentation: See
UV_MIGRATION.md,UV_QUICK_REFERENCE.md - UV issues: https://github.com/astral-sh/uv/issues
- Project team: Open an issue in the project repository