Mastering Python Project Management with uv: Part 2 — Deep Dives and Advanced Use

Thomas Bury
4 min readOct 5, 2024

--

Welcome back! If you haven’t checked out Part 1, now’s the time to do so. We covered how `uv` simplifies managing dependencies, creating virtual environments, Python versions, and inline metadata. Now, let’s go deeper into the magic of `uv` and explore its advanced features that can take Python development to the next level.

— -

1. How `uv` Manages Dependencies with `pyproject.toml`

In Part 1, we briefly touched on adding dependencies to your Python project using `uv`. Let’s expand on how `uv` integrates tightly with `pyproject.toml`, which is the standardized format for Python project configurations.

The `uv add` Command & `pyproject.toml`
When you use the `uv add` command, `uv` automatically updates your `pyproject.toml` file. This file contains all your project metadata, including dependencies. Think of it as the central brain of your project. Here’s an example:

uv add fastapi

Your `pyproject.toml` file will then reflect this change and `uv` resolves dependencies automatically (versions for illustrative purposes):

[tool.uv.dependencies]
fastapi = ">=0.68,<1.0"

This makes your dependencies explicit and your project easily shareable with others. Whenever you or someone else clones your project, simply running `uv` will install the same packages listed.

Version Pinning & Constraints
One of `uv`’s strengths is that it makes managing exact package versions easy. You can pin specific versions directly in the `pyproject.toml` file or set version ranges:

[tool.uv.dependencies]
flask = "==2.0.1"

This prevents any surprises from version mismatches and ensures stability.

Extras and Optional Dependencies
Need optional packages that not all users will require? You can easily declare these in your `pyproject.toml`:

[tool.uv.dependencies]
fastapi = { version = ">=0.68,<1.0", extras = ["all"] }

Install the optional extras whenever needed:

uv add fastapi[all]

This modular approach keeps your project flexible and avoids unnecessary bloat.

— -

2. Locking Dependencies with the `uv.lock` File

Whenever you add or update dependencies using `uv`, it doesn’t just modify your `pyproject.toml` file. `uv` also creates a `uv.lock` file. Why is this important?

- Precise Versioning: The `uv.lock` file locks in the exact versions of all dependencies and their transitive dependencies (packages that your dependencies rely on).
- Reproducible Environments: Whether it’s you coming back to a project after a break or a colleague cloning your repo, running `uv` will install the exact versions specified in the `uv.lock` file.

The result? A consistent, reliable environment that eliminates the “it works on my machine” problem.

— -

3. Managing Tools: Global vs. Project-Specific

In Part 1, we discussed how `uv` makes it easy to install CLI tools. Now, let’s break down how `uv` distinguishes between **global** and **project-specific** tools.

Installing Global Tools
Installing a tool globally with `uv` is simple:

uv tool install black

This makes `black` available across all your projects but keeps it in its isolated virtual environment, avoiding system-wide conflicts.

Project-Specific Tools
If you need a tool for a specific project, add it directly as a dependency:

uv add ruff

This keeps the tool local to your project and listed in your `pyproject.toml`. Your other projects remain unaffected, allowing for isolated development environments.

Running Tools Ephemerally with `uvx`
For quick, one-off tool usage without permanently installing it, `uvx` is your friend:

uvx black my_script.py

This runs `black` within a temporary virtual environment and then cleans up afterward. It’s like `pipx`, but faster and tightly integrated with `uv`.

— -

4. Creating & Using Virtual Environments the Right Way

Making Virtual Environments Easy
In Part 1, we explained how `uv` defaults to using virtual environments for all package installations. Here’s a quick recap:

uv venv

This command creates a `.venv` directory in your project. If you want to use a custom directory or Python version:

uv venv my_venv - python 3.11

You can then activate your virtual environment as you normally would:
`$ .venv/Scripts/activate`

Automatic Environment Detection
Whenever you work on a project managed by `uv`, the tool will automatically detect and use the appropriate virtual environment without any additional setup. No need to worry about manually activating or deactivating environments.

— -

5. `uv` and Existing Environments

Already using another environment manager like `conda`? No problem. `uv` is built to play nicely with external virtual environments.

Automatic Environment Detection & Integration
When you use `uv pip install` or `uv add`, `uv` searches for existing virtual environments:
1. Activated environments (e.g., `VIRTUAL_ENV` or `CONDA_PREFIX`).
2. A `.venv` directory in your current project.

If `uv` doesn’t find a virtual environment, it will prompt you to create one to keep your environment clean and isolated.

— -

6. `uv` vs. `conda`: When to Use What?

`uv` handles almost all your Python package and environment needs quickly and efficiently. However, if your project has non-Python dependencies (like system-level packages) or requires multi-language support (e.g., Python and R), `conda` might still be a better choice.

For pure Python workflows, `uv` is often a faster and more flexible alternative, simplifying the management of virtual environments and dependencies.

— -

`uv` provides an all-in-one solution for managing Python dependencies, environments, and tools. By combining speed, reproducibility, and simplicity, it aims to make your Python workflow more efficient than ever.

So whether you’re starting a new project, working with multiple Python versions, or managing complex dependencies — `uv` has you covered.
Although there is still a gap to fill, the `conda` integration. `Pixi` + `uv` could be the awaited python manager to rule them all.

Try it today, and see how it transforms your Python development process. 🚀

— -

If you haven’t read Part 1, check it out [here](https://dev.to/thomas_bury_b1a50c1156cbf/mastering-python-project-management-with-uv-part1-its-time-to-ditch-poetry-3bi0) to get an overview of how `uv` can supercharge your Python projects. Happy coding! 🐍✨

For full details and documentation, check out the official [`uv` docs](https://docs.astral.sh/uv).

--

--

Thomas Bury

Physicist by passion and training, Data Scientist and MLE for a living (it's fun too), interdisciplinary by conviction.