14 Punkte von GN⁺ 2025-07-22 | 7 Kommentare | Auf WhatsApp teilen
  • 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

 
ihabis02 2025-07-24

Ich bin auch von pip zu uv gewechselt, und allein wegen der wirklich hohen Geschwindigkeit lohnt sich der Umstieg schon.

 
idunno 2025-07-23

Das taucht häufig auf, deshalb habe ich es gestern zum ersten Mal ausprobiert … es ist wirklich schnell. Wahnsinn …

 
ytuniverse 2025-07-23

Ich glaube, ich habe hier schon mehr als fünf Beiträge zu uv gesehen;;;

 
pmc7777 2025-07-23

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.nix ersetzt; abgesehen von gemeinschaftlichen Arbeiten oder Projekten, die bisher mit conda+pip gepflegt wurden, werde ich persönlich wohl künftig uv+nix verwenden.

 
ndrgrd 2025-07-22

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.

 
GN⁺ 2025-07-22
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.

    # /// script
    # dependencies = [
    #  "requests<3",
    #  "rich",
    # ]
    # ///
    import requests, rich
    # ... script
    

    Speichert man diese Datei als script.py und führt dann uv run script.py aus, 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.sh ausführen.

      #!/usr/bin/env -S uv run --script
      # /// script
      # dependencies = [
      #  "requests<3",
      #  "rich",
      # ]
      # ///
      import requests, rich
      # ... script
      
    • 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 --offline kann 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.13 hinzufügen, den Entwicklern brew install uv sagen, und schon konnten sie das direkt im Skript nutzen, ohne extra eine venv anlegen zu müssen.

    • Weiß jemand, warum das Flag -S nötig ist?
      In meiner BSD-Umgebung scheint sowohl /usr/bin/env -S uv run --python 3.11 python als auch /usr/bin/env uv run --python 3.11 python die 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.
      (-S dient 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.

    • Mit dem Befehl 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:

    uv run --with jupyter jupyter notebook
    

    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 run ein kleines Problem aufgefallen.
    Wenn man ein Skript von außerhalb des Projektordners ausführt, sucht es nach pyproject.toml im aktuellen Arbeitsverzeichnis und nicht am tatsächlichen Speicherort der Skriptdatei.
    Deshalb kann ein Skript, dessen Abhängigkeiten in pyproject.toml gespeichert sind, bei einem externen Aufruf wie uv run path/to/my/script.py unter Umständen nicht korrekt funktionieren.
    Das lässt sich lösen, indem man immer Inline-Abhängigkeiten verwendet oder das Argument --project angibt, 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.py sogar 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.

    • Mich würde interessieren, wofür Leute einen Lock für ein einzelnes Skript verwenden.
      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.