PEP 780 – ABI-Features als Umgebungsvariablen
- Autor:
- Klaus Zimmermann <klaus_zimmermann at gmx.de>, Ralf Gommers <ralf.gommers at gmail.com>
- Sponsor:
- Lysandros Nikolaou <lisandrosnik at gmail.com>
- Discussions-To:
- Discourse thread
- Status:
- Entwurf
- Typ:
- Standards Track
- Thema:
- Packaging
- Erstellt:
- 21. März 2025
- Python-Version:
- 3.14
- Post-History:
- 05. August 2024, 26. März 2025
Zusammenfassung
Diese PEP definiert die Verwendung von ABI-Features als Umgebungsvariablen für Projekt-Abhängigkeiten über eine neue sys_abi_features Umgebungsvariable. PEP 508 (später verschoben zu Dependency specifiers) führte Umgebungsvariablen ein, um Abhängigkeiten basierend auf Regeln zu spezifizieren, die beschreiben, wann die Abhängigkeit verwendet werden soll. Diese PEP erweitert die Umgebungsvariablen, um die Spezifizierung von Abhängigkeiten basierend auf spezifischen ABI-Features des Python-Interpreters zu ermöglichen. Dazu definiert sie eine Reihe von ABI-Features und spezifiziert, wie diese für Umgebungsvariablen als neue Variablen, sys_abi_features, verfügbar gemacht werden.
Motivation
Im Jahr 2015 etablierte PEP 508 Umgebungsvariablen, um Abhängigkeiten basierend auf Umgebungsbedingungen zu spezifizieren. Die Entwicklung des freigeschalteten CPython [1] hat die Notwendigkeit einer Umgebungsvariable hervorgehoben, um zwischen verschiedenen ABI-Features, mit denen der Interpreter erstellt wurde, zu unterscheiden. Zum Beispiel gibt es derzeit keine Möglichkeit, zwischen einem GIL-aktivierten und einem freigeschalteten CPython-Interpreter mit einer Umgebungsvariable zu unterscheiden. Dies führt zu realen Problemen bei der Einführung von Freischaltung und deren schrittweisem Rollout. Wenn ein Python-Paket mit freigeschaltetem CPython kompatibel gemacht wird, benötigt es auch alle seine Build- und Laufzeitabhängigkeiten, um kompatibel zu sein. Das Erfassen der ersten Version einer Abhängigkeit, die genau in den Metadaten kompatibel ist, ist derzeit nicht möglich, und die Erhöhung der Mindestversion einer Abhängigkeit auch für den GIL-aktivierten Build ist in der Regel unerwünscht, da sie die Kompatibilität zwischen Paketen unnötigerweise einschränkt.
Einige konkrete Beispiele für solche Probleme wurden im Discourse-Thread Environment marker for free-threading diskutiert.
- Cython hat (experimentelle) Unterstützung für Freischaltung nur in seinem Master-Zweig und wird von vielen Projekten verwendet, die bereits
cp313tWheels veröffentlichen. Die Wahl der falschen Cython-Version verursacht viele obskure Build-Fehler und Laufzeitabstürze. Es wäre vorteilhaft, wenn die Metadaten dies ausdrücken könnten (vgl. Require Cython Pre-release for Free-Threaded Python). - CFFI hat noch keine Unterstützung für Freischaltung, und Armin Rigo, einer der Maintainer, hat erklärt, dass es eine gute Idee sein könnte,
cffizu forken, die Unterstützung für Freischaltung zu implementieren und erst mit einem einzigen großen PR, der die Unterstützung hinzufügt, zum CFFI-Projekt zurückzukehren, nachdem die Funktionalität „vernünftig gut getestet wurde (entweder als Tests oder, besser in diesem Fall, getestet durch die Nutzung in verschiedenen anderen Projekten)“. Es gibt viele Projekte, die voncffiabhängen. Sie sind wahrscheinlich damit einverstanden, einen Fork für Freischaltung zu verwenden, aber einen Fork für >=3.13 oder für alle Python-Versionen zu verwenden, erscheint wie eine viel größere Bitte und störender für Distributionspackager.
Auch wenn diese konkreten Beispiele später in diesem Jahr von Cython und CFFI mit kompatiblen Releases behoben werden können, wird sich dasselbe Problem weiter oben im Stack wiederholen. Der Rollout von Freischaltung wird voraussichtlich mehrere Jahre dauern, und eine Umgebungsvariable für Freischaltung wird diesen Rollout erheblich erleichtern.
Ein weiteres wichtiges ABI-Feature, das noch nicht von Umgebungsvariablen abgedeckt ist, ist die Bitness des Interpreters. In den meisten Fällen reichen die sys_platform oder platform_system Variablen aus, da pro Plattform nur eine Bitness verwendet wird. Dies ist jedoch unter Windows nicht der Fall: Sowohl 32-Bit- als auch 64-Bit-Python-Interpreter werden auf x86-64 Windows weit verbreitet eingesetzt. Die Unfähigkeit, zwischen beiden zu unterscheiden, kann für Pakete mit kompilierten Erweiterungen relevant sein. Zum Beispiel stellt SciPy keine win32 Wheels bereit (es kann dies aufgrund fehlender geeigneter 32-Bit-Compiler-Toolchains mit Fortran-Unterstützung nicht tun). Diese fehlenden Wheels können besonders für Projekte, bei denen SciPy nur eine optionale Abhängigkeit ist, umständlich sein. In diesem Fall wäre es nützlich, angeben zu können, dass SciPy erforderlich ist, *es sei denn*, der Interpreter ist ein 32-Bit-Interpreter unter Windows (vgl. Require SciPy Unless on 32-bit win32), um fehlerhafte Installationen aus dem Quellcode aufgrund fehlender Wheels zu vermeiden.
Begründung
Die Absicht dieser PEP ist es, ihre Kernfunktionen mit minimalen Auswirkungen auf das bestehende Ökosystem einzuführen. Die in PEP 508 vorgeschlagene Grammatik eignet sich gut für eine einfache Erweiterung, um die neue Umgebungsvariable aufzunehmen.
Eine vorausschauende Betrachtung von freigeschaltetem Python
PEP 703, der angenommene Vorschlag für Freischaltung, besagt, dass die Einführung von freigeschaltetem Python schrittweise erfolgen soll, was vom Python Steering Council im PEP 703 Akzeptanzpost näher erläutert wurde, um einen dreistufigen Prozess über mehrere Releases hinweg zu bedeuten. Es ist daher wichtig sicherzustellen, dass die Mechanismen dieser PEP für Python-Interpreter nutzbar sind, bei denen entweder Freischaltung oder Nicht-Freischaltung die Standardoption oder die einzige Option sein könnte.
Zum Zeitpunkt der Erstellung befindet sich freigeschaltetes Python in Phase I: Experimentelle Phase. In dieser Phase besteht ein dringender Bedarf an den vorgeschlagenen Umgebungsvariablen, um den Übergang zu freigeschaltetem Python zu unterstützen, da Paketautoren schrittweise Unterstützung hinzufügen.
Mit zunehmender Anzahl von Paketen mit Unterstützung, und insbesondere während Phase II: Unterstützt, aber nicht standardmäßig, erwarten wir weiterhin einen starken Bedarf an Umgebungsvariablen, um den Übergang zu erleichtern.
Wenn freigeschaltetes Python in Phase III: Standard-Phase eintritt, wird der Bedarf an Umgebungsvariablen abnehmen, obwohl zu diesem Zeitpunkt unklar ist, ob das GIL-aktivierte Python vollständig abgeschafft wird (es kann als nicht standardmäßige Build-Option verfügbar bleiben). Wenn es fortbesteht, kann der umgekehrte Bedarf an der ABI-Feature-Erkennung entstehen.
Tatsächlich kann es in allen drei Phasen für Paketautoren notwendig sein, spezifische Versionen ihrer Abhängigkeiten basierend auf den ABI-Features auszuwählen, mit einer Verschiebung von GIL-aktiviert als Standard zu Freischaltung als Standard im Laufe der Zeit.
Die ABI-Features sind mit diesem Ziel konzipiert, um die Nützlichkeit und Einfachheit für die absehbare Zukunft in einem sich verändernden Python-Ökosystem zu gewährleisten.
Bezug zu anderen PEPs
Diese PEP erweitert Umgebungsvariablen um Mengenoperationen für ABI-Features. PEP 751 enthält eine ähnliche Erweiterung für Lockfile-spezifische Umgebungsvariablen; obwohl die beiden unabhängig voneinander entwickelt wurden, sind sie dort, wo sie sich in Bezug auf die neuen Mengenoperationen überschneiden, kompatibel.
Spezifikation
Die Schlüsselwörter „MUSS“, „DARF NICHT“, „ERFORDERLICH“, „SOLL“, „SOLL NICHT“, „EMPFOHLEN“, „KANN“ und „OPTIONAL“ werden in diesem Dokument wie in RFC 2119 beschrieben interpretiert.
ABI-Features
ABI-Features sind intrinsische Eigenschaften des Python-Interpreters, ausgedrückt als einfache, verständliche Zeichenketten. Allerdings sind nicht alle Features für alle Python-Interpreter oder Python-Versionen gleichermaßen anwendbar. Zum Beispiel ist die Unterscheidung zwischen freigeschalteten und GIL-aktivierten Interpretern erst ab CPython 3.13 relevant, aber die Bitness des Interpreters ist für alle Interpreter relevant.
Alle Interpreter MÜSSEN die folgenden ABI-Features wie angegeben behandeln. ABI-Features, die auf bestimmte Interpreter beschränkt sind, DÜRFEN NICHT von anderen Interpretern bereitgestellt werden. Die Features sind in Gruppen unterteilt, und für jede Gruppe MUSS genau ein Feature vorhanden sein, es sei denn, die Gruppe ist als optional gekennzeichnet, in welchem Fall höchstens ein Feature vorhanden sein darf.
free-threadingodergil-enabled(nur CPython)- Wenn der Python-Interpreter freigeschaltet ist, MUSS das Feature
free-threadingvorhanden sein und das Featuregil-enabledDARF NICHT vorhanden sein. Andernfalls MUSS das Featuregil-enabledvorhanden sein und das Featurefree-threadingDARF NICHT vorhanden sein. debug(nur CPython, optional)- Dieses ABI-Feature ist für den
--with-pydebugBuild von CPython reserviert. Wenn der Interpreter ein CPython-Interpreter mitPy_DEBUGFähigkeiten ist, MUSS das Featuredebugvorhanden sein. Auf POSIX-Systemen entspricht dies dem Python-Ausdruck"d" in sys.abiflags. 32-bitoder64-bit(optional)- Die Bitness des Interpreters, d. h., ob es sich um einen 32-Bit- oder 64-Bit-Build handelt [2]. Wenn die Bitness unbekannt ist oder weder 32-Bit noch 64-Bit ist, DARF dieses Feature NICHT vorhanden sein.
Die sys_abi_features Umgebungsvariable
Um ABI-Features in Abhängigkeitsspezifikationen verfügbar zu machen, wird eine neue Umgebungsvariable, sys_abi_features, zum Format der Abhängigkeitsspezifikationen hinzugefügt.
Dazu müssen wir die in PEP 508 dargelegte und in den Dependency specifiers gepflegte Grammatik erweitern und die möglichen Werte dokumentieren.
Die Grammatik wird um die sys_abi_features Variablen erweitert, indem die Definition von env_var wie folgt modifiziert wird
env_var = ('python_version' | 'python_full_version' |
'os_name' | 'sys_platform' | 'platform_release' |
'platform_system' | 'platform_version' |
'platform_machine' | 'platform_python_implementation' |
'implementation_name' | 'implementation_version' |
'sys_abi_features' |
'extra' # ONLY when defined by a containing layer
)
Ähnlich wie die Grammatik wird auch die Übersichtstabelle der Umgebungsvariablen in den Dependency specifiers erweitert, um die folgende Zeile hinzuzufügen
| Variable | Python-Äquivalent | Beispielwerte |
|---|---|---|
sys_abi_features |
kein direktes Äquivalent verfügbar | {'free-threading', '64-bit'}, {'gil-enabled', 'debug', '32-bit'} |
Mit diesen Ergänzungen können ABI-Features in Abhängigkeitsspezifikationen über den in Operator zum Testen auf das Vorhandensein eines Features oder den not in Operator zum Testen auf das Fehlen eines Features verwendet werden.
Beispiele
Cython Pre-Release für freigeschaltetes Python erforderlich
Um eine Pre-Release-Version von Cython nur für einen freigeschalteten Python-Interpreter zu benötigen, kann die folgende Abhängigkeitsspezifikation verwendet werden
cython >3.1.0a1; "free-threading" in sys_abi_features
cython ==3.0.*; "free-threading" not in sys_abi_features
SciPy erforderlich, außer unter 32-Bit win32
Um SciPy zu benötigen, es sei denn, es handelt sich um einen 32-Bit-Interpreter unter Windows, kann die folgende Abhängigkeitsspezifikation verwendet werden
scipy; platform_system != "Windows" or "32-bit" not in sys_abi_features
NumPy für einen freigeschalteten Interpreter mit Debugging-Funktionen erforderlich
Um NumPy nur für einen freigeschalteten Interpreter mit Debugging-Fähigkeiten zu benötigen, kann die folgende Abhängigkeitsspezifikation verwendet werden
numpy; "free-threading" in sys_abi_features and "debug" in sys_abi_features
Abwärtskompatibilität
Dies ist eine reine Erweiterung der bestehenden Umgebungsvariablen und beeinträchtigt keine bestehenden Umgebungsvariablen oder Abhängigkeitsspezifikationen, daher gibt es keine direkten Abwärtskompatibilitätsprobleme.
Die Einführung der Funktion hat jedoch Auswirkungen auf eine Reihe von Ökosystem-Tools, insbesondere auf diejenigen, die versuchen, die Daten in pyproject.toml und requirements.txt zu analysieren.
Tools prüfen und aktualisieren
Eine breite Palette von Tools versteht Python-Abhängigkeitsdaten, wie sie in requirements.txt-Dateien ausgedrückt werden (z. B. Dependabot, Tidelift usw.).
Solche Tools inspizieren Abhängigkeitsdaten und bieten in einigen Fällen toolgestützte oder vollautomatische Updates an. Wir gehen davon aus, dass solche Tools zunächst keine Unterstützung für die neuen Umgebungsvariablen haben werden, und eine breite Unterstützung im Ökosystem Monate oder sogar Jahre dauern könnte.
Infolgedessen erfahren Benutzer der neuen Umgebungsvariablen eine Verschlechterung ihrer Arbeitsabläufe und Tool-Unterstützung zum Zeitpunkt der Nutzung. Dies gilt für jeden neuen Standard, wo und wie Abhängigkeitsdaten kodiert werden.
Sicherheitsimplikationen
Diese PEP führt neue Syntax für die Angabe von Abhängigkeitsinformationen in Projekten ein. Sie führt jedoch keine neu spezifizierten Mechanismen für die Handhabung oder Auflösung von Abhängigkeiten ein.
Sie birgt daher keine Sicherheitsrisiken, außer denen, die bereits mit Werkzeugen verbunden sind, die zur Installation von Abhängigkeiten verwendet werden – d. h. bösartige Abhängigkeiten können hier spezifiziert werden, ebenso wie in requirements.txt-Dateien.
Wie man das lehrt
Die Verwendung von Umgebungsvariablen ist gut etabliert und wird hauptsächlich in Dependency specifiers kommuniziert. Die neue Umgebungsvariable kann in demselben Dokument eingeführt werden. Zusätzlich können sowohl für Paketautoren als auch für Benutzer spezifische Anleitungen für Freischaltung im Python free-threading guide bereitgestellt werden.
Referenzimplementierung
Die Referenzimplementierung für die Umgebungsvariablen ist in einem Fork der packaging-Bibliothek unter Environment markers for ABI features verfügbar.
Ein Demonstrationspaket ist ebenfalls verfügbar.
Da pip eine intern mitgelieferte Kopie von packaging verwendet, stellen wir auch eine gepatchte Version von pip bereit, die die mitgelieferte packaging durch die oben verlinkte Referenzimplementierung ersetzt.
Abgelehnte Ideen
Erweiterungsmechanismus
In einer frühen Diskussion über das Thema (Environment marker for free-threading) wurde die Idee eines allgemeinen Erweiterungsmechanismus für Umgebungsvariablen aufgeworfen. Obwohl es verlockend ist, einen ganzen PEP-Prozess zu umgehen, falls in Zukunft neue Umgebungsvariablen benötigt werden, gibt es zwei Hauptprobleme.
Erstens würde ein vollständig dynamischer Mechanismus Schwierigkeiten für Tools darstellen, die auf statische Analyse von Abhängigkeitsspezifikationen angewiesen sind.
Das bedeutet, dass selbst wenn ein dynamischer Mechanismus übernommen würde, neue Umgebungsvariablen wahrscheinlich immer noch in einer PEP dargelegt werden müssten.
Zweitens würde die Einführung eines dynamischen Mechanismus eine komplexere Implementierung in der Packaging-Bibliothek erfordern, was eine deutliche Abweichung vom aktuellen Ansatz wäre.
Offene Fragen
Andere Umgebungsvariablen
Wenn derzeit andere Umgebungsvariablen benötigt werden, könnte diese PEP erweitert werden, um diese aufzunehmen.
Andere Werkzeuge
Die Referenzimplementierung basiert auf der packaging-Bibliothek und pip. Wir haben bestätigt, dass dies das Bauen und Installieren von Paketen mit verschiedenen Build-Backends ermöglicht. Es ist möglich, dass weitere Tools zur Referenzimplementierung hinzugefügt werden sollten.
Fußnoten
Danksagungen
Vielen Dank an Filipe Laíns für den Vorschlag des abi_features-Attributs und an Stephen Rosen für den Abschnitt zur Abwärtskompatibilität von PEP 735, der als Vorlage für den entsprechenden Abschnitt in dieser PEP diente.
Urheberrecht
Dieses Dokument wird in die Public Domain oder unter die CC0-1.0-Universal-Lizenz gestellt, je nachdem, welche Lizenz permissiver ist.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0780.rst
Zuletzt geändert: 2025-04-17 09:38:03 GMT