<- VOLVER AL ARCHIVO
EN

Uv pacakage manager

IDEAS / CÓDIGO / PROCESO *

UV

uv is a tool for working with Python projects and packages.

It can perform tasks for which we would normally use other tools:

pip, venv, pip-tools.

With uv we can:

  • create virtual environments
  • install packages
  • install a project's dependencies
  • resolve version conflicts
  • save exact dependency versions
  • run commands within the project environment

Pip and uv

pip is the Python package installer:

pip install numpy

You can also install a project's dependencies:

pip install

uv can also work as a package installer in the same way as pip by using (this does not mean it is installed through pip; you are only telling uv to “behave like pip”):

uv pip install numpy

But it also has its own commands that let you manage a complete project:

uv sync

In other words, uv has two operating modes:

uv
│
├── Pip-like mode
│
│   uv pip install
│   uv pip uninstall
│   uv pip list
│   uv pip freeze
│
└── Project management mode
    │
    uv sync
    uv lock
    uv add
    uv remove
    uv run

Differences

| PIP | UV | | --- | --- | | Installs packages | Installs packages | | Resolves dependencies | Resolves dependencies | | Can INSTALL from pyproject.toml | Can work directly with pyproject.toml | | Usually combined with venv | Can create the virtual environment directly (venv) | | Does not use uv.lock | Can use uv.lock | | Focused on installing packages | Focused on managing a complete project |

Advantages of uv

More tools in a single program

With pip:

python3 -m venv .venv
source .venv/bin/activate
pip install .

With uv:

uv venv
uv pip install .

Faster dependency resolution

uv is designed to perform tasks such as:

  • resolving dependencies
  • downloading packages (including private Forgejo packages)
  • installing packages

image.png

Chart taken directly from the Astral website (it may be exaggerated).

Project management

uv can work directly with:

pyproject.toml
uv.lock
.venv/

Example:

uv sync

This synchronizes the environment with the project's dependencies. It automatically creates the uv.lock file; if it already exists, uv updates it when necessary.

Dependency lock file (uv.lock)

The uv.lock file stores the resolved dependencies of the project.

While pyproject.toml specifies dependencies broadly, this can allow incompatible versions. For example, if we specify “numpy≥2.0” and another package we depend on uses “numpy=2.2”, in practice versions 2.0 and 2.1 are not valid even though pyproject.toml accepts them.

uv.lock stores the exact dependencies that do work (not just one dependency; there can be several versions).

For the previous example, uv's resolver would detect the correct version and install it directly.

If we had something like “numpy==2.0” and the other package required “numpy>2.1”, this would be a direct version conflict and would have to be corrected manually.

Errors with Python versions

uv also checks that dependencies are compatible with all Python versions that the project claims to support.

Supported Python versions are specified in pyproject.toml with:

requires-python = ">=3.10"

This indicates that our project must be able to work with Python 3.10, 3.11, 3.12, and so on.

One of our dependencies may have more restrictive requirements. For example:

Our project:
Python >= 3.10

astropy >= 7.2:
Python >= 3.11

In this case there is a conflict.

Even if we are running uv sync using Python 3.11, uv detects that our project also declares compatibility with Python 3.10 and that the dependencies cannot be resolved for that version.

How to solve it

We need to check the actual minimum Python version supported by our project.

If our project really needs Python 3.11 or later, we must change:

requires-python = ">=3.10"

to:

requires-python = ">=3.11"

This correctly indicates:

Project:
Python >= 3.11

Dependency:
Python >= 3.11

In these cases, we should mainly review:

requires-python = "..."

and verify that the Python range we declare is compatible with the project's dependencies.

Disadvantages of uv

Learning new commands

If we are used to pip, it will feel strange at first to distinguish between:

uv pip install

and:

uv sync

uv can detect problems that did not appear before

This may sound like an advantage, but in reality, seeing version errors in a project that did not have them before can make us think uv is a bad tool or that it has bugs, when they are actually our fault.

Example, in pyproject.toml:

requires-python = ">=3.10"

and another dependency:

Python >=3.11

As explained earlier, this can cause an error when resolving the project.

Switching from pip to uv can change version resolution

If versions are declared broadly, such as “numpy≥1.26”, a new installation may select a more recent version (which, most of the time, will not be a major problem).

COMMANDS

Installation

As simple as:

curl -LsSf https://astral.sh/uv/install.sh | sh

Create a virtual environment

With Python, we would normally use:

python3 -m venv .venv

With uv:

uv venv

To choose a specific Python version:

uv venv --python python3

Then activate it as usual:

source .venv/bin/activate

Use uv as if it were pip

This is the simplest option if we have just switched to uv.

Install a package

uv pip install numpy

Install a specific version

uv pip install numpy==2.2.6

Install the current project

uv pip install .

Install the project with extras

uv pip install ".[private]"

Use uv as a project manager

uv sync synchronizes the project's dependencies with the environment (creating or updating the lock file).

If we want an extra (optional dependencies), we use:

uv sync --extra private

uv add adds a dependency to the project, for example:

uv add numpy

uv remove removes a dependency from the project:

uv remove numpy

uv run runs a command using the project's environment:

uv run python main.py