How to Install Python Dev-Dependencies Using uv

Managing dependencies is a core part of Python development, but have you ever wondered how to handle development dependencies specifically—those tools like pytest or ruff that you need for testing and linting but not for production? Enter uv, a blazing-fast Python package and project manager written in Rust that’s revolutionizing how developers manage dependencies. If you’re struggling to figure out how to install Python dev-dependencies with uv, this guide is for you.

In this article, we’ll walk through the process step by step, using a Socratic approach to help you understand why things work the way they do. By asking thought-provoking questions, we’ll guide you to discover solutions and master uv dependency management for your Python projects. Whether you’re a beginner or switching from tools like pip or Poetry, you’ll learn how to use uv to streamline your workflow. Let’s get started!

What Are Python Development Dependencies?

Before diving into uv, let’s clarify what development dependencies are. Unlike production dependencies (e.g., requests or fastapi for your app), development dependencies are packages used during development, such as:

  • Testing tools: pytest, unittest
  • Linters and formatters: ruff, black
  • Documentation tools: mkdocs, sphinx
  • Other utilities: ipython, jupyterlab

These packages aren’t needed when your project runs in production, so they’re kept separate to keep your production environment lean.

Question: Why might it be useful to separate development dependencies from production ones? How could this impact your project’s performance or security?

Why Use uv for Dependency Management?

uv is a modern Python package manager designed to be 10-100x faster than pip and more streamlined than Poetry. It’s built in Rust, which gives it a performance edge, and it supports advanced features like automatic virtual environment management and reproducible lockfiles. Here’s why uv is ideal for Python development dependencies:

  • Speed: Installs dependencies in seconds, even for large projects.
  • Reproducibility: Uses uv.lock to ensure consistent environments across machines.
  • Dependency Groups: Supports [dependency-groups] for organizing dev dependencies.
  • Ease of Use: Commands like uv add and uv sync simplify workflows.

Question: If pip has been the standard for years, what problems might it have that uv aims to solve? How could faster dependency installation improve your development process?

Step 1: Install uv on Your System

Before you can install Python dev-dependencies with uv, you need to install uv itself. Since uv is a standalone binary written in Rust, it doesn’t require Python to run, making installation straightforward.

How to Install uv

  • On macOS/Linux:curl -LsSf https://astral.sh/uv/install.sh | sh
  • On Windows:powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
  • Via pip (if you prefer):pip install uv

After installation, verify it worked:

uv --version

This should output something like uv 0.8.4. If not, check the uv installation documentation for troubleshooting.

Question: Why might a tool like uv not depend on Python, unlike pip? How could this benefit developers working across different environments?

Step 2: Set Up a Python Project with uv

To use uv for dependency management, you need a Python project with a pyproject.toml file. This file defines your project’s metadata and dependencies, replacing the older requirements.txt for modern Python projects.

Create a New Project

Run this command to initialize a project:

uv init my-project
cd my-project

This creates:

  • pyproject.toml: Defines project metadata and dependencies.
  • .python-version: Specifies the Python version (optional).
  • README.md: Basic project documentation.

Your pyproject.toml might look like this:

[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = []

Question: What’s the advantage of using pyproject.toml over requirements.txt for defining dependencies? How might this affect collaboration with other developers?

Step 3: Add Development Dependencies with uv

uv uses the [dependency-groups] table in pyproject.toml to manage development dependencies, as defined in PEP 735. This allows you to organize dev dependencies into groups like dev, lint, or test.

Add a Dev Dependency

To add pytest as a development dependency:

uv add --dev pytest

This updates pyproject.toml to include:

[dependency-groups]
dev = ["pytest>=8.3.4"]

The --dev flag adds the package to the dev group, which is special-cased in uv for development dependencies. You can create other groups with the --group flag, e.g.:

uv add --group lint ruff

This adds ruff to a lint group:

[dependency-groups]
dev = ["pytest>=8.3.4"]
lint = ["ruff>=0.8.2"]

Question: Why might you want to organize dev dependencies into different groups? How could this help in a large project with multiple developers?

Step 4: Install Dev Dependencies with uv sync

To install Python dev-dependencies with uv, use the uv sync command. By default, uv sync installs all dependencies from pyproject.toml, including the dev group, and creates/updates a virtual environment in .venv.

Run:

uv sync

This:

  • Creates a virtual environment (.venv) if it doesn’t exist.
  • Installs production dependencies (from [project.dependencies]).
  • Installs dev group dependencies (e.g., pytest).
  • Updates uv.lock for reproducibility.

Excluding Dev Dependencies

If you only want production dependencies (e.g., for deployment), use:

uv sync --no-dev

Installing Specific Groups

To install only a specific group, like lint:

uv sync --group lint

Or install all groups (including non-dev ones):

uv sync --all-groups

Question: What’s the benefit of a lockfile like uv.lock? How might it prevent issues when sharing your project with others?

Step 5: Verify Your Environment

After running uv sync, activate the virtual environment to test your dependencies:

source .venv/bin/activate  # macOS/Linux
.venv\Scripts\activate      # Windows

Check if pytest is installed:

pytest --version

You should see output like pytest 8.3.4. If not, ensure uv sync ran successfully.

Question: Why is a virtual environment important for development dependencies? What problems might arise if you install dependencies globally?

Step 6: Run Scripts with uv run

uv simplifies running scripts by ensuring the environment is up-to-date. For example, to run a test script:

uv run pytest tests/

uv run automatically:

  • Checks pyproject.toml and uv.lock.
  • Syncs the environment if needed.
  • Runs the command in the project’s virtual environment.

This eliminates the need to manually activate the virtual environment.

Question: How does uv run improve your workflow compared to manually activating a virtual environment? What might happen if your environment isn’t synced with your lockfile?

Step 7: Manage Dependency Groups

For complex projects, you might want multiple dependency groups. For example, create a complete group that includes all other groups:

uv add --group complete pytest ruff jupyterlab

However, uv doesn’t currently support groups depending on other groups directly. Instead, list all dependencies in the complete group or use:

uv sync --all-groups

Example pyproject.toml:

[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = ["fastapi>=0.115.6"]

[dependency-groups]

dev = [“pytest>=8.3.4”] lint = [“ruff>=0.8.2”] complete = [“pytest>=8.3.4”, “ruff>=0.8.2”, “jupyterlab>=4.2.5”]

Question: How might grouping dependencies like complete help in a team setting? What challenges could arise if groups aren’t clearly defined?

Step 8: Handle Platform-Specific Dependencies

Sometimes, dev dependencies are only needed for specific environments (e.g., Python versions or operating systems). Use environment markers in pyproject.toml:

[dependency-groups]
dev = [
  "importlib-metadata>=7.1.0,<8; python_version < '3.10'",
  "colorama>=0.4.6,<5; platform_system == 'Windows'"
]

Then, uv sync installs these dependencies only when the conditions are met.

Question: Why might you need platform-specific dependencies? How could this affect a project deployed across different operating systems?

Step 9: Migrate from Other Tools

If you’re switching from pip or Poetry, uv makes migration easy.

From requirements.txt

Convert a requirements.txt to pyproject.toml:

uv add -r requirements.txt

From Poetry

If you have a poetry.lock and pyproject.toml, run:

uv sync

uv will respect the pyproject.toml and create a uv.lock file. Note that uv sync is equivalent to poetry install for installing exact versions from a lockfile.

Question: What challenges might you face when migrating from Poetry to uv? How could a lockfile help ensure consistency during migration?

Step 10: Troubleshoot Common Issues

Here are common issues when installing dev dependencies with uv:

  • Dependencies Not Installed: Ensure you ran uv sync (not uv pip install), as uv pip install doesn’t use uv.lock or install dev dependencies by default.
  • Missing Group: If --group lint fails, check that the group exists in pyproject.toml.
  • Slow Performance: Ensure you’re using the latest uv version (uv --version). Update with:uv self update
  • VS Code Autocompletion: If imports aren’t recognized, ensure your virtual environment is selected in VS Code (set python.pythonPath to .venv/bin/python).

Question: What might cause a dependency to not install as expected? How could you debug a missing dependency in your environment?

Dependency Management Comparison

ToolDev Dependency SupportSpeedLockfileVirtual Env Management
uvYes (dependency-groups)10-100x fasteruv.lockautomatique
pipLimitedSlowerNoneManual
PoetryYesModeratepoetry.lockManual

Source: Adapted from DataCamp’s UV Guide

FAQs About Installing Python Dev-Dependencies with uv

What’s the difference between uv sync and uv pip install?

uv sync installs dependencies from pyproject.toml and uv.lock, including dev dependencies, ensuring reproducibility. uv pip install is a drop-in replacement for pip install and doesn’t use uv.lock or install dev groups by default.

Can I install multiple dependency groups at once?

Yes, use uv sync --all-groups to install all groups or specify groups like uv sync --group dev --group lint.

How do I update dev dependencies?

Run uv add --dev package_name to update or add a package, then uv sync to update the environment and lockfile.

Does uv work with Docker?

Yes, but use uv sync --no-dev for production containers to exclude dev dependencies. For development, include --all-groups if needed.

Conclusion: Master uv for Python Dev-Dependencies

Installing Python dev-dependencies with uv is fast, intuitive, and powerful, thanks to commands like uv add and uv sync. By organizing dependencies in pyproject.toml and using uv.lock for reproducibility, you can streamline your development workflow and avoid common pitfalls like dependency conflicts. Whether you’re writing tests with pytest or linting with ruff, uv makes managing dev dependencies a breeze.

Try It Now: Create a new project with uv init, add pytest with uv add --dev pytest, and run uv sync. Did it work? Share your experience in the comments!

Resource: Learn more about uv at docs.astral.sh/uv.

Leave a Comment