- Mit uv wird die Verwaltung von Abhängigkeiten beim Ausführen von Python-Skripten automatisiert
- Ohne separate Verwaltung virtueller Umgebungen wird für jedes Skript automatisch eine Umgebung erstellt und gepflegt
- Benötigte Pakete können auf verschiedene Arten deklariert werden, etwa per Inline-Metadaten oder über Kommandozeilenoptionen
- Auch Python-Versionen und Paketverwaltung lassen sich pro Skript deklarieren und automatisch anpassen
- Mit Lock-Dateien und Optionen zur Begrenzung von Abhängigkeitsversionen werden Reproduzierbarkeit und Wartbarkeit verbessert
Überblick
- uv ist ein Tool, das beim Ausführen von Python-Skripten die dafür benötigten Paketabhängigkeiten automatisch verwaltet
- Nutzer müssen sich nicht selbst um die mühsame Erstellung virtueller Umgebungen oder die Installation von Paketen kümmern
- Es bietet verschiedene Ausführungsoptionen, den Einsatz von Inline-Metadaten, unterschiedliche Arten zur Deklaration von Abhängigkeiten sowie diverse Steuerungsfunktionen
Python-Umgebungen und die Rolle von uv
- Python besitzt für jede Installation eine eigene Umgebung
- Im Allgemeinen wird empfohlen, virtuelle Umgebungen zu erstellen und zu verwalten
- uv verwaltet virtuelle Umgebungen automatisch und behandelt Abhängigkeiten auf deklarative Weise
- Ein einfaches Skript lässt sich sofort mit
uv run example.py ausführen
- Bei Verwendung der Standardbibliothek funktioniert es ohne zusätzliche Konfiguration
Übergabe von Argumenten und Eingabemethoden
- An ein Skript können Kommandozeilenargumente übergeben werden
- Es kann Skriptcode direkt aus der Standardeingabe ausführen und unterstützt auch die Here-Document-Funktion
Projektumgebung und die Option --no-project
- Wird ein Skript in einem Projektordner ausgeführt, etwa dort, wo sich eine
pyproject.toml befindet, werden auch die Projektabhängigkeiten installiert
- Falls das nicht gewünscht ist, kann die Projektumgebung mit dem Flag
--no-project vor dem Skriptnamen ignoriert werden
Deklaration und Verwaltung von Skriptabhängigkeiten
- Wenn externe Pakete benötigt werden, können Abhängigkeiten mit der Kommandozeilenoption
--with angegeben und so ausgeführt werden
- Auch Einschränkungen auf bestimmte Versionen werden unterstützt, und mehrere Abhängigkeiten können durch wiederholte Angabe der Option gesetzt werden
- In einer Projektumgebung lassen sich zusätzliche Abhängigkeiten ergänzen; wenn das nicht gewünscht ist, kann dies mit
--no-project gesteuert werden
Inline-Skript-Metadaten (PEP-723-Methode)
- Python unterstützt inzwischen ein Standardformat, um Abhängigkeiten oder Python-Versionen direkt im Skript selbst zu deklarieren
- Mit
uv init --script lässt sich bequem ein Skript mit eingebetteten Metadaten erzeugen
- Mit
uv add --script können benötigte Abhängigkeiten im TOML-Format zum Skript hinzugefügt und verwaltet werden
- Wenn Inline-Metadaten vorhanden sind, werden die Abhängigkeiten des Projekts ignoriert und es werden nur die Abhängigkeiten des Skripts angewendet
Deklaration und Verwaltung der Python-Version
- Die gewünschte Python-Version kann im Skript selbst oder beim Ausführen angegeben werden
- Falls die angegebene Version nicht vorhanden ist, wird sie automatisch heruntergeladen und eingerichtet
Direkt ausführbare Skripte mit Shebang schreiben
- Mit einem Shebang (
#!...) lassen sich direkt ausführbare Dateien im Stil von uv run --script erstellen
- Auch dabei können Abhängigkeitsdeklarationen und die Python-Version am Anfang des Skripts festgelegt werden
Paketindex und Authentifizierungsunterstützung
- Mit der Option
--index kann ein benutzerdefinierter Paketindex verwendet werden
- Index-Informationen können ebenfalls in den Metadaten enthalten sein
- Falls Authentifizierung erforderlich ist, kann auf die separate Dokumentation verwiesen werden
Abhängigkeiten fixieren (Lock) und Reproduzierbarkeit verbessern
- Mit
uv lock --script kann eine Lock-Datei auf Skriptebene erstellt und verwaltet werden
- Bei späteren Ausführungen oder beim Hinzufügen von Abhängigkeiten wird die Lock-Datei wiederverwendet und bei Bedarf aktualisiert
- Für Versionsreproduzierbarkeit gibt es die Option
exclude-newer (schließt Releases nach einem bestimmten Datum aus)
- Das Datum wird als RFC-3339-Zeitstempel angegeben
Flexible Python-Versionen
- Bei jeder Ausführung kann über eine Kommandozeilenoption eine beliebige Python-Version festgelegt werden
- Beispiel:
uv run --python 3.10 example.py
Windows-Unterstützung
- Skripte mit der Erweiterung
.pyw werden unter Windows mit pythonw ausgeführt
- Auch GUI-basierte Skripte können zusammen mit ihren Abhängigkeiten ausgeführt werden
Referenzdokumentation
- Ausführlichere Informationen zur Verwendung der Befehle finden sich in der CLI-Referenzdokumentation sowie in den Anleitungen zum Ausführen und Installieren des Tools
Fazit
- uv ist ein Tool, das Ausführungsumgebung, Abhängigkeiten, Versionen, Paketindizes und Reproduzierbarkeit von Python-Skripten automatisch und einfach verwaltet und damit Produktivität und Zuverlässigkeit zugleich erhöht
7 Kommentare
Ich bin auch von pip zu uv gewechselt, und allein wegen der wirklich hohen Geschwindigkeit lohnt sich der Umstieg schon.
Das taucht häufig auf, deshalb habe ich es gestern zum ersten Mal ausprobiert … es ist wirklich schnell. Wahnsinn …
Ich glaube, ich habe hier schon mehr als fünf Beiträge zu uv gesehen;;;
Andere Funktionen einmal beiseitegelassen – allein die Geschwindigkeit ist schon Grund genug, es zu verwenden.
Wenn man mich bitten würde, wieder pip zu benutzen, könnte ich das absolut nicht mehr.
Das System-Paketmanagement von conda habe ich durch
flake.nixersetzt; abgesehen von gemeinschaftlichen Arbeiten oder Projekten, die bisher mit conda+pip gepflegt wurden, werde ich persönlich wohl künftig uv+nix verwenden.Uv – ein ultraschnelles Python-Packaging-Tool, implementiert in Rust
Den Python-Entwicklungs-Workflow mit UV revolutionieren
Python-Skripte mit uv und PEP 723 nutzen
Ein Jahr mit uv: Vor- und Nachteile sowie Punkte, die bei einer Migration zu beachten sind
In letzter Zeit habe ich die meisten Python-Ausführungen durch uv ersetzt, und es ist wirklich schnell.
Es gibt zwar einige fortgeschrittene Funktionen, die nicht vollständig kompatibel sind, aber in den meisten Fällen verhält es sich fast genauso.
Hacker-News-Kommentar
Ich habe festgestellt, dass die Funktion zum „Deklarieren von Skript-Abhängigkeiten“ wirklich nützlich ist.
Wie in der offiziellen Anleitung beschrieben, kann man die Abhängigkeiten ganz oben in einer Python-Datei als Kommentar angeben.
Speichert man diese Datei als
script.pyund führt dannuv run script.pyaus, werden die angegebenen Abhängigkeiten wie von Zauberhand in einer temporären virtuellen Umgebung installiert und das Skript lässt sich sofort ausführen.Das ist eine Implementierung von Python-PEP 723, und auch Claude 4 kennt diesen Trick. Wenn man also nach einem „Python-Skript mit Inline-Skript-Abhängigkeiten“ fragt, erzeugt es korrekt eines.
Man kann es zum Beispiel bitten, Code zu schreiben, der mit httpx und click große Dateien herunterlädt und einen Fortschrittsbalken anzeigt.
Vor Claude 4 brauchte man für solche Funktionen ein maßgeschneidertes Projekt und zusätzliche Anweisungen, jetzt nicht mehr.
Weitere Beispiele für praktische Einsatzzwecke gibt es hier.
Auch der shebang-Modus ist wirklich nützlich.
Fügt man wie unten in die erste Zeile des Skripts einen shebang ein, kann man es wie
./script.shausführen.Ich wünschte, es hätte dasselbe Format wie eine requirements-Datei.
Dann könnte man für Nutzer ohne uv auch mit einem einfachen Kommentar einen One-Liner angeben, mit dem sich dasselbe per pip installieren lässt.
Zum Beispiel wäre ein Ansatz wie
pip install -r <(head myscript.py)denkbar.Tatsächlich wird PEP 723 inzwischen nicht nur vom derzeit viel beachteten uv unterstützt, sondern auch von pipx und hatch.
Und auch pip-tools steht auf der Support-Roadmap.
(Siehe dieses Issue.)
Als ich das zum ersten Mal gesehen habe, hielt ich das Zeichen neben requests kurz für ein Herz-Emoji.
Ich finde diesen Ansatz wirklich großartig.
Aber irgendwann wäre es schön, wenn das nicht nur magische Kommentare wären, sondern eingebaute Sprachsyntax.
Kommentare wirken etwas unordentlich.
Natürlich verstehe ich, dass magische Kommentare aus Tool-Sicht leichter zu parsen sind und dass es strukturelle Überlegungen gibt, etwa dass Python-Core nicht allzu viel Packaging-Wissen enthalten soll, aber irgendwann wäre eingebaute Syntax schön.
Ich kann mich mit diesem Ansatz sehr gut identifizieren.
Zwar ist eine
requirements.txt-Datei in Python nicht zwingend erforderlich, aber wenn man die Pflege vernachlässigt, geht oft etwas kaputt, und das ist frustrierend.Dazu ein passender Tweet
Ich möchte eine Falle teilen, auf die ich bei diesem Ansatz gestoßen bin.
Ich habe ihn in einem Skript verwendet, das bei Internetausfall den Router neu startet. Dabei stellte sich heraus, dass die Installation der Abhängigkeiten selbst von einer Internetverbindung abhängt, sodass das Skript bei fehlendem Netzwerk gar nicht mehr funktioniert.
Ich habe das rechtzeitig entdeckt und durch Vorabinstallation der Abhängigkeiten gelöst, aber macht nicht denselben Fehler wie ich und verwendet das nicht in echten Air-Gap-Umgebungen, also Umgebungen mit vollständig getrennter Netzwerkverbindung.
Selbst mit uv-Cache kann es zu Cache-Misses kommen.
Mit der Option
uv run --offlinekann man gecachte Abhängigkeiten verwenden und das Skript ausführen, ohne nach neuen Versionen zu suchen.Dasselbe funktioniert auch mit
uvx(uvx --offline ...).Ich verstehe es so, dass man, wenn man Abhängigkeiten oder eine venv verwenden will, mindestens einmal mit Internetverbindung ausführen muss, damit es danach auch offline nutzbar ist.
In letzter Zeit habe ich das Gefühl, dass im Python-Ökosystem immer mehr Dinge sauber zusammenspielen.
Mit der Kombination aus Marimo und uv-Skript-Abhängigkeiten habe ich begonnen, reproduzierbare Reporting- und Diagnose-Tools zu bauen, die andere Teams gut verwenden können.
Diese Funktion von uv gefällt mir am besten, und genau deshalb bin ich auf uv umgestiegen.
Mehrere Git-Hooks-Skripte haben jeweils eigene Abhängigkeiten, die ich nicht in der Haupt-venv installieren wollte.
Ich musste nur
#!/usr/bin/env -S uv run --script --python 3.13hinzufügen, den Entwicklernbrew install uvsagen, und schon konnten sie das direkt im Skript nutzen, ohne extra eine venv anlegen zu müssen.Weiß jemand, warum das Flag
-Snötig ist?In meiner BSD-Umgebung scheint sowohl
/usr/bin/env -S uv run --python 3.11 pythonals auch/usr/bin/env uv run --python 3.11 pythondie Python-Shell zu starten, also wirkt das Ergebnis gleich.Auch aus der env-Manpage wird mir das nicht ganz klar; falls jemand dazu hilfreiche Informationen hat, würde ich sie gern hören.
(
-Sdient hier dazu, Argumente anhand von Leerzeichen aufzuteilen.)Dank UV wollte ich ursprünglich eine große Python-Migration in Golang umsetzen, aber dank UV konnte ich den Umfang dieser Migration reduzieren.
Gerade kleine Aufgaben in Skriptform müssen nicht mehr migriert werden.
Ich bin überzeugt, dass diese Funktion wirklich eine Killer-Feature ist.
Wenn unter den Abhängigkeiten Pytorch ist, kann dieser Ansatz etwas eingeschränkt sein.
Uv bietet zwar gute integrierte Unterstützung für Pytorch, aber allein über den Skript-Header lässt sich leider nicht eindeutig auswählen, welcher Wheel-Index am besten passt, also etwa CPU, CUDA oder ROCm.
Ich wünschte, VS Code könnte die von uv automatisch erzeugte venv leichter erkennen.
Im Moment markiert die Python-Extension alle Drittanbieter-Imports rot.
Als temporäre Lösung suche ich den venv-Pfad im Cache-Verzeichnis von uv manuell heraus und registriere ihn, aber wenn die venv häufig neu erzeugt wird, muss ich das immer wiederholen, was lästig ist.
uv python find --script "${filePath}"kann man den Pfad der Umgebung finden.Ich entwickle gerade eine Erweiterung, die das in VS Code automatisch erkennt und aktiviert.
Ich liebe diese Funktion von UV.
Man kann sogar ein Jupyter-Notebook ohne separate Installation mit einem One-Liner wie diesem starten:
Alles wird in einer temporären virtuellen Umgebung installiert und danach wieder sauber aufgeräumt.
Führt man das innerhalb eines Projekts aus, erkennt es außerdem automatisch die Abhängigkeiten dieses Projekts.
Allerdings wird nicht vollständig „sauber“ aufgeräumt, denn der uv-Cache-Ordner kann weiter anwachsen.
Ich nutze ebenfalls oft Dinge wie
uv run --with ipython --with boto3 ipython, und das spart wirklich viel Zeit.Kürzlich ist mir bei
uv runein kleines Problem aufgefallen.Wenn man ein Skript von außerhalb des Projektordners ausführt, sucht es nach
pyproject.tomlim aktuellen Arbeitsverzeichnis und nicht am tatsächlichen Speicherort der Skriptdatei.Deshalb kann ein Skript, dessen Abhängigkeiten in
pyproject.tomlgespeichert sind, bei einem externen Aufruf wieuv run path/to/my/script.pyunter Umständen nicht korrekt funktionieren.Das lässt sich lösen, indem man immer Inline-Abhängigkeiten verwendet oder das Argument
--projectangibt, aber dann muss man den Skriptpfad zweimal eingeben, was umständlich ist.uv selbst ist großartig, aber diese kleine Eigenheit empfinde ich als ziemlich unpraktisch.
Ich war mit dem uv-spezifischen shebang und dem Ansatz mit Abhängigkeiten im Skript bereits sehr zufrieden.
Umso beeindruckender fand ich, dass man mit
uv lock --script example.pysogar eine Lock-Datei nur für ein einzelnes Skript erzeugen kann.Python-Packaging gibt es seit über 20 Jahren, und es überrascht mich, dass so eine natürliche Erfahrung erst jetzt auftaucht.
In unserer Organisation scannen wir die Abhängigkeiten in Lockfiles mit Dingen wie
trivy fs uv.lock, um zu verhindern, dass Code mit bekannten CVEs ausgeführt wird.