PEP 711 – PyBI: ein Standardformat für die Verteilung von Python-Binärdateien
- Autor:
- Nathaniel J. Smith <njs at pobox.com>
- PEP-Delegate:
- TODO
- Discussions-To:
- Discourse thread
- Status:
- Entwurf
- Typ:
- Standards Track
- Thema:
- Packaging
- Erstellt:
- 06-Apr-2023
- Post-History:
- 06-Apr-2023
Zusammenfassung
„Wie Wheels, aber statt eines vorkompilierten Python-Pakets ist es ein vorkompilierter Python-Interpreter“
Motivation
Endziel: Pypi.org verfügt über vorkompilierte Pakete für alle Python-Versionen auf allen gängigen Plattformen, sodass automatisierte Tools sie leicht abrufen und einrichten können. Es wird schnell und einfach, Python-Vorabversionen auszuprobieren, Python-Versionen in CI festzulegen, eine temporäre Umgebung zu erstellen, um einen Bug-Report zu reproduzieren, der nur bei einer bestimmten Python-Punktversion auftritt, usw.
Erster Schritt (dieser PEP): Definieren eines Standard-Paketdateiformats zum Speichern vorkompilierter Python-Interpreter, das vorhandene Python-Paketstandards so weit wie möglich wiederverwendet.
Beispiele
Beispiel-Pybi-Builds sind unter pybi.vorpus.org verfügbar. Es handelt sich um Zip-Dateien, sodass Sie sie entpacken und im Inneren nachsehen können, wenn Sie sich ein Bild von ihrer Struktur machen möchten.
Sie können auch die Tools, die ich zu ihrer Erstellung verwendet habe, ansehen.
Spezifikation
Dateiname
Dateiname: {distribution}-{version}[-{build tag}]-{platform tag}.pybi
Dies entspricht dem in PEP 427 definierten Wheel-Dateiformat, mit Ausnahme des Weglassens des {python tag} und {abi tag} und der Änderung der Erweiterung von .whl zu .pybi.
Zum Beispiel:
cpython-3.9.3-manylinux_2014.pybicpython-3.10b2-win_amd64.pybi
Genau wie bei Wheels können Sie, wenn ein pybi mehrere Plattformen unterstützt, diese durch Punkte trennen, um eine „komprimierte Tag-Menge“ zu erstellen.
cpython-3.9.5-macosx_11_0_x86_64.macosx_11_0_arm64.pybi
(Obwohl dies in der Praxis wahrscheinlich nicht viel verwendet wird, wird der obige Dateiname beispielsweise idiomatischer als cpython-3.9.5-macosx_11_0_universal2.pybi geschrieben.)
Dateiinhalte
Eine .pybi-Datei ist eine Zip-Datei, die direkt an eine beliebige Stelle entpackt und dann als in sich geschlossene Python-Umgebung verwendet werden kann. Es gibt kein .data-Verzeichnis oder Installationsschema-Schlüssel, da die Python-Umgebung weiß, welches Installationsschema sie verwendet, und die Dinge daher von Anfang an an die richtigen Stellen legen kann.
Der Teil „beliebige Stelle“ ist wichtig: Der pybi darf keine fest codierten absoluten Pfade enthalten. Insbesondere dürfen vorinstallierte Skripte in ihren Shebang-Zeilen KEINE absoluten Pfade einbetten.
Ähnlich wie das Verzeichnis <package>-<version>.dist-info von Wheels muss das Pybi-Archiv ein Verzeichnis auf oberster Ebene namens pybi-info/ enthalten. (Begründung: Die Benennung als pybi-info statt dist-info stellt sicher, dass Tools nicht verwirrt werden, welche Art von Metadaten sie betrachten; das Weglassen des Teils {name}-{version} ist in Ordnung, da nur ein pybi in ein bestimmtes Verzeichnis installiert werden kann.) Das Verzeichnis pybi-info/ enthält mindestens die folgenden Dateien:
.../PYBI: Metadaten über das Archiv selbst, im selben RFC822-ähnlichen Format wie die DateienMETADATAundWHEEL.Pybi-Version: 1.0 Generator: {name} {version} Tag: {platform tag} Tag: {another platform tag} Tag: {...and so on...} Build: 1 # optional
.../RECORD: wie bei Wheels, außer siehe Hinweis zu Symlinks unten..../METADATA: Im selben Format wie in der aktuellen Kernmetadatenspezifikation beschrieben, mit der Ausnahme, dass die folgenden Schlüssel verboten sind, da sie keinen Sinn ergeben:Requires-DistProvides-ExtraRequires-Python
Und außerdem gibt es einige neue, erforderliche Schlüssel, die unten beschrieben werden.
Pybi-spezifische Kernmetadaten
Hier ist ein Beispiel für die neuen METADATA-Felder, bevor wir die vollständigen Details angeben:
Pybi-Environment-Marker-Variables: {"implementation_name": "cpython", "implementation_version": "3.10.8", "os_name": "posix", "platform_machine": "x86_64", "platform_system": "Linux", "python_full_version": "3.10.8", "platform_python_implementation": "CPython", "python_version": "3.10", "sys_platform": "linux"}
Pybi-Paths: {"stdlib": "lib/python3.10", "platstdlib": "lib/python3.10", "purelib": "lib/python3.10/site-packages", "platlib": "lib/python3.10/site-packages", "include": "include/python3.10", "platinclude": "include/python3.10", "scripts": "bin", "data": "."}
Pybi-Wheel-Tag: cp310-cp310-PLATFORM
Pybi-Wheel-Tag: cp310-abi3-PLATFORM
Pybi-Wheel-Tag: cp310-none-PLATFORM
Pybi-Wheel-Tag: cp39-abi3-PLATFORM
Pybi-Wheel-Tag: cp38-abi3-PLATFORM
Pybi-Wheel-Tag: cp37-abi3-PLATFORM
Pybi-Wheel-Tag: cp36-abi3-PLATFORM
Pybi-Wheel-Tag: cp35-abi3-PLATFORM
Pybi-Wheel-Tag: cp34-abi3-PLATFORM
Pybi-Wheel-Tag: cp33-abi3-PLATFORM
Pybi-Wheel-Tag: cp32-abi3-PLATFORM
Pybi-Wheel-Tag: py310-none-PLATFORM
Pybi-Wheel-Tag: py3-none-PLATFORM
Pybi-Wheel-Tag: py39-none-PLATFORM
Pybi-Wheel-Tag: py38-none-PLATFORM
Pybi-Wheel-Tag: py37-none-PLATFORM
Pybi-Wheel-Tag: py36-none-PLATFORM
Pybi-Wheel-Tag: py35-none-PLATFORM
Pybi-Wheel-Tag: py34-none-PLATFORM
Pybi-Wheel-Tag: py33-none-PLATFORM
Pybi-Wheel-Tag: py32-none-PLATFORM
Pybi-Wheel-Tag: py31-none-PLATFORM
Pybi-Wheel-Tag: py30-none-PLATFORM
Pybi-Wheel-Tag: py310-none-any
Pybi-Wheel-Tag: py3-none-any
Pybi-Wheel-Tag: py39-none-any
Pybi-Wheel-Tag: py38-none-any
Pybi-Wheel-Tag: py37-none-any
Pybi-Wheel-Tag: py36-none-any
Pybi-Wheel-Tag: py35-none-any
Pybi-Wheel-Tag: py34-none-any
Pybi-Wheel-Tag: py33-none-any
Pybi-Wheel-Tag: py32-none-any
Pybi-Wheel-Tag: py31-none-any
Pybi-Wheel-Tag: py30-none-any
Spezifikation
Pybi-Environment-Marker-Variables: Der Wert aller PEP 508-Umgebungsmarker-Variablen, die über Installationen dieses Pybi hinweg statisch sind, als JSON-Dictionary. Zum Beispiel:python_versionwird immer vorhanden sein, da ein Python-3.10-Paket immerpython_version == "3.10"hat.platform_versionwird im Allgemeinen nicht vorhanden sein, da es detaillierte Informationen über das Betriebssystem liefert, auf dem Python ausgeführt wird, zum Beispiel:#60-Ubuntu SMP Thu May 6 07:46:32 UTC 2021platform_releasehat ähnliche Probleme.platform_machinewird *meistens* vorhanden sein, mit Ausnahme von macOS Universal2-Pybis: Diese können potenziell im x86-64- oder im ARM64-Modus ausgeführt werden, und wir wissen nicht, welcher Modus bis zur tatsächlichen Ausführung des Interpreters gilt, daher können wir ihn nicht in statischen Metadaten aufzeichnen.
Begründung: In vielen Fällen sollte dies einem Resolver, der unter Linux läuft, ermöglichen, Paket-Pins für eine Python-Umgebung unter Windows oder umgekehrt zu berechnen, solange der Resolver Zugriff auf die .pybi-Datei der Zielplattform hat. (Beachten Sie, dass
Requires-Python-Beschränkungen durch Verwendung despython_full_version-Werts überprüft werden können.) Obwohl wir einige Schlüssel manchmal weglassen müssen, sind sie entweder ziemlich nutzlos (platform_version,platform_release) oder können vom Resolver rekonstruiert werden (platform_machine).Die Marker sind auch allgemein nützliche Informationen, auf die zugegriffen werden kann. Wenn Sie beispielsweise ein
pypy3-7.3.2-Pybi haben und wissen möchten, welche Python-Sprachversion dies unterstützt, dann ist dies impython_version-Marker aufgezeichnet.(Hinweis: Möglicherweise möchten wir
platform_versionundplatform_releasedeprecaten/entfernen? Sie sind problematisch und ich kann keine Fälle finden, in denen sie nützlich sind. Aber das liegt außerhalb des Umfangs dieser speziellen PEP.)Pybi-Paths: Die für die Installation von Wheels benötigten Installationspfade (gleiche Schlüssel wiesysconfig.get_paths()), als relative Pfade ab dem Stammverzeichnis der Zip-Datei, als JSON-Dictionary.Diese Pfade MÜSSEN im Unix-Format mit Schrägstrichen als Trennzeichen und nicht mit Backslashes geschrieben werden.
Es muss möglich sein, den Python-Interpreter aufzurufen, indem
{paths["scripts"]}/pythonausgeführt wird. Wenn alternative Interpreter-Einstiegspunkte vorhanden sind (z. B.pythonwfür Windows-GUI-Anwendungen), sollten diese ebenfalls in diesem Verzeichnis unter ihren üblichen Namen ohne Versionsnummer aufgeführt sein. (Sie können *auch* einenpython3.11-Symlink haben, wenn Sie möchten; es gibt keine Regel dagegen. Es ist nur so, dasspythonvorhanden und funktionsfähig sein muss.)Begründung:
Pybi-PathsundPybi-Wheel-Tags (siehe unten) reichen zusammen aus, damit ein Installer Wheels auswählen und sie in eine entpackte Pybi-Umgebung installieren kann, ohne Python aufrufen zu müssen. Außerdem müssen wir den Speicherort des Interpreters irgendwo festhalten, also ist das ein zweischneidiges Schwert.Pybi-Wheel-Tag: Die von diesem Interpreter unterstützten Wheel-Tags in bevorzugter Reihenfolge (am meisten bevorzugt zuerst, am wenigsten bevorzugt zuletzt), mit der Ausnahme, dass der spezielle Plattform-TagPLATFORMalle Plattform-Tags ersetzen sollte, die vom endgültigen Installationssystem abhängen.Diskussion: Es wäre schön™, wenn Installer die entsprechenden Wheel-Tags eines Pybis im Voraus berechnen könnten, damit sie Wheels in das entpackte Pybi installieren könnten, ohne den Python-Interpreter tatsächlich aufrufen zu müssen, um seine Tags abzufragen – sowohl aus Effizienzgründen als auch um exotischere Anwendungsfälle wie die Einrichtung einer Windows-Umgebung von einem Linux-Host aus zu ermöglichen.
Aber leider ist es unmöglich, die vollständige Menge der von einer Python-Installation unterstützten Plattform-Tags im Voraus zu berechnen, da sie vom endgültigen System abhängen können.
- Ein Pybi mit dem Tag
manylinux_2_12_x86_64kann immer Wheels verwenden, die alsmanylinux_2_12_x86_64getaggt sind. Es *kann* auch Wheels verwenden, die mitmanylinux_2_17_x86_64getaggt sind, aber nur, wenn das endgültige Installationssystem glibc 2.17+ hat. - Ein Pybi mit dem Tag
macosx_11_0_universal2(= x86-64 + ARM64-Unterstützung im selben Binärpaket) kann möglicherweise Wheels verwenden, die alsmacosx_11_0_arm64getaggt sind, aber nur, wenn es auf einem „Apple Silicon“-Computer installiert ist und im ARM64-Modus ausgeführt wird.
In diesen beiden Fällen kann ein Installationstool immer noch den geeigneten Satz von Wheel-Tags ermitteln, indem es die lokalen Plattform-Tags berechnet, die Wheel-Tag-Vorlagen aus
Pybi-Wheel-Tagentnimmt und die tatsächlichen unterstützten Plattformen anstelle des magischenPLATFORM-Strings einsetzt.Es gibt jedoch andere, noch kompliziertere Fälle.
- Sie können (normalerweise) sowohl 32-Bit- als auch 64-Bit-Anwendungen auf 64-Bit-Windows ausführen. Ein Pybi
- Installer könnte den Satz zulässiger Pybi-Tags auf der aktuellen Plattform als [
win32,win_amd64] berechnen. Aber Sie können diesen Satz nicht einfach nehmen und ihn in die Wheel-Tag-Vorlage des Pybis einsetzen, sonst erhalten Sie Unsinn.[ "cp39-cp39-win32", "cp39-cp39-win_amd64", "cp39-abi3-win32", "cp39-abi3-win_amd64", ... ]
Um dies zu handhaben, muss der Installer irgendwie verstehen, dass ein
manylinux_2_12_x86_64-Pybi einmanylinux_2_17_x86_64-Wheel verwenden kann, solange beides gültige Tags auf der aktuellen Maschine sind, aber einwin32-Pybi *kann kein*win_amd64-Wheel verwenden, auch wenn beides gültige Tags auf der aktuellen Maschine sind.
- Ein Pybi mit dem Tag
macosx_11_0_universal2kann möglicherweise Wheels verwenden, die alsmacosx_11_0_x86_64getaggt sind, aber nur, wenn es auf einer x86-64-Maschine installiert ist *oder* es auf einer ARM-Maschine installiert ist *und* der Interpreter mit dem magischen Zauberspruch aufgerufen wird, der macOS anweist, ein Binärpaket im x86-64-Modus auszuführen. Wie der Installer den Pybi aufrufen möchte, spielt also auch eine Rolle!
Die tatsächliche Verwendung von
Pybi-Wheel-Tag-Werten ist also weniger trivial, als es scheinen mag, und sie sind wahrscheinlich nur mit ziemlich ausgefeilten Tools nützlich. Aber intelligente Pybi-Installer müssen bereits viele dieser Plattformkompatibilitätsprobleme verstehen, um ein funktionierendes Pybi auswählen zu können, und für den Fall des plattformübergreifenden Pinning/Umgebungsaufbaus können Benutzer potenziell alle Informationen bereitstellen, die erforderlich sind, um genau zu disambiguieren, welche Plattform sie anvisieren. Daher ist es immer noch nützlich genug, um in die PyBI-Metadaten aufgenommen zu werden – Tools, die es nicht nützlich finden, können es einfach ignorieren.- Ein Pybi mit dem Tag
Sie können diese Metadatenwerte wahrscheinlich generieren, indem Sie dieses Skript auf dem kompilierten Interpreter ausführen.
import packaging.markers
import packaging.tags
import sysconfig
import os.path
import json
import sys
marker_vars = packaging.markers.default_environment()
# Delete any keys that depend on the final installation
del marker_vars["platform_release"]
del marker_vars["platform_version"]
# Darwin binaries are often multi-arch, so play it safe and
# delete the architecture marker. (Better would be to only
# do this if the pybi actually is multi-arch.)
if marker_vars["sys_platform"] == "darwin":
del marker_vars["platform_machine"]
# Copied and tweaked version of packaging.tags.sys_tags
tags = []
interp_name = packaging.tags.interpreter_name()
if interp_name == "cp":
tags += list(packaging.tags.cpython_tags(platforms=["xyzzy"]))
else:
tags += list(packaging.tags.generic_tags(platforms=["xyzzy"]))
tags += list(packaging.tags.compatible_tags(platforms=["xyzzy"]))
# Gross hack: packaging.tags normalizes platforms by lowercasing them,
# so we generate the tags with a unique string and then replace it
# with our special uppercase placeholder.
str_tags = [str(t).replace("xyzzy", "PLATFORM") for t in tags]
(base_path,) = sysconfig.get_config_vars("installed_base")
# For some reason, macOS framework builds report their
# installed_base as a directory deep inside the framework.
while "Python.framework" in base_path:
base_path = os.path.dirname(base_path)
paths = {key: os.path.relpath(path, base_path).replace("\\", "/") for (key, path) in sysconfig.get_paths().items()}
json.dump({"marker_vars": marker_vars, "tags": str_tags, "paths": paths}, sys.stdout)
Dies gibt ein JSON-Dictionary auf stdout aus, mit separaten Einträgen für jede Gruppe von Pybi-spezifischen Tags.
Symlinks
Derzeit werden Symlinks standardmäßig in allen Unix-Python-Installationen verwendet (z. B. bin/python3 -> bin/python3.9). Und darüber hinaus sind Symlinks *erforderlich*, um macOS-Framework-Builds in .pybi-Dateien zu speichern. Daher müssen wir im Gegensatz zu Wheel-Dateien Symlinks in .pybi-Dateien unbedingt unterstützen, damit sie überhaupt nützlich sind.
Symlinks in Zip-Dateien darstellen
Der De-facto-Standard für die Darstellung von Symlinks in Zip-Dateien ist die Info-Zip-Symlink-Erweiterung, die wie folgt funktioniert:
- Der Zielpfad des Symlinks wird wie die Dateiinhalte gespeichert.
- Die obersten 4 Bits des Unix-Berechtigungsfeldes werden auf
0xagesetzt, d.h.:permissions & 0xf000 == 0xa000. - Das Unix-Berechtigungsfeld wird wiederum als die obersten 16 Bits des Feldes „externe Attribute“ gespeichert.
Wenn Sie also das zipfile-Modul von Python verwenden, können Sie prüfen, ob ein ZipInfo einen Symlink repräsentiert, indem Sie Folgendes tun:
(zip_info.external_attr >> 16) & 0xf000 == 0xa000
Oder wenn Sie die zip-Crate von Rust verwenden, ist die entsprechende Prüfung:
fn is_symlink(zip_file: &zip::ZipFile) -> bool {
match zip_file.unix_mode() {
Some(mode) => mode & 0xf000 == 0xa000,
None => false,
}
}
Wenn Sie unter Unix sind, verstehen Ihre zip- und unzip-Befehle dieses Format wahrscheinlich bereits.
Symlinks in RECORD-Dateien darstellen
Normalerweise listet eine RECORD-Datei jede Datei + ihren Hash + ihre Länge auf.
my/favorite/file,sha256=...,12345
Für Symlinks schreiben wir stattdessen:
name/of/symlink,symlink=path/to/symlink/target,
Das heißt: Wir verwenden eine spezielle „Hash-Funktion“ namens symlink und speichern dann das tatsächliche Symlink-Ziel als „Hash-Wert“. Die Länge bleibt leer.
Begründung: Wir sind bereits an die RECORD-Datei gebunden, die eine redundante Überprüfung von allem im Hauptarchiv enthält. Daher müssen wir für Symlinks zumindest eine Art von Hash speichern, plus eine Art von Flagge, um anzuzeigen, dass es sich um einen Symlink handelt. Da Symlink-Zielzeichenketten ungefähr die gleiche Größe wie ein Hash haben, können wir sie auch direkt speichern. Dies erleichtert auch den Zugriff auf die Symlink-Informationen für Tools, die die Info-Zip-Symlink-Erweiterung nicht verstehen, und ermöglicht das verlustfreie Entpacken und erneute Packen eines Unix-Pybis auf einem Windows-System, was jemand zu einem bestimmten Zeitpunkt praktisch finden könnte.
Speichern von Symlinks in pybi-Dateien
Wenn ein Pybi-Ersteller einen Symlink speichert, MUSS er beide oben genannten Mechanismen verwenden: Speichern im Zip-Archiv direkt unter Verwendung der Info-Zip-Darstellung und Aufzeichnung im RECORD-File.
Pybi-Konsumenten SOLLTEN überprüfen, ob die Symlinks im Archiv und in der RECORD-Datei miteinander übereinstimmen.
Wir haben auch erwogen, *nur* die RECORD-Datei zum Speichern von Symlinks zu verwenden, aber dann würde das normale unzip-Tool sie nicht entpacken können, und das würde die Installation eines Pybis aus einem Shell-Skript erschweren.
Einschränkungen
Symlinks ermöglichen eine Menge potenziellen Unrats. Um die Dinge unter Kontrolle zu halten, legen wir die folgenden Einschränkungen fest:
- Symlinks DÜRFEN NICHT in
.pybis verwendet werden, die für Windows oder andere Plattformen mit fehlender First-Class-Symlink-Unterstützung bestimmt sind. - Symlinks DÜRFEN NICHT innerhalb des Verzeichnisses
pybi-infoverwendet werden. (Begründung: Es gibt keinen Bedarf und es vereinfacht die Dinge für Resolver, die Informationen auspybi-infoextrahieren müssen, ohne das gesamte Archiv zu entpacken.) - Symlink-Ziele MÜSSEN relative Pfade sein und MÜSSEN sich innerhalb des Pybi-Verzeichnisses befinden.
- Wenn
A/B/...als Symlink im Archiv aufgezeichnet wird, darf es KEINE anderen Einträge im Archiv mit dem NamenA/B/.../Cgeben.Wenn beispielsweise ein Archiv einen Symlink
foo -> barhat und später im Archiv eine reguläre Datei namensfoo/blah.pyvorhanden ist, könnte ein naiver Entpacker potenziell eine Datei namensbar/blah.pyschreiben. Seien Sie nicht naiv.
Entpacker MÜSSEN überprüfen, ob diese Regeln befolgt werden, denn ohne sie könnten Angreifer böswillige Symlinks wie foo -> /etc/passwd oder foo -> ../../../../../etc + foo/passwd -> ... erstellen und Unheil anrichten.
Nicht-normative Kommentare
Warum nicht einfach conda verwenden?
Dies liegt nicht wirklich im Umfang dieser PEP, aber da Conda ein beliebter Weg ist, binäre Python-Interpreter zu verteilen, ist dies eine natürliche Frage.
Die einfache Antwort ist: Conda ist großartig! Aber es gibt viele Python-Benutzer, die keine Conda-Benutzer sind, und sie verdienen auch nette Dinge. Diese PEP gibt ihnen einfach eine weitere Option.
Die tiefere Antwort ist: Die Maintainer, die Pakete auf PyPI hochladen, sind das Rückgrat des Python-Ökosystems. Sie sind die erste Zielgruppe für Python-Paketierungs-Tools. Und eine Sache, die sie wollen, ist, ein Paket einmal hochzuladen und es über alle verschiedenen Arten, wie Python bereitgestellt wird, zugänglich zu machen: in Debian und Fedora und Homebrew und FreeBSD, in Conda-Umgebungen, in Monorepos großer Unternehmen, in Nix, in Blender-Plugins, in RenPy-Spielen, ... Sie verstehen schon.
All diese Umgebungen haben ihre eigenen Werkzeuge und Strategien zur Verwaltung von Paketen und Abhängigkeiten. Was PyPI und Wheels also besonders macht, ist, dass sie darauf ausgelegt sind, Abhängigkeiten auf eine *standardisierte, abstrakte Weise* zu beschreiben, die all diese nachgelagerten Systeme verbrauchen und in ihre lokalen Konventionen umwandeln können. Deshalb verwenden Paketmaintainer Python-spezifische Metadaten und laden auf PyPI hoch: weil es ihnen ermöglicht, all diese Systeme gleichzeitig anzusprechen. Jedes Mal, wenn Sie ein Python-Paket für Conda erstellen, wird ein Zwischen-Wheel generiert, da Wheels die gemeinsame Sprache sind, mit der Python-Paket-Build-Systeme und Conda miteinander sprechen können.
Aber wenn Sie dann ein Maintainer sind, der ein sdist+wheels veröffentlicht, möchten Sie natürlich testen, was Sie veröffentlichen, was von beliebigen PyPI-Paketen und -Versionen abhängen kann. Sie benötigen also Tools, die Python-Umgebungen direkt aus PyPI erstellen, und Conda ist dafür grundsätzlich nicht ausgelegt. Daher sind Conda und Pip für verschiedene Fälle notwendig, und dieser Vorschlag zielt zufällig auf die Pip-Seite dieser Gleichung ab.
Sdists (oder nicht)
Es könnte cool sein, ein „sdist“-Äquivalent für Pybis zu haben, d.h. eine Art Format für eine Python-Quellveröffentlichung, die strukturiert genug ist, um Tools automatisch abrufen und in ein Pybi umwandeln zu lassen, für Plattformen, auf denen keine vorkompilierten Pybis verfügbar sind. Aber das ist für die MVP nicht notwendig und öffnet eine Büchse der Pandora, also kümmern wir uns später darum.
Welche Pakete sollten in einem pybi gebündelt werden?
Pybi-Builder haben die Möglichkeit, genau auszuwählen, was in sie hineinkommt. Sie könnten beispielsweise einige vorinstallierte Pakete in das site-packages-Verzeichnis des Pybis aufnehmen oder Teile der Standardbibliothek entfernen, die Sie nicht möchten. Wir können Sie nicht aufhalten! Wenn Sie jedoch Pakete vorinstallieren, wird dringend empfohlen, auch die entsprechenden Metadaten (.dist-info usw.) einzuschließen, damit Pip oder andere Tools verstehen können, was vor sich geht.
Für meine Prototyp-„Allzweck“-Pybis habe ich Folgendes gewählt:
- Stellen Sie sicher, dass
site-packages*leer* ist.Begründung: Bei herkömmlichen eigenständigen Python-Installern, die sich an Endbenutzer richten, möchten Sie wahrscheinlich mindestens
pipeinbeziehen, um Bootstrapping-Probleme zu vermeiden (PEP 453). Aber Pybis sind anders: Sie sind dafür konzipiert, von „intelligenten“ Tools installiert zu werden, die das Pybi als Teil eines größeren automatisierten Bereitstellungsprozesses verwenden. Für diese Installer ist es einfacher, von einem leeren Blatt zu starten und dann hinzuzufügen, was sie benötigen, als mit einigen vorinstallierten Paketen zu beginnen, die sie vielleicht wollen oder nicht wollen. (Und außerdem kann man immer nochpython -m ensurepipausführen.) - Vollständige Standardbibliothek einbeziehen, *außer*
test.Begründung: Das Top-Level-Modul
testenthält die Testsuite von CPython selbst. Es ist riesig (CPython ohnetestist ca. 37 MB, dann fügttestweitere ca. 25 MB hinzu!), und wird von regulärem Benutzercode praktisch nie verwendet. Außerdem lassen die offiziellen Nuget-Pakete, die offiziellen Manylinux-Images und mehrere Linux-Distributionen es aus, und das hat keine größeren Probleme verursacht.Dies scheint also der beste Weg zu sein, um breite Kompatibilität mit vernünftigen Download-/Installationsgrößen auszugleichen.
- Ich versende keine
.pyc-Dateien. Sie beanspruchen Speicherplatz beim Download, können auf dem endgültigen System zu minimalen Kosten generiert werden und entfernen durch ihr Weglassen eine Quelle für standortabhängige Informationen. (.pyc-Dateien speichern den absoluten Pfad der entsprechenden.py-Datei und fügen ihn in Tracebacks ein; Pybis sind jedoch verschiebbar, sodass der korrekte Pfad erst nach der Installation bekannt ist.)
Abwärtskompatibilität
Keine Abwärtskompatibilitätsprobleme.
Sicherheitsimplikationen
Keine Sicherheitsimplikationen, abgesehen von der Tatsache, dass jeder, der sich verpflichtet, Binärdateien zu verteilen, einen Plan für die Verwaltung ihrer Sicherheit erstellen muss (z. B. ob er einen neuen Build nach einem OpenSSL CVE veröffentlicht). Aber gemeinsam pflegen wir Kern-Python-Leute bereits Binärpakete für alle wichtigen Plattformen (macOS + Windows über python.org und Linux-Builds über das offizielle manylinux-Image), sodass selbst wenn wir offizielle CPython-Builds auf PyPI veröffentlichen, dies keine neuen Sicherheitsprobleme aufwirft.
Wie man das lehrt
Dies richtet sich nicht an Endbenutzer; ihre Erfahrung wird einfach sein, dass z. B. ihre pyenv- oder tox-Aufrufe magisch schneller und zuverlässiger werden (wenn die Maintainer dieser Projekte beschließen, diese PEP zu nutzen).
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-0711.rst
Zuletzt geändert: 2025-02-01 08:55:40 GMT