uv#

The uv tool is a Python package and project manager written in Rust. Even though the first version was only released in February of 2024, its feature set is growing rapidly, just like its popularity inside the community. In case you can only bring a single tool to a remote island, pick uv.

The features illustrate how uv is designed to be a single command that can replace various other tools, including pip, pipx, pipenv, poetry, pyenv, venv and more. A lot of effort has been put in optimizing for speed, starting from how it downloads package metadata and resolves dependencies, to how it caches the packages in a central location and then reflinks them into the individual venvs.

Usage#

Installation#

There are various ways to install uv. Given the project’s huge development speed, new versions of uv are published every couple of days. Especially when hitting a possible bug, make sure to first upgrade to the latest version.

$ uv self update

Python#

Without any Python installed you can bootstrap your host by simply downloading the binary from the upstream releases, as uv can then even install Python for you. This also works without any admin rights, as the pre-compiled Python binaries are installed within the user’s home.

$ uv python list    # show available python versions (incl system-wide)
$ uv python dir     # show path to uv python installation directory
$ uv python install <ver>   # install given python version

Note however that this will not replace the full freedom and on-demand optimization of pyenv. The installation of Python takes a couple of seconds, but depending on your problem, you may lose a few percent in performance due to missing optimizations. Especially on HPC clusters the provided Python installations should always be preferred, as they often include tailored optimizations.

Projects#

The concept of Python project basically refers to whenever you write your own code and need to manage its dependencies. In order to use uv, start by creating a minimal pyproject.toml (as motivated by PEP 518).

[project]
name = "samplename"
version = "0.1.0"
description = "Add your description here"

Then add dependencies as needed,

$ uv add pandas

where each package will be automatically added to the pyproject.toml, installed inside a new venv and tracked with all its dependencies inside the cross-platform uv.lock. The latter is an extended version of the pip freeze output and precisely tracks the versions of all installed dependencies. This file is the key to recreating exactly the same environment on a different machine for full reproducibility.

Tip

Always add pyproject.toml and uv.lock to your version-control system. Not only does it help your collaborators to use the same package versions, but it also tracks all package updates in the git history.

You can also flag dependencies with --dev as only required for development, but not for production. Command-line tools, like linter, can directly be run from inside the venv using uv run.

$ uv add --dev ruff
$ uv run ruff check

Your collaborators can then clone the repo and call uv sync to install all package versions exactly as defined in the uv.lock file, independently of the operating system they are working on.

$ uv sync --frozen --extra=dev

The dependencies inside an existing uv.lock can be upgraded on-demand.

$ uv lock --upgrade                 # resolve project deps allowing package upgrades
$ uv lock --upgrade-package <pkg>   # upgrade given package (and its deps as required)

The pip interface helps to run pip-like commands inside the venv.

$ uv pip list             # list installed packages
$ uv pip freeze           # list installed packages in requirements format
$ uv pip tree             # show dependency graph of installed packages
$ uv pip check            # check for package conflicts of missing deps

Note that, in contrast to normal pip, uv does not pre-compile bytecode when installing a package. Even though this speeds up the installation, the first run of the software might be slightly slower, as the .pyc will then be generated on-the-fly. Especially when working with containers or read-only environments, keep in mind to generate the bytecode in advance.

$ uv pip install --compile-bytecode <pkg>   # install given package and pre-compile bytecode

More advanced tricks let you even install and run tools, without having to modify the project dependencies or its venv. The following allows to quickly test the black formatter on a given file, without it ever being installed inside the project’s virtual environment.

$ uv run --with black black main.py

Tools#

Conceptually a Python tool is any package that provides a command-line interface. The motivation to manage such tools differently was already provided when discussing pipx and the usage is also similar.

$ uv tool install ruff    # install given command-line tool inside dedicated venv
$ uv tool run ruff check  # run given command-line tool
$ uv tool install --with ansible-lint ansible   # install tool and extra dep inside same venv
$ uv tool list            # show list of installed tools
$ uv tool upgrade ruff    # upgrade tool to latest version
$ uv tool update-shell    # add ~/.local/bin to $PATH to make all tools directly callable

Cache#

Given that uv aggressively caches already downloaded packages, you may occasionally want to inspect and drop the cache.

$ uv cache dir            # show path to cache directory
$ uv cache prune          # delete unused cache files
$ uv cache clean <pkg>    # delete given package from cache
$ uv cache clean          # delete all packages from cache