Overview #
UV is Team Astral’s new tool. It’s written in Rust and aims to replace pip
and pip-tools
, all with extreme speed.
After the publication of Ruff, the team continues with the aim of creating a “Cargo for Python” with this new publication.
UV can be installed in several ways (with pip or standalone) and is compatible with Linux, Windows and macOS. I installed it with the following command:
pip install uv
To use it, simply use the uv
prefix and then one of the following commands:
# Basic command like install, uninstall, freeze, sync, compile
uv pip
# Create a VENV
uv venv
# Clean cache or show cache directory
uv cache
UV benchmark #
Let’s compare UV and VENV/PIP to see how this new solution performs. According to the creators, UV should be around 80x faster than python -m venv
and 7x faster than virtualenv
.
After creating virtual environments with these different tools, I was able to obtain the following results:
In my case, UV is ~15x faster than virtualenv
and ~150x faster than python -m venv
. I then tried installing python packets with UV and PIP to compare speeds:
For packet insertion I find that UV is ~5x faster than pip and ~33x faster then pip
with the UV cache.
Docker image for CI/CD #
Now let’s try to integrate it into our CIs. To do this, I’ll create a modified python image that I’ll then use in my various workflows.
FROM python:3.11-slim
RUN python3 -m pip install --upgrade pip && \
pip3 install uv && \
uv venv && \
. /.venv/bin/activate && \
uv pip install ruff
ENV VIRTUAL_ENV /.venv
ENV PATH /.venv/bin:$PATH
The Dockerfile is quite simple, I base it on a python 3.11 image, upgrade pip, then install UV. I then create a venv with UV, and activate it. Finally, I install the packets I need for my workflows.
Finally, I set the environment variables VIRTUAL_ENV
and PATH
. This allows me to be directly in the venv when using the image. I then build the image and check that it works correctly:
debian@debian:~/dev/images$ docker build -t uv_python .
[...]
debian@debian:~/dev/images$ docker run -it --rm uv_python bash
root@ec910e7ea8eb:/# uv pip install django
Resolved 3 packages in 483ms
Downloaded 3 packages in 584ms
Installed 3 packages in 150ms
+ asgiref==3.7.2
+ django==5.0.2
+ sqlparse==0.4.4
root@ec910e7ea8eb:/# python3
Python 3.11.8 (main, Feb 7 2024, 22:49:54) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>>
After building and testing the image with a docker run, I can confirm that the image works correctly and is usable in my various CIs.
In addition to this image, we can set the cache for UV in Workflow. For Gitlab, I use the following configuration:
[...]
variables:
UV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/uv"
cache:
- key: uv-pip-cache
paths:
- $CI_PROJECT_DIR/.cache/uv
[...]
After a few, I’ve noticed that the cache can be useful in some situations (especially if you have a very good machine) but can also slow down the CI in others. In some situations, UV is faster than Gitlab’s cache compression/decompression. In particular, I’ve seen it slow down runners using HDDs.
I suggest you test with and without to see which is faster.
Conclusion #
UV is a very promising tool, in line with what Team Astral has to offer. In my opinion, it can already be deployed in production, and therefore saves a great amont of time, especially for repeat installations (e.g. CI). The speed of this tool even calls into question some current time-saving options, such as the CI cache.
It’s worth noting that, despite the objective of being a “drop-in replacement for pip”, it currently lacks features that could be blocking in certain situations: