Python-Skripte mit uv und PEP 723 nutzen
(cottongeeks.com)- Mit dem uv-Paketmanager und PEP 723 lassen sich Python-Skripte ohne Abhängigkeitsprobleme ausführen
- Die Funktion uvx erstellt automatisch eine Disposable Virtual Environment und beseitigt so den Aufwand bei der Einrichtung der Umgebung
- Wenn PEP-723-Metadaten in eine Python-Datei eingebettet werden, werden automatische Skriptausführung und Paketverwaltung deutlich einfacher
- Als Beispielskript lässt sich ein Programm zum Extrahieren von YouTube-Untertiteln schnell umsetzen und verteilen
- Dadurch ist es nun auch in Python möglich, kompakte einzeln ausführbare Dateien zu schreiben, was die Nutzbarkeit von Skripten deutlich verbessert
Überblick
- Beim Ausführen von „One-off-Skripten“ in Python musste man bisher jedes Mal die Umgebung einrichten und Pakete installieren; diese Unannehmlichkeit verschwindet mit der Einführung von uv und PEP 723
- uv ist ein in Rust entwickelter schneller Python-Paket- und Projektmanager und erledigt mit der neuen Funktion uvx die Einrichtung von Disposable Virtual Environments, automatische Paketinstallation und die Verknüpfung mit Python-Versionen sehr schnell und einfach
Vorteile von uv und uvx
- Die Funktion uvx arbeitet ähnlich wie npx im Nodejs-Ökosystem und erstellt schnell eine Ausführungsumgebung für ein angegebenes Python-Paket, zum Beispiel ruff
- Disposable Virtual Environments werden als Cache genutzt und ermöglichen eine schnelle Ausführung ohne Overhead
- Einrichtung der Umgebung und Installation von Abhängigkeiten erfolgen mit einem einzigen Befehl, sodass Entwickler keine separate Umgebungsverwaltung mehr benötigen
Einführung und Nutzung von PEP 723
- PEP 723 definiert einen Standard, mit dem sich Metadaten zu Abhängigkeiten und Umgebung am Anfang eines Python-Skripts einbetten lassen
- Beispiel: Am Anfang des Codes können
requires-python,dependenciesund Ähnliches angegeben werden - Externe Tools, die dies erkennen, etwa uv, übernehmen anhand der im Skript hinterlegten Informationen automatisch Installation, Einrichtung der Umgebung und Ausführung
Die Kombination aus uv und PEP 723
- Werden diese Metadaten am Anfang einer echten Python-Beispieldatei eingetragen und mit dem
run-Befehl von uv ausgeführt, werden sofort alle benötigten Pakete automatisch installiert, die angegebene Python-Version eingerichtet und anschließend der Code ausgeführt - Der Beispielcode ruft eine Internet-API auf, nämlich die PEP-Liste, und gibt das Ergebnis aus. Zusätzliche Paketinstallation oder Umgebungssetup sind nicht nötig; ein einzelner Befehl genügt
Praxisbeispiel: ein YouTube-Untertitel-Skript
- Es wird ein Python-Skript mit shebang (
#!/usr/bin/env -S uv run --script) und PEP-723-Metadaten gezeigt - Externe Pakete wie
youtube-transcript-apiwerden automatisch installiert und die virtuelle Umgebung wird ebenfalls automatisch eingerichtet - Der Nutzer kann einer ausführbaren Datei (
ytt) eine YouTube-Video-URL oder ID als Argument übergeben und erhält die Untertitel sofort als Ergebnis - Nach dem Setzen der Ausführungsrechte mit
chmodlässt sich das Skript einfach im Terminal starten
Verbesserte Developer Experience und erweiterte Möglichkeiten
- Früher wurden für einfache Skripte oft eher Binärsprachen mit einer einzelnen ausführbaren Datei wie Go bevorzugt, doch nun bietet auch Python ein vergleichbares Maß an Komfort
- Die Kombination aus uv und PEP 723 erleichtert das Teilen, Verteilen und die automatisierte Ausführung von Python-Skripten erheblich
- Über das Github-Beispiel
cottongeeks/ytt-mcplassen sich auch komplexere Anwendungsfälle entwickeln
2 Kommentare
uvist unglaublich schnell, das gefällt mir sehr. In letzter Zeit verwende ich nach Möglichkeit überalluv.Hacker-News-Kommentare
Wie der Autor des Beitrags greife ich in letzter Zeit eher zu plattformübergreifenden Python-One-offs und persönlichen Skripten statt zu Go, bin aber unzufrieden damit, dass sich das Python-Type-Checking-System wie pures Chaos anfühlt. Ich hoffe, dass Tools wie ty und pyrefly das wenigstens ein Stück weit verbessern.
Inzwischen fühlen sich Python-Skripte so an, als würden sie einfach direkt gut funktionieren, ohne dass man mit virtualenv leiden muss. So eine Erfahrung hätte ich gern auch bei Shell-Skripten. Packaging, Abhängigkeitsmanagement und Reproduzierbarkeit sind dort weiterhin auf Steinzeitniveau. Im Moment ist die Realität immer noch entweder
curl | bashund auf Glück hoffen oder eine README-Datei mit 3 fehlenden Abhängigkeiten und 12 manuellen Schritten. Nix? Wirkt wie eine brauchbare Option nur für Leute, die Zeit, Raum und das Nix-Handbuch bereits transzendiert haben. Docker? Eine gute Wahl, falls es für einen vernünftig klingt, eine Linux-Distribution herunterzuladen, nur um einmalsedauszuführen. Es braucht unbedingt einen einfachen, deklarativen Mittelweg, den jeder nutzen kann.Ein wirklich großartiger Trend, der sich immer weiter verbreitet. Ich habe zuerst im Blog von simonw davon gelesen und den Zusammenhang dann in einem Blogpost von simonwillison nachgesehen. Im März dieses Jahres gab es dazu auch schon eine Hacker-News-Diskussion zu einem anderen Blogbeitrag. Ich hoffe, dieser Trend bleibt lange genug auf der Startseite, damit ihn noch mehr Leute wahrnehmen.
Ich habe uv in kleinen Projekten ausprobiert und die Erfahrung ist wirklich hervorragend. Mit der Kombination aus
uv rununduv tool run(uvx) ist das Installieren und direkte Ausführen von Python-Skripten von GitHub auf einer VM extrem einfach. Keingit clone, kein Erstellen oder Betreten eines venv, keinpip install. Vor allem ist uv so schnell, dass ich anfangs dachte, irgendetwas müsse kaputt sein; tatsächlich ist es etwa 10-mal schneller als pip. Tooling und Dokumentation sind zwar noch ein wenig unfertig, aber bei so viel Innovationskraft und praktischem Nutzen ist es trotzdem absolut verwendbar.--helpausgeben kann.Auch Rust entwickelt eine ähnliche Idee von Shell-Skripten mit Single-File-Typ weiter. Dort habe ich so einen Ansatz zuerst gesehen, also die Unterstützung für das Ausführen einzelner Dateien inklusive Abhängigkeitsmanagement. Ich hoffe, dieses Muster setzt sich in noch mehr Sprachen durch; für das Austauschen per Gist oder das schnelle Schreiben kleiner Tools ist es extrem nützlich. Siehe auch das cargo-script-RFC-Dokument.
Wenn man
uv run --scriptverwendet und die Metadaten im Skript selbst einbettet, ist es etwas umständlich, direkt aus dem Skript eine Python-REPL zum Bearbeiten und Testen zu öffnen. Zum Beispiel muss man so etwas machen:Ich würde mir eine kompaktere Variante wünschen. Zum Beispiel wäre so etwas ideal:
Tatsächlich kann man es aber so ausführen und landet direkt in der passenden Python- und venv-Umgebung für das Skript:
Allerdings muss man das Skript einmal ausführen, damit die Umgebung erzeugt wird.
--interactivehinzufügen und als CLI-Option anbieten. Kleine CLIs auf Basis von Typer schreibe ich oft genau so. In einem Dev-Skript bin ich über ein--sql-Flag auch schon in eine DuckDB-SQL-REPL eingestiegen.Wenn man conda verwendet, kann man in einem Shell-Wrapper für Python-Skripte auch direkt die Umgebung aktivieren. Zum Beispiel so:
Das ist allerdings kein so eigenständiger Ansatz wie im Stil von PEP 723.
Nachdem ich gestern und heute die HN-Threads gesehen hatte, habe ich mich zum ersten Mal an uv gewagt und war von der Geschwindigkeit und der einfachen Abhängigkeitsverwaltung tief beeindruckt. Mit besserer offizieller Dokumentation wäre es noch besser, besonders mit einer Anleitung für den Umstieg von einem
requirements.txt-Workflow auf uv. Auch die projektspezifische Festlegung der Python-Version ist etwas verwirrend, weil sie an zwei Stellen definiert wird:.python-versionundpyproject.toml.requires-versioninpyproject.tomlbezeichnet den kompatiblen Versionsbereich, während.python-versiondie konkrete Version für die Entwicklung festlegt. Wenn man mituv initstartet, sehen beide anfangs gleich aus, aber mit der Zeit gibtrequires-versioneher die niedrigste noch unterstützte Version an, die unter.python-versionliegen kann.requires-versionlandet außerdem in den Paketmetadaten und beeinflusst auch die Auflösung von Abhängigkeiten bei anderen, die das veröffentlichte Paket verwenden. Zum Beispiel wenn v1 noch ältere Python-3-Versionen unterstützt, v2 aber nicht mehr.npm updateoderdotnet restore, aber ein venv funktioniert danach problemlos weiter. Bei uv wirkt der Umgang mit einem Plattformwechsel dagegen komplizierter und es scheint mehr manuelle Bereinigung nötig zu sein.pyproject.tomldient, unabhängig von uv selbst, dazu, die benötigte Umgebung zu definieren, wenn man Code mit externen Entwicklern und Nutzern teilt. Beim Bauen eines Pakets für PyPI beschreibt es, welche Umgebung erforderlich ist, und der Versionsbereich wird so gesetzt, dass mehr Leute den Code wiederverwenden können..python-versionist nur für uv gedacht, und zwar nur für das Setup meiner eigenen Entwicklungsumgebung. Wenn bereits eine vorgefertigte Umgebung existiert, muss man das nicht unbedingt neu definieren. uv ist zwar noch kein offizielles Build-Backend, arbeitet aber an dieser Funktion (Issue #3957)..python-versionim Wesentlichen der Kompatibilität mit anderen Tools dient, die keinen TOML-Parser haben.Ich wollte früher einmal ein Tool bauen, das Python-Skripte ihre Abhängigkeiten selbst installieren lässt. Das Ziel war ein Tool, das ähnlich wie uvx funktioniert, aber nur Python selbst voraussetzt. Ein Nachteil ist allerdings, dass man am Anfang des Skripts mehrere etwas seltsam aussehende Zeilen einfügen muss. Wer neugierig ist: Auf PyPI ist es unter dem Namen pysolate veröffentlicht.
Eine von COBOL inspirierte Nachricht im Stil von Grace Hopper. Es sollte die Kultur geben, dass jedes Python-Programm eine ENVIRONMENT division definiert und seine Compile- und Laufzeitumgebung einschließlich Hardware- und Softwareanforderungen klar dokumentiert. So eine Struktur hätte entscheidenden Einfluss darauf, die Portabilität von Programmen zwischen unterschiedlichen Systemen zu verbessern.