21.05.2025

The dependency inferno

A descent into the Python packaging hell

⚡ Lightning Talk ⚡

Sunniva Indrehus

autodesk$ echo $(whoami)

The Python dependency hell

Short 🐍 📦 history

  • 1991 Python 1.0 released (Guido van Rossum)
  • 2004 setuptools (Phillip Eby) — Packaging foundation
  • 2007 virtualenv (Ian Bicking) - Isolating environments
  • 2008 Python 3.0
  • 2011 pip bundled with Python - Standardizing the installer
  • 2012 conda (Anaconda Inc.) and venv (Vinay Sajip)
  • 2015 PEP 517 - Build system interface
  • 2016 PEP 518 - Build dependencies declaration
  • 2017 pipenv (PyPA-backed) - Unified env & deps
  • 2018 poetry (S. Eustace) - All-in-one manager
  • 2019 hatch (Ofek)
  • 2020 PEP 621 - Metadata, PDM (Frost Ming)
  • 2024 uv (Astral)
  • 1991 Python 1.0 released (Guido van Rossum)
  • 2004 setuptools (Phillip Eby) — Packaging foundation
  • 2007 virtualenv (Ian Bicking) - Isolating environments
  • 2008 Python 3.0
  • 2011 pip bundled with Python - Standardizing the installer
  • 2012 conda (Anaconda Inc.) and venv (Vinay Sajip)
  • 2015 PEP 517 - Build system interface
  • 2016 PEP 518 - Build dependencies declaration
  • 2017 pipenv (PyPA-backed) - Unified env & deps
2018 poetry (S. Eustace) - All-in-one manager
2024 uv (Astral)

UV

  • Ultra-fast Python package manager and resolver
  • Drop-in replacement for pip, pip-tools, and parts of Poetry
  • Cross-platform Python installation (😱 No pyenv! 😱 )
  • Lock file is cross-platform
Cute kitten
Time for installing Trio's dependencies with warm cache, Figure credit: Astral's docs

Basic API

Install uv

~$ curl -LsSf https://astral.sh/uv/install.sh | sh
~$ uv 
An extremely fast Python package manager.

Usage: uv [OPTIONS] <COMMAND>

Install latest python version

~$ uv python install
~$ uv python install 3.12
~$ uv python install pypy@3.10

Start a packaged project

Create

~$ uv init --package test-uv-package
~test-uv-package$ ls 
├── .git
├── .gitignore
├── .python-version
├── README.md
├── pyproject.toml
├── src
│   ├── test_uv_package
│     └── __init__.py

Run

~test-uv-package$ uv run test-uv-package
  Using CPython 3.13.3
  Creating virtual environment at: .venv
  Hello from test-uv-package!

Plain dependency migration

~my-project$ uvx migrate-to-uv
Installed 1 package in 16ms
Locking dependencies with "uv lock"...
Using CPython 3.12.4 interpreter at: /Users/sunnivaindrehus/.pyenv/versions/3.12.4/bin/python3.12
Resolved 123 packages in 1.01s
Successfully migrated project from Poetry to uv!

Complex dependency migration

  1. Make sure to capture all dependencies (use the right poetry version, and all relevant groups)

    ~/repo$ poetry@1.8 export -f requirements.txt --output requirements.txt --without-hashes --with dev
    
  2. Remove pyproject.toml and poetry.lock files.

    ~/repo$ uv init --bare
    
  3. Install locked dependencies from .txt file

    ~/repo$ uv add -r requirements.txt
    

Private packages migration

Poetry 1.8

SCP-like shorthand

[tool.poetry.dependencies]
python = ">=3.11,<3.12"
my-private-package = { git = "git@github.com:my-org/my-private-package.git", tag = "1.0.1" }

uv

Explicit URL schemes

[project]
requires-python = ">=3.11,<3.12"
dependencies = [
    "my-private-package"
  ]

[tool.uv.sources]
"my-private-package" = {git= "ssh://git@github.com:my-org/my-private-package.git", rev="34f59994bb920679ba5f0cade8061e0da7ca00b5"}

Poetry 2.X vs. UV

# Start a project Create project ``` ~$ uv init test-uv ~test-uv$ ls ├── .git ├── .gitignore ├── .python-version ├── README.md ├── main.py ├── pyproject.toml ``` Run example script ``` ~test-uv$ uv run main.py Using CPython 3.13.3 Creating virtual environment at: .venv Hello from test-uv! ``` ---