Pipenv to UV
Posted on 12 April 2025 in Technology
I have been (mostly) happily using Pipenv for many years now on all of my Python projects. Recently, I heard about UV so I'm giving it a try with the very small set of Python dependencies used for this blog.
Installation
I'm also moving to using a devcontainer for this blog's dependencies so for installation I'm just using the devcontainer UV feature. Then I install the Python version I want to use (3.12 here):
0 1 2 | uv python install 3.12 Installed Python 3.12.10 in 5.25s + cpython-3.12.10-linux-x86_64-gnu |
And initial my project:
0 1 | uv init Initialized project `chris-wells.net` |
This adds a .python-version file to the repo to specify the default Python version, a main.py (which is this case I delete), a pyproject.toml file with project information, and an empty README.md.
Then, I instally my short list of requirements currently in the Pipfile.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | $ uv add pelican markdown pelican-youtube Using CPython 3.12.10 interpreter at: /usr/local/bin/python3.12 Creating virtual environment at: .venv Resolved 24 packages in 564ms Prepared 22 packages in 4.34s ░░░░░░░░░░░░░░░░░░░░ [0/22] Installing wheels... warning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance. If the cache and target directories are on different filesystems, hardlinking may not be supported. If this is intentional, set `export UV_LINK_MODE=copy` or use `--link-mode=copy` to suppress this warning. Installed 22 packages in 72ms + anyio==4.9.0 + blinker==1.9.0 + docutils==0.21.2 + feedgenerator==2.1.0 + idna==3.10 + jinja2==3.1.6 + markdown==3.8 + markdown-it-py==3.0.0 + markupsafe==3.0.2 + mdurl==0.1.2 + ordered-set==4.1.0 + pelican==4.11.0 + pelican-youtube==0.3.0 + pygments==2.18.0 + python-dateutil==2.9.0.post0 + pytz==2025.2 + rich==14.0.0 + six==1.17.0 + sniffio==1.3.1 + typing-extensions==4.13.2 + unidecode==1.3.8 + watchfiles==1.0.5 |
This command installs the requirements and their dependencies, updates the pyproject.toml file, and adds a uv.lock file to lock the specific dependency versions.
Since speed is a big focus of UV the warning message interested me. This is a teeny project and the performance of UV isn't relevant, but I figured it was worth learning about. After following the documentation at Using uv in Docker I ended up adding some configuration to my DevContainer Dockerfile:
0 1 2 3 4 5 6 7 8 | # Install UV # See: https://docs.astral.sh/uv/guides/integration/docker/#installing-uv # See: https://docs.astral.sh/uv/guides/integration/docker/#caching ADD https://astral.sh/uv/install.sh /uv-installer.sh ENV UV_INSTALL_DIR="/home/$USERNAME/.local/bin/" RUN sh /uv-installer.sh && rm /uv-installer.sh ENV PATH="/home/$USERNAME/.local/bin/:$PATH" ENV UV_LINK_MODE=copy RUN --mount=type=cache,target="/home/$USERNAME/.cache/uv" |
This change tells UV to use the less efficient "copy" link mode but it does so on a Docker cache volume to improve speed.
Running Code
Now that UV is installed and configured I'll try running something:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | uv run pelican [16:40:54] ERROR Cannot load plugin `pelican_youtube` Cannot import plugin `pelican_youtube` [16:40:55] ERROR Could not process articles/2017/aoc-2017/05-days-16-20.rst /workspaces/chrxs.net/content/articles/2017/aoc-2017/05-days-16-20.rst:159: (ERROR/3) Unknown directive type "youtube" .. youtube:: _cZC67wXUTs WARNING Unable to find '05-days-16-20.rst#day-16-one-billion-permutations-in-0-535-seconds', skipping url replacement. WARNING Unable to find '05-days-16-20.rst#day-17-collections-deque', skipping url replacement. WARNING Unable to find '05-days-16-20.rst#day-18-negative-numbers-and-str-isdigit', skipping url replacement. WARNING Unable to find '05-days-16-20.rst#day-19-the-internet-is-not-a-big-truck', skipping url replacement. WARNING Other resources were not found and their urls not replaced Done: Processed 19 articles, 1 draft, 0 hidden articles, 2 pages, 0 hidden pages and 0 draft pages in 1.11 seconds. |
Mostly good! It looks like in the 2+ years since I have updated this blog and used Pelican the pelican_youtube plugin is not working.
This turns out to be because Pelican 4.5 introduced support for plugin autodiscovery so I solved this by removing the PLUGIN_PATHS and PLUGINS settings from my pelicanconf.py.
With that corrected I'm now able to get a happy build with the latest version of Pelican!
0 1 | uv run pelican Done: Processed 20 articles, 1 draft, 0 hidden articles, 2 pages, 0 hidden pages and 0 draft pages in 1.07 seconds. |
And I can run the listen server also via UV:
0 1 2 3 | uv run pelican --autoreload --listen --- AutoReload Mode: Monitoring `content`, `theme` and `settings` for changes. --- Serving site at: http://127.0.0.1:8000 - Tap CTRL-C to stop Done: Processed 20 articles, 1 draft, 0 hidden articles, 2 pages, 0 hidden pages and 0 draft pages in 0.99 seconds. |