cat posts/uv-python-paketmanager.md
uv: pip und venv in schnell
uv bündelt Paketinstallation, virtuelle Umgebungen, Projektverwaltung, Python-Versionen und isolierte Tools – schnell, reproduzierbar und mit modernen Workflows für pyproject.toml und uv.lock.
In Teil 10 der Python-Serie
haben wir venv und pip kennengelernt:
python -m venv .venv
source .venv/bin/activate
python -m pip install rich
Das ist der klassische Weg, Python-Projekte mit eigenen Abhängigkeiten zu verwalten. Er funktioniert und ist wichtig zu verstehen.
Im Alltag stößt dieser Werkzeugkasten aber schnell an Grenzen:
venvlegt die Umgebung an.pipinstalliert Pakete.pip-toolsoder ähnliche Werkzeuge erzeugen reproduzierbare Lockfiles.pipxinstalliert Kommandozeilen-Tools isoliert.pyenvoder andere Tools verwalten Python-Versionen.- In der CI muss alles wieder korrekt zusammengesetzt werden.
uv bündelt viele dieser Aufgaben in einem einzigen Werkzeug.
Es ist ein eigenständiges, in Rust geschriebenes Programm von Astral, den Leuten
hinter Ruff. uv ist sehr schnell, arbeitet mit
pyproject.toml, erzeugt eine Lockdatei und kann auf Wunsch auch
Python-Versionen und isolierte Tools verwalten.
Was uv ist
uv ist ein moderner Python-Paket- und Projektmanager.
Es kann unter anderem:
- virtuelle Umgebungen anlegen,
- Pakete installieren,
- Projekte über
pyproject.tomlverwalten, - eine reproduzierbare
uv.lockerzeugen, - Abhängigkeiten synchronisieren,
- Python-Versionen installieren und pinnen,
- Tools isoliert ausführen,
- einzelne Skripte mit eigenen Abhängigkeiten starten.
Dabei ersetzt uv nicht die Python-Sprache, nicht die Standardbibliothek und
nicht Dein Verständnis von venv und pip.
Besser formuliert:
uv übernimmt viele Aufgaben, für die man klassisch
pip,venv,pipx,pip-toolsund teilweisepyenvkombiniert hat.
Du solltest die alten Begriffe trotzdem kennen, weil sie in Dokumentationen, Fehlermeldungen und bestehenden Projekten weiterhin häufig auftauchen.
Warum uv so schnell ist
uv ist in Rust geschrieben und darauf ausgelegt, viele Schritte zu parallelisieren und zu cachen.
Das betrifft unter anderem:
- Auflösen von Abhängigkeiten,
- Herunterladen von Paketen,
- Wiederverwenden bereits geladener Wheels,
- Erstellen und Synchronisieren von Umgebungen.
Für kleine Lernprojekte ist der Unterschied nett. Für größere Projekte, CI-Pipelines oder häufig neu erzeugte Umgebungen kann er deutlich spürbar sein.
Der wichtigste Vorteil ist aber nicht nur Geschwindigkeit.
uv bringt mehrere bisher getrennte Arbeitsschritte in einen konsistenten Workflow:
uv add rich
uv run python main.py
uv sync
Du musst eine virtuelle Umgebung oft nicht mehr manuell aktivieren, weil uv run
das passende Projekt-Environment automatisch verwendet.
uv installieren
uv ist ein eigenständiges Programm. Es wird nicht zuerst in eine bestehende virtuelle Umgebung installiert.
Die offizielle Installationsmethode unter Linux und macOS ist beispielsweise:
curl -LsSf https://astral.sh/uv/install.sh | sh
Unter Windows PowerShell:
irm https://astral.sh/uv/install.ps1 | iex
Je nach Betriebssystem kannst Du uv auch über Paketmanager installieren.
Prüfe danach die Installation:
uv --version
Die Ausgabe sieht ungefähr so aus:
uv 0.x.y
Die genaue Versionsnummer hängt davon ab, wann Du uv installiert oder aktualisiert hast.
Zwei Arbeitsweisen
uv kann in zwei verschiedenen Stilen verwendet werden.
1. Der pip-kompatible Stil
Wenn Du schon einen klassischen venv- und pip-Workflow kennst, kannst Du mit
uv ähnlich arbeiten:
uv venv
uv pip install rich
Das legt eine virtuelle Umgebung an und installiert rich.
Diese Kommandos sind besonders nützlich, wenn Du ein bestehendes Projekt mit
requirements.txt hast oder uv zunächst als schnellen Ersatz für einzelne
pip-Befehle verwenden möchtest.
2. Der Projektstil
Der modernere uv-Workflow verwendet ein Projekt mit:
pyproject.toml.venvuv.lock
Typische Kommandos sind dann:
uv init
uv add rich
uv run python main.py
uv sync
Dieser Artikel konzentriert sich vor allem auf den Projektstil, weil er die Stärken von uv am besten zeigt.
Ein neues Projekt anlegen
Lege ein neues Projekt an:
uv init mein-projekt
Wechsle in den Ordner:
cd mein-projekt
uv erzeugt eine einfache Projektstruktur, unter anderem mit einer
pyproject.toml.
Je nach uv-Version und gewählter Vorlage kann die Struktur leicht variieren. Typisch ist aber ein Startpunkt wie:
mein-projekt/
├── README.md
├── main.py
└── pyproject.toml
In der pyproject.toml stehen Projektmetadaten und Abhängigkeiten.
Ein stark vereinfachtes Beispiel:
[project]
name = "mein-projekt"
version = "0.1.0"
description = "Ein kleines Python-Projekt"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
Ein Paket hinzufügen
Installiere rich als Abhängigkeit:
uv add rich
uv erledigt dabei mehrere Dinge:
- Es trägt
richin diepyproject.tomlein. - Es erzeugt oder aktualisiert die Lockdatei
uv.lock. - Es erstellt bei Bedarf eine
.venv. - Es installiert die Abhängigkeiten in diese Umgebung.
Danach enthält die pyproject.toml ungefähr:
[project]
dependencies = [
"rich>=14.0.0",
]
Die genaue Versionsangabe kann anders aussehen, abhängig vom aktuellen Paketstand.
Code im Projekt ausführen
In main.py kannst Du rich verwenden:
from rich import print
print("[bold green]Willkommen im Dungeon![/bold green]")
Starte das Programm mit:
uv run python main.py
Oder kurz:
uv run main.py
Wenn main.py eine Python-Datei ist, behandelt uv sie als Skript und startet sie
mit dem passenden Python.
Der wichtige Punkt:
uv runführt den Code in der passenden Projektumgebung aus.
Du musst die .venv nicht vorher manuell aktivieren.
Warum nicht einfach python main.py?
Wenn Du direkt ausführst:
python main.py
verwendest Du das Python, das gerade in Deiner Shell aktiv ist.
Das kann funktionieren, wenn die .venv aktiviert ist. Es kann aber auch das
falsche Python sein, zum Beispiel das System-Python oder eine andere Umgebung.
Mit uv ist der sichere Standard:
uv run python main.py
Oder bei einfachen Skripten:
uv run main.py
So stellt uv sicher, dass die Abhängigkeiten aus dem Projekt verwendet werden.
uv.lock: reproduzierbare Abhängigkeiten
Die pyproject.toml beschreibt, was Dein Projekt direkt benötigt:
dependencies = [
"rich>=14.0.0",
]
Das ist noch nicht der vollständige exakte Zustand.
rich kann selbst weitere Pakete benötigen. Diese transitiven Abhängigkeiten
haben eigene Versionen.
uv schreibt den aufgelösten Zustand in die Datei:
uv.lock
Diese Lockdatei enthält die exakten Versionen, die zusammen installiert werden sollen.
Deshalb gilt:
pyproject.tomlbeschreibt die direkten Anforderungen.uv.lockbeschreibt den konkret aufgelösten, reproduzierbaren Stand.
Die uv.lock gehört normalerweise ins Git.
Die .venv gehört dagegen nicht ins Git.
Umgebung synchronisieren
Auf einem anderen Rechner reicht dann:
uv sync
uv liest die pyproject.toml und die uv.lock, erstellt bei Bedarf die
virtuelle Umgebung und installiert den gelockten Stand.
Das ist ideal für:
- neue Entwickler im Projekt,
- CI-Pipelines,
- reproduzierbare Builds,
- saubere Neuinstallationen.
Wenn Du ein Projekt aus Git klonst, ist der typische Ablauf:
git clone <repo>
cd <repo>
uv sync
uv run python main.py
Abhängigkeiten entfernen
Ein Paket entfernst Du mit:
uv remove rich
uv entfernt die Abhängigkeit aus der pyproject.toml, aktualisiert die
Lockdatei und synchronisiert die Umgebung.
Das ist besser, als die Datei manuell zu bearbeiten und anschließend zu hoffen, dass die Umgebung noch passt.
Development Dependencies
Nicht jede Abhängigkeit wird zur Laufzeit des Programms gebraucht.
Ruff ist zum Beispiel ein Entwicklungswerkzeug. Dein Programm importiert Ruff nicht, aber Du nutzt es beim Entwickeln.
Solche Pakete kannst Du in eine Dependency Group legen:
uv add --dev ruff
Danach kannst Du Ruff über uv ausführen:
uv run ruff check .
uv run ruff format .
So ist klar:
richwäre eine normale Projektabhängigkeit,ruffist ein Entwicklungswerkzeug.
In der pyproject.toml werden diese Gruppen getrennt dokumentiert.
Projektbefehle mit uv run
Alles, was in der Projektumgebung verfügbar ist, kannst Du über uv run
ausführen:
uv run python main.py
uv run ruff check .
uv run ruff format .
uv run sorgt vor dem Start dafür, dass Lockdatei und Environment zueinander
passen.
Das macht den Workflow sehr angenehm: Du musst nicht ständig überlegen, ob die richtige virtuelle Umgebung aktiv ist.
Der klassische Modus: uv venv und uv pip
uv kann auch ohne pyproject.toml wie ein schneller Ersatz für venv und pip
verwendet werden.
Eine virtuelle Umgebung anlegen:
uv venv
Das erzeugt standardmäßig .venv.
Aktivieren kannst Du sie wie gewohnt.
Linux und macOS:
source .venv/bin/activate
Windows PowerShell:
.venv\Scripts\Activate.ps1
Dann ein Paket installieren:
uv pip install rich
Oder aus einer requirements.txt:
uv pip install -r requirements.txt
Dieser Modus ist praktisch für bestehende Projekte, die noch nicht auf
pyproject.toml und uv.lock umgestellt werden sollen.
Für neue Projekte ist der Projektmodus meist angenehmer.
Python-Versionen verwalten
uv kann auch Python-Versionen installieren:
uv python install 3.13
Für ein Projekt kannst Du eine Version pinnen:
uv python pin 3.13
Dabei entsteht eine Datei wie:
.python-version
uv verwendet diese Information, um für das Projekt die passende Python-Version zu finden oder bei Bedarf zu installieren.
Daneben gibt es in pyproject.toml die Angabe:
requires-python = ">=3.12"
Diese beiden Dinge erfüllen unterschiedliche Aufgaben:
requires-pythonbeschreibt, welche Python-Versionen das Projekt unterstützt..python-versionbeschreibt, welche Python-Version uv lokal für dieses Projekt verwenden soll.
Beispiel:
requires-python = ">=3.12"
bedeutet: Das Projekt soll mit Python 3.12 oder neuer laufen.
.python-version
mit dem Inhalt
3.13
bedeutet: uv soll in diesem Checkout Python 3.13 verwenden.
Das ist nicht zwingend ein Widerspruch. Python 3.13 erfüllt schließlich
>=3.12.
Ein Projekt mit bestimmter Python-Version starten
Du kannst beim Initialisieren oder Ausführen auch direkt eine Python-Version angeben:
uv run --python 3.13 python --version
Oder für ein bestehendes Projekt:
uv python pin 3.13
uv sync
Damit ist der gewünschte Interpreter im Projekt klar dokumentiert.
Gerade in Teams und CI ist das hilfreich, weil nicht jeder Entwickler zufällig dieselbe lokal installierte Python-Version hat.
Tools ausführen mit uvx
Ein weiteres praktisches Feature ist uvx.
uvx ist eine Kurzform für:
uv tool run
Damit führst Du Kommandozeilen-Tools in einer isolierten, temporären Umgebung aus.
Beispiel:
uvx ruff check .
uv lädt Ruff bei Bedarf herunter, cached es und führt es aus, ohne dass Du Ruff dauerhaft global installieren musst.
Weitere Beispiele:
uvx pycowsay "Hallo Dungeon"
uvx httpie --version
Das ist ähnlich zur Idee von pipx run, aber in uv integriert.
Tools dauerhaft installieren
Manche Tools möchtest Du regelmäßig verwenden, aber nicht als Abhängigkeit eines bestimmten Projekts eintragen.
Dafür gibt es:
uv tool install ruff
Danach steht ruff als Kommando zur Verfügung, wird aber isoliert von Deinen
Projekten verwaltet.
Aktualisieren:
uv tool upgrade ruff
Entfernen:
uv tool uninstall ruff
Für projektbezogene Werkzeuge wie Ruff ist oft uv add --dev ruff sinnvoller,
damit alle im Projekt dieselbe Version verwenden.
Für persönliche Tools, die Du überall nutzen möchtest, passt uv tool install.
Single-File-Skripte mit Abhängigkeiten
uv kann auch einzelne Python-Skripte mit eigenen Abhängigkeiten ausführen.
Dafür gibt es Inline-Metadaten nach PEP 723:
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "rich",
# ]
# ///
from rich import print
print("[bold green]Läuft ohne manuelles venv.[/bold green]")
Speichere die Datei als skript.py und starte sie:
uv run skript.py
uv liest die Metadaten, richtet eine passende Umgebung ein und führt das Skript aus.
Das ist sehr praktisch für kleine Tools, die Du weitergeben möchtest, ohne ein vollständiges Projekt anzulegen.
Abhängigkeiten zu einem Skript hinzufügen
Du musst den Metadatenblock nicht immer von Hand schreiben.
uv kann eine Abhängigkeit zu einem Skript hinzufügen:
uv add --script skript.py rich
Danach enthält die Datei den passenden Metadatenblock.
Das Skript kann anschließend weiterhin gestartet werden mit:
uv run skript.py
Für größere Projekte ist pyproject.toml besser. Für ein einzelnes Tool ist
PEP 723 sehr elegant.
Ein Blick auf pyproject.toml
Nach einigen uv-Kommandos könnte eine pyproject.toml ungefähr so aussehen:
[project]
name = "mein-projekt"
version = "0.1.0"
description = "Ein kleines Python-Projekt"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"rich>=14.0.0",
]
[dependency-groups]
dev = [
"ruff>=0.15.0",
]
Die genauen Versionsnummern hängen vom Zeitpunkt ab.
Wichtig ist die Trennung:
[project]enthält Projektmetadaten und normale Abhängigkeiten.[dependency-groups]kann Entwicklungsabhängigkeiten enthalten.uv.lockenthält die vollständig aufgelösten Versionen.
uv im Dungeon-Projekt
Unser Dungeon aus Teil 10 kommt vollständig mit der Standardbibliothek aus.
Er braucht also eigentlich keine externen Pakete.
Trotzdem könnten wir das Projekt mit uv verwalten:
cd dungeon-projekt
uv init
Wenn bereits Dateien existieren, solltest Du prüfen, was uv erzeugt oder ergänzt.
Danach kannst Du das Spiel starten:
uv run python spiel.py
Oder, wenn spiel.py direkt als Skript behandelt wird:
uv run spiel.py
Für Ruff als Entwicklungswerkzeug:
uv add --dev ruff
uv run ruff check .
uv run ruff format .
Damit ist die Ruff-Version Teil des Projekts und nicht nur zufällig lokal installiert.
uv in der CI
In einer CI-Pipeline ist uv besonders praktisch, weil der Ablauf kurz und reproduzierbar ist.
Typisch:
uv sync --locked
uv run ruff check .
uv run ruff format --check .
uv run python spiel.py
--locked sorgt dafür, dass uv die Lockdatei nicht verändert. Wenn
pyproject.toml und uv.lock nicht zusammenpassen, schlägt der Schritt fehl.
Das ist in CI sinnvoll: Die Pipeline soll nicht still neue Abhängigkeiten auflösen, sondern prüfen, ob der eingecheckte Stand konsistent ist.
Für Anwendungen mit Tests käme später zum Beispiel hinzu:
uv run pytest
uv.lock und Git
Die Lockdatei gehört normalerweise ins Repository:
uv.lock
Sie sorgt dafür, dass andere Entwickler und die CI denselben aufgelösten Abhängigkeitsstand verwenden.
Nicht ins Git gehören dagegen:
.venv/
und üblicherweise auch Cache-Verzeichnisse.
Eine .gitignore könnte enthalten:
.venv/
__pycache__/
*.pyc
Falls Dein Projekt lokale Spielstände erzeugt:
spielstand.json
requirements.txt mit uv
Viele bestehende Umgebungen erwarten weiterhin eine requirements.txt.
uv kann Abhängigkeiten in andere Formate exportieren. Für einfache Fälle ist das
nützlich, wenn ein anderer Dienst noch nicht direkt mit uv.lock arbeitet.
Beispiel:
uv export --format requirements-txt > requirements.txt
Ob Du das brauchst, hängt vom Projekt ab.
Für ein reines uv-Projekt ist normalerweise uv.lock die maßgebliche Datei.
requirements.txt ist dann eher ein Export für andere Werkzeuge.
Wann ist uv sinnvoll?
uv lohnt sich besonders, wenn Du:
- neue Python-Projekte startest,
- reproduzierbare Abhängigkeiten möchtest,
- häufig Umgebungen neu aufbaust,
- CI-Zeiten reduzieren möchtest,
- Entwicklungswerkzeuge sauber pro Projekt verwalten willst,
- mehrere Python-Versionen verwendest,
- kleine Skripte mit Abhängigkeiten weitergeben möchtest.
Auch für Anfänger ist uv angenehm, weil viele Schritte einfacher werden.
Trotzdem ist es gut, venv und pip verstanden zu haben. uv abstrahiert diese
Themen nicht vollständig weg, sondern baut auf denselben Konzepten auf:
Umgebungen, Interpreter, Abhängigkeiten und Paketversionen.
Wann reicht klassisches venv und pip?
Für sehr kleine Beispiele reicht weiterhin:
python -m venv .venv
python -m pip install paket
Das gilt besonders, wenn Du einem Tutorial folgst, das ausdrücklich diesen Weg verwendet.
Auch in älteren Projekten kann es sinnvoll sein, nicht sofort alles umzustellen.
uv ist ein Werkzeug, kein Muss.
Wenn ein Projekt gut mit pip, venv, requirements.txt oder Poetry
funktioniert, sollte eine Migration bewusst passieren und nicht nur wegen eines
neuen Tools.
Migration vorsichtig angehen
Ein bestehendes Projekt solltest Du nicht blind umstellen.
Sinnvoller Ablauf:
- Aktuellen Stand committen.
- Prüfen, wie Abhängigkeiten bisher verwaltet werden.
- uv testweise in einem Branch einführen.
pyproject.tomlund Lockdatei prüfen.- CI anpassen.
- Dokumentation aktualisieren.
- Erst danach alte Konfigurationsdateien entfernen.
Besonders bei Projekten mit Poetry, Hatch, PDM, privaten Paketquellen oder komplexen Extras lohnt sich ein genauer Blick.
uv kann sehr viel, aber jedes Projekt hat eigene Gewohnheiten und Anforderungen.
Stolperfallen
-
uv runvergessen: Wer direktpython skript.pyausführt, verwendet möglicherweise nicht die Projektumgebung. -
.venvins Git einchecken: Die virtuelle Umgebung ist lokal. Ins Git gehört dieuv.lock, nicht die.venv. -
uv.lockignorieren: Ohne Lockdatei verlierst Du einen wichtigen Vorteil von uv: reproduzierbare Installationen. -
pyproject.tomlunduv.lockverwechseln: Diepyproject.tomlbeschreibt Anforderungen, die Lockdatei den konkret aufgelösten Stand. -
uv addmituv pip installvermischen:uv addverwaltet Projektabhängigkeiten.uv pip installinstalliert in eine Umgebung, ohne automatisch die Projektmetadaten zu pflegen. -
Entwicklungswerkzeuge global installieren, obwohl sie projektabhängig sind: Für Ruff, pytest oder mypy ist oft
uv add --dev ...besser als eine globale Installation. -
uvxfür projektfeste Tools verwenden:uvx ruffist praktisch zum schnellen Ausprobieren. Für ein Projekt sollte die Tool-Version besser in der Projektkonfiguration stehen. -
requires-pythonund.python-versionverwechseln: Das eine beschreibt unterstützte Versionen, das andere pinnt die lokal gewünschte Version für uv. -
PEP-723-Skripte mit normalen Projekten verwechseln: Inline-Abhängigkeiten sind ideal für einzelne Skripte. Größere Projekte gehören in eine
pyproject.toml. -
Migration ohne sauberen Git-Stand: uv kann mehrere Dateien ändern. Vorher committen, danach Diffs prüfen.
-
uv als Python-Ersatz verstehen: uv verwaltet Python-Versionen und Pakete. Es ersetzt nicht die Sprache, die Standardbibliothek oder Tests.
Kompakte Übersicht
| Aufgabe | Klassisch | Mit uv |
|---|---|---|
| venv anlegen | python -m venv .venv |
uv venv |
| Paket installieren | python -m pip install rich |
uv add rich im Projekt oder uv pip install rich |
| Paket entfernen | manuell / pip uninstall |
uv remove rich |
| Projekt ausführen | venv aktivieren, dann python ... |
uv run python ... |
| Umgebung synchronisieren | pip install -r requirements.txt |
uv sync |
| Lockdatei nutzen | Zusatztool nötig | uv.lock |
| Python installieren | externes Tool | uv python install 3.13 |
| Python fürs Projekt pinnen | oft pyenv | uv python pin 3.13 |
| Tool einmalig ausführen | pipx run ... |
uvx ... |
| Tool isoliert installieren | pipx install ... |
uv tool install ... |
| Skript mit Abhängigkeiten | manuelles venv | uv run skript.py mit PEP 723 |
Übungen
1. Ein neues uv-Projekt anlegen
Lege ein neues Projekt an, installiere rich und starte das Beispielprogramm.
Lösung
uv init mein-projekt
cd mein-projekt
uv add rich
from rich import print
print("[bold green]Hallo uv![/bold green]")
uv run python main.py
2. Ruff als Development Dependency hinzufügen
Füge Ruff als Entwicklungsabhängigkeit hinzu und führe den Linter aus.
Lösung
uv add --dev ruff
uv run ruff check .
uv run ruff format .
3. Eine Python-Version pinnen
Installiere Python 3.13 mit uv und pinne das Projekt darauf.
Lösung
uv python install 3.13
uv python pin 3.13
uv run python --version
4. Ein Tool mit uvx ausführen
Führe Ruff einmalig über uvx aus, ohne es dem Projekt hinzuzufügen.
Lösung
uvx ruff check .
5. Ein PEP-723-Skript schreiben
Lege ein einzelnes Skript mit eigener Abhängigkeit an und starte es mit uv.
Lösung
`skript.py`:# /// script
# requires-python = ">=3.12"
# dependencies = [
# "rich",
# ]
# ///
from rich import print
print("[bold cyan]Single-File-Skript mit Abhängigkeit[/bold cyan]")
uv run skript.py
Vertiefung
Das Schwestertool von Astral für Linting und Formatierung:
Ruff: Linter und Formatter in einem
Der klassische Einstieg, auf dem uv aufbaut:
Python lernen, Teil 10: Module und Projektstruktur
Fazit
uv macht Python-Projektverwaltung deutlich angenehmer.
Für neue Projekte ist der typische Workflow kurz:
uv init
uv add rich
uv run python main.py
Für reproduzierbare Umgebungen:
uv sync
Für Entwicklungswerkzeuge:
uv add --dev ruff
uv run ruff check .
Für einzelne Tools:
uvx ruff check .
Und für Skripte mit Inline-Abhängigkeiten:
uv run skript.py
Der wichtigste Unterschied zum klassischen Workflow ist nicht nur die Geschwindigkeit. uv verbindet Umgebung, Abhängigkeiten, Lockdatei, Python-Versionen und Tool-Ausführung zu einem einheitlichen Modell.
Trotzdem bleibt das Grundverständnis aus venv und pip wichtig. uv macht diese
Konzepte bequemer, aber nicht magisch.
0 Kommentare
Noch keine Kommentare. Sei der/die Erste!
Anmelden um einen Kommentar zu hinterlassen.