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
anduv 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
anduv.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
(notuv pip install
), asuv pip install
doesn’t useuv.lock
or install dev dependencies by default. - Missing Group: If
--group lint
fails, check that the group exists inpyproject.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
Tool | Dev Dependency Support | Speed | Lockfile | Virtual Env Management |
---|---|---|---|---|
uv | Yes (dependency-groups) | 10-100x faster | uv.lock | automatique |
pip | Limited | Slower | None | Manual |
Poetry | Yes | Moderate | poetry.lock | Manual |
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.