How to use uv: A superfast Python package installer

Of all the criticisms leveled at Python, one of the most valid—and unfortunately long-lived—is the chaotic state of its packaging ecosystem. It’s less of a mess than it used to be, as so memorably illustrated by XKCD, but it’s still hardly ideal. Third parties such as poetry and pipenv have filled the gaps by offering tools that are built atop Python’s existing standards but designed around more elegant workflows.

Now we have uv, the newest addition to the Python package installer ecosystem. Created by Astral, the same team maintaining the ruff Python linting tool, uv aims to be an all-in-one replacement for pip, venv, and many other command-line project management tools for Python. Unlike other Python project managers, uv is written primarily in Rust, which is intended to make it faster than other tools in its class, potentially by orders of magnitude.

Setting up uv and working with venvs

There are a few different ways to install uv. A common and easy way to get started is to use pip to install uv into an underlying Python installation. If that Python installation is in the system PATH, you can invoke uv by just typing uv at the command line.

Once you have uv installed, you can create a virtual environment in a given directory with the command uv venv. If you don’t supply a directory name yourself, the venv will be created in the directory .venv.

The venv uv creates will behave exactly like a regular virtual environment, with a couple of minor changes. You activate the venv the same way you would a regular one—e.g., source .venv/bin/activate on Linux/macOS, or .venv\Scripts\activate on Microsoft Windows.

However, the venv uv creates will not have pip or setuptools installed by defaut. For a uv-managed project, you are expected to use uv‘s management tools whenever possible.

Using pip with uv

uv maintains its own version of pip, which you access explicitly through uv. The commands are the same:

uv pip install flask

uv supports the vast majority of common pip behaviors, like editable installs, optional component selection (e.g., uv pip install "flask[dotenv]"), or installing from a git source.

A few behaviors aren’t supported yet, but these should not interfere with your day-to-day work. Some things are notably different, however.

Using ‘uv pip’ with git

If you want to install a requirement from a git repository or GitHub, note that you’ll need to use a slightly different syntax than you would with pip alone. You will need to specify the name of the package to install, @, and then the source:

uv pip install "<package_name> @<user>/<repo>"

Note the quotes, which are needed to escape the @ properly. You also will need to pass special syntax to use authentication with git links.

Using ‘uv pip freeze’ instead of ‘pip list’

To list what’s installed in a given venv, use uv pip freeze instead of uv pip list. The results can be redirected to a file as one normally would with pip freeze.

Locking, compiling, and syncing dependencies

uv provides several features for locking and synchronizing dependencies with a project’s requirements list.

When you use uv pip freeze, the resulting list will have explicit version requirements for each package, meaning it will be “locked” to the specific versions in question.

If you want to take an existing pyproject.toml or file and generate a locked dependency set as requirement.txt, use:

uv pip compile pyproject.toml -o requirements.txt
# or ...
uv pip compile -o requirements.txt

Using pip-compile and pip-sync with uv

uv‘s long-term goal is to provide alternatives for multiple Python tools. Two of the tools uv can currently replace, although in a primordial way, are pip-compile and pip-sync.

pip-sync takes a project’s virtual environment and synchronizes its package set with a provided list of packages, typically a requirements.txt file. With uv, to bring a project’s installed dependencies in sync with a list of locked dependencies, in the same manner as pip-sync tool, use:

uv pip sync requirements.txt

The pip-compile tool generates a file, which lists “locked” dependencies, from an existing pyproject.toml or requirements.txt file:

uv pip compile .\pyproject.toml -o

This saves a version-locked list of dependencies listed in pyproject.toml into, which can then be used to restore requirements that match a specific configuration.

The limitations of uv

The uv project is still in its early stages, so it doesn’t yet support the full range of intended functionality. Many features are incomplete (although they’re documented as such), and many more are slated to be added later.

Another issue for uv is being written in Rust—which is of course also one of its strengths. Being written in Rust makes uv fast and efficient, but could also make contributing back to it difficult for Python users. A Python developer who wants to contribute to Python tools needs mostly to learn the particular process for contributing to the project. But a Python developer who wants to contribute back to uv, or any other Python tool written in Rust, needs to learn Rust as well.

Because writing Python tools in Rust is still a relatively new phenomenon, it isn’t clear how much impact it will have on how Python developers contribute to such projects. But it’s clear Rust is becoming a valid choice for writing Python tools, if only for the sake of putting performance first.

Copyright © 2024 IDG Communications, Inc.

Source link