Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 751 – Ein Dateiformat zur Aufzeichnung von Python-Abhängigkeiten für reproduzierbare Installationen

Autor:
Brett Cannon <brett at python.org>
Status:
Final
Typ:
Standards Track
Thema:
Packaging
Erstellt:
24. Juli 2024
Post-History:
25. Juli 2024 30. Okt. 2024 15. Jan. 2025
Ersetzt:
665
Resolution:
31. März 2025

Inhaltsverzeichnis

Wichtig

Dieses PEP ist ein historisches Dokument. Die aktuelle, kanonische Spezifikation, pylock.toml-Spezifikation, wird auf der PyPA Specs Seite gepflegt.

×

Siehe den PyPA-Spezifikations-Update-Prozess, um Änderungen vorzuschlagen.

Zusammenfassung

Dieses PEP schlägt ein neues Dateiformat für die Angabe von Abhängigkeiten vor, um reproduzierbare Installationen in einer Python-Umgebung zu ermöglichen. Das Format ist so konzipiert, dass es von Menschen lesbar und von Maschinen generiert werden kann. Installer, die die Datei verbrauchen, sollten in der Lage sein, zu berechnen, was installiert werden muss, ohne dass eine Abhängigkeitsauflösung zur Installationszeit erforderlich ist.

Motivation

Derzeit gibt es keinen Standard, um eine unveränderliche Aufzeichnung wie eine Sperrdatei zu erstellen, die angibt, welche direkten und indirekten Abhängigkeiten in einer virtuellen Umgebung installiert werden sollen.

Angesichts der Tatsache, dass es mindestens fünf bekannte Lösungen für dieses Problem in der Community gibt (PDM, pip freeze, pip-tools, Poetry und uv), scheint ein allgemeiner Appetit auf Sperrdateien zu bestehen.

Diese Werkzeuge unterscheiden sich auch darin, welche Sperrszenarien sie unterstützen. Zum Beispiel generieren pip freeze und pip-tools nur Einmal-Sperrdateien für die aktuelle Umgebung, während PDM, Poetry und uv Sperren für mehrere Umgebungen und Anwendungsfälle gleichzeitig ermöglichen/versuchen. Es gibt auch Bedenken hinsichtlich des Mangels an sicheren Standardeinstellungen angesichts von Lieferkettenangriffen durch einige Werkzeuge (z. B. Einbeziehung von Hashes für Dateien).

Das Fehlen eines Standards hat auch einige Nachteile. Beispielsweise muss jedes Werkzeug, das mit Sperrdateien arbeiten möchte, ein Format wählen, das es unterstützen möchte, was Benutzer möglicherweise ununterstützt lässt (z. B. Dependabot unterstützt nur ausgewählte Werkzeuge, ebenso Cloud-Anbieter, die Abhängigkeitsinstallationen in Ihrem Namen durchführen können usw.). Es beeinträchtigt auch die Portabilität zwischen Werkzeugen, was zu Vendor-Lock-in führt. Ohne Kompatibilität und Interoperabilität werden Werkzeuge um Sperrdateien herum fragmentiert, wobei sowohl Benutzer als auch Werkzeuge im Voraus wählen müssen, welches Sperrdateiformat verwendet werden soll, was die Verwendung/den Wechsel zu anderen Formaten kostspielig macht (z. B. Werkzeuge zur Überprüfung einer Sperrdatei). Die Konzentration auf ein einziges Format beseitigt diese Kosten/Barrieren.

Am nächsten kommt dem Standard, den die Community hat, die Requirements-Dateien von pip, die alle oben genannten Werkzeuge entweder direkt als Dateiformat verwenden oder dorthin exportieren (d. h. requirements.txt). Leider ist das Format kein Standard, sondern wird per Konvention unterstützt. Es ist auch sehr stark auf die Bedürfnisse von pip zugeschnitten, was seine Flexibilität und Benutzerfreundlichkeit einschränkt (z. B. ist es ein proprietäres Dateiformat). Schließlich ist es nicht standardmäßig sicher (z. B. ist die Unterstützung von Dateihashes eine reine Opt-in-Funktion, man muss pip sagen, nicht nach anderen Abhängigkeiten außerhalb dessen zu suchen, was in der Requirements-Datei enthalten ist, usw.).

Hinweis

Ein Großteil der Motivation aus PEP 665 gilt auch für dieses PEP.

Begründung

Das von diesem PEP vorgeschlagene Dateiformat ist so konzipiert, dass es von Menschen lesbar ist. Dies dient dazu, dass der Inhalt der Datei von einem Menschen auditiert werden kann, um sicherzustellen, dass keine unerwünschten Abhängigkeiten in die Sperrdatei aufgenommen werden.

Das Dateiformat ist auch so konzipiert, dass es zur Installationszeit keinen Resolver benötigt. Dies vereinfacht die Nachvollziehbarkeit dessen, was installiert werden würde, wenn eine Sperrdatei verwendet wird, erheblich. Es sollte auch zu schnelleren Installationen führen, die viel häufiger vorkommen als die Erstellung einer Sperrdatei.

Die Daten in der Datei sollten von Werkzeugen, die nicht in Python geschrieben sind, verbrauchbar sein. Dies ermöglicht es beispielsweise Cloud-Hosting-Anbietern, ihr eigenes Werkzeug zur Durchführung von Installationen in ihrer bevorzugten Programmiersprache zu schreiben. Dies führt das Konzept von Lockern ein, die die Sperrdatei schreiben, und Installern, die aus einer Sperrdatei installieren (sie können dasselbe Werkzeug sein).

Das Dateiformat sollte gute Sicherheitseinstellungen fördern. Da das Format nicht von Menschen geschrieben werden soll, ist es zumutbar und keine kostspielige Belastung, wenn Werkzeuge sicherheitsbezogene Details bereitstellen.

Der Inhalt einer Sperrdatei sollte die überwiegende Mehrheit der Verwendungen von Requirements-Dateien ersetzen, wenn sie als Sperrdatei verwendet wird (z. B. was pip-tools und pip freeze ausgeben). Das bedeutet, dass das von diesem PEP spezifizierte Dateiformat zumindest als Exportziel für Werkzeuge dienen kann, die ihr eigenes internes Sperrdateiformat haben.

Sperrdateien können einmalig und mehrfach verwendet werden. Einmalige Sperrdateien sind Dinge wie requirements.txt-Dateien, die einen einzigen Anwendungsfall/Zweck erfüllen (weshalb es nicht ungewöhnlich ist, dass ein Projekt mehrere Requirements-Dateien für unterschiedliche Anwendungsfälle hat). Mehrfach verwendbare Sperrdateien stellen mehrere Anwendungsfälle innerhalb einer einzigen Datei dar, die oft durch Extras und Abhängigkeitsgruppen ausgedrückt werden. Daher unterstützt dieses PEP Ergänzungen zu Umgebungsmarkern, die die Angabe von Extras und Abhängigkeitsgruppen ermöglichen. Dies ermöglicht es einer einzelnen Sperrdatei, diese Fälle abzudecken. Dies reduziert nicht nur die Anzahl möglicher Sperrdateien, sondern erleichtert auch die Konsistenz eines einzelnen Pakets über alle Anwendungsfälle hinweg (bei mehreren Einmal-Sperrdateien ist eine Koordination über mehrere Sperrdateien erforderlich). Diese Unterstützung bedeutet auch, dass dieses PEP alle paketinstallationsbezogenen Daten unterstützt, die in einer pyproject.toml-Datei aufgezeichnet werden können. Die Hoffnung ist, dass diese Unterstützung es einigen Werkzeugen ermöglicht, ihre internen Sperrdateien vollständig fallen zu lassen und sich ausschließlich auf das zu verlassen, was dieses PEP spezifiziert.

Spezifikation

Dateiname

Eine Sperrdatei MUSS den Namen pylock.toml haben oder dem regulären Ausdruck r"^pylock\.([^.]+)\.toml$" entsprechen, wenn ein Name für die Sperrdatei gewünscht wird oder wenn mehrere Sperrdateien existieren. Die Verwendung der Dateiendung .toml dient dazu, die Syntaxhervorhebung in Editoren zu erleichtern und die Tatsache zu unterstreichen, dass das Dateiformat von Menschen lesbar sein soll. Das Präfix und Suffix einer benannten Datei MÜSSEN, wenn möglich, kleingeschrieben werden, zur einfachen Erkennung und Entfernung, z.B.

if len(filename) > 11 and filename.startswith("pylock.") and filename.endswith(".toml"):
    name = filename.removeprefix("pylock.").removesuffix(".toml")

Die Erwartung ist, dass Dienste, die automatisch aus Sperrdateien installieren, nach

  1. Der Sperrdatei mit dem Namen des Dienstes suchen und die Standardinstallation durchführen
  2. Eine Mehrfach-Sperrdatei pylock.toml mit einer Abhängigkeitsgruppe mit dem Namen des Dienstes
  3. Die Standardinstallation von pylock.toml

Zum Beispiel würde ein Cloud-Hosting-Dienst namens "spam" zuerst nach pylock.spam.toml suchen, um daraus zu installieren, und wenn diese Datei nicht existiert, dann aus pylock.toml installieren und nach einer Abhängigkeitsgruppe namens "spam" suchen, falls vorhanden.

Die Sperrdatei(en) SOLLTEN im Verzeichnis entsprechend dem Geltungsbereich der Sperrdatei liegen. Eine Sperrung gegen eine einzelne pyproject.toml würde beispielsweise die pylock.toml im selben Verzeichnis platzieren. Wenn die Sperrdatei mehrere Projekte in einem Monorepo abdeckt, dann ist die Erwartung, dass die pylock.toml-Datei im Verzeichnis liegt, das alle zu sperrenden Projekte enthielt.

Dateiformat

Das Format der Datei ist TOML.

Werkzeuge SOLLTEN ihre Sperrdateien konsistent schreiben, um Rauschen in der Diff-Ausgabe zu minimieren. Schlüssel in Tabellen – einschließlich der Top-Level-Tabelle – SOLLTEN in konsistenter Reihenfolge aufgezeichnet werden (falls Inspiration gewünscht wird, hat dieses PEP versucht, die Schlüssel in logischer Reihenfolge aufzuschreiben). Ebenso SOLLTEN Werkzeuge Arrays in konsistenter Reihenfolge sortieren. Die Verwendung von Inline-Tabellen SOLLTE ebenfalls konsistent gehalten werden.

lock-version

  • Typ: String; Wert von "1.0"
  • Erforderlich?: Ja
  • Inspiration: Metadata-Version
  • Aufzeichnung der Dateiformatversion, der die Datei entspricht.
  • Dieses PEP spezifiziert die initiale Version – und den einzigen gültigen Wert, bis zukünftige Updates des Standards diese ändern – als "1.0".
  • Wenn ein Werkzeug die Hauptversion unterstützt, aber nicht die Nebenversion, SOLLTE ein Werkzeug eine Warnung ausgeben, wenn ein unbekannter Schlüssel gesehen wird.
  • Wenn ein Werkzeug keine Hauptversion unterstützt, MUSS es einen Fehler ausgeben.

environments

  • Typ: Array von Strings
  • Erforderlich?: Nein
  • Inspiration: uv
  • Eine Liste von Umgebungsmarkern, für die die Sperrdatei als kompatibel gilt.
  • Werkzeuge SOLLTEN exklusive/nicht überlappende Umgebungsmarker schreiben, um das Verständnis zu erleichtern.

requires-python

  • Typ: String
  • Erforderlich?: Nein
  • Inspiration: PDM, Poetry, uv
  • Gibt die Requires-Python für die minimale Python-Version an, die mit jeder vom Sperrdatei unterstützten Umgebung kompatibel ist (d. h. die minimale brauchbare Python-Version für die Sperrdatei).

extras

  • Typ: Array von Strings
  • Erforderlich?: Nein; Standardwert ist []
  • Inspiration: Provides-Extra (mehrfache Verwendung)
  • Die Liste der Extras, die von dieser Sperrdatei unterstützt werden.
  • Lockers KÖNNEN wählen, keine Sperrdateien zu unterstützen, die Extras und Abhängigkeitsgruppen unterstützen (d. h. Werkzeuge können nur eine Einmal-Sperrdatei exportieren).
  • Werkzeuge, die Extras unterstützen, MÜSSEN auch Abhängigkeitsgruppen unterstützen.
  • Werkzeuge SOLLTEN diesen Schlüssel explizit auf ein leeres Array setzen, um zu signalisieren, dass die zur Generierung der Sperrdatei verwendeten Eingaben keine Extras hatten (z. B. hatte eine pyproject.toml-Datei keine [project.optional-dependencies]-Tabelle), was signalisiert, dass die Sperrdatei effektiv mehrfach verwendet werden kann, auch wenn sie nur als Einmal-Sperrdatei erscheint.

dependency-groups

  • Typ: Array von Strings
  • Erforderlich?: Nein; Standardwert ist []
  • Inspiration: Beliebige Werkzeugkonfiguration: die [tool]-Tabelle
  • Die Liste der Abhängigkeitsgruppen, die von dieser Sperrdatei öffentlich unterstützt werden (d. h. Abhängigkeitsgruppen, die Benutzer voraussichtlich über eine Benutzeroberfläche eines Werkzeugs angeben können).
  • Lockers KÖNNEN wählen, keine Sperrdateien zu unterstützen, die Extras und Abhängigkeitsgruppen unterstützen (d. h. Werkzeuge können nur eine Einmal-Sperrdatei exportieren).
  • Werkzeuge, die Abhängigkeitsgruppen unterstützen, MÜSSEN auch Extras unterstützen.
  • Werkzeuge SOLLTEN diesen Schlüssel explizit auf ein leeres Array setzen, um zu signalisieren, dass die zur Generierung der Sperrdatei verwendeten Eingaben keine Abhängigkeitsgruppen hatten (z. B. hatte eine pyproject.toml-Datei keine [dependency-groups]-Tabelle), was signalisiert, dass die Sperrdatei effektiv mehrfach verwendet werden kann, auch wenn sie nur als Einmal-Sperrdatei erscheint.

default-groups

  • Typ: Array von Strings
  • Erforderlich?: Nein; Standardwert ist []
  • Inspiration: Poetry, PDM
  • Der Name von synthetischen Abhängigkeitsgruppen, die darstellen, was standardmäßig installiert werden soll (z. B. was project.dependencies implizit darstellt).
  • Sollte in Situationen verwendet werden, in denen packages.marker eine solche Gruppe erfordert.
  • Die von diesem Schlüssel aufgelisteten Gruppen SOLLTEN NICHT in dependency-groups aufgeführt werden, da die Gruppen nicht direkt namentlich für Benutzer bestimmt sind, sondern über die Benutzeroberfläche eines Installers.

created-by

  • Typ: String
  • Erforderlich?: Ja
  • Inspiration: Werkzeuge mit ihrem Namen im Sperrdateinamen
  • Zeichnet den Namen des Werkzeugs auf, das zum Erstellen der Sperrdatei verwendet wurde.
  • Werkzeuge KÖNNEN die [tool]-Tabelle verwenden, um genügend Details aufzuzeichnen, dass abgeleitet werden kann, welche Eingaben zur Erstellung der Sperrdatei verwendet wurden.
  • Werkzeuge SOLLTEN den normalisierten Namen des Werkzeugs aufzeichnen, wenn es als Python-Paket verfügbar ist, um die Suche nach dem Werkzeug zu erleichtern.

[[packages]]

  • Typ: Array von Tabellen
  • Erforderlich?: Ja
  • Inspiration: PDM, Poetry, uv
  • Ein Array, das alle Pakete enthält, die installiert werden *können*.
  • Pakete KÖNNEN mehrmals mit unterschiedlichen Daten aufgeführt werden, aber alle zu installierenden Pakete MÜSSEN zur Installationszeit auf einen einzigen Eintrag reduziert werden.
packages.name
  • Typ: String
  • Erforderlich?: Ja
  • Inspiration: Name
  • Der Name des Pakets, normalisiert.
packages.version
  • Typ: String
  • Erforderlich?: Nein
  • Inspiration: Version
  • Die Version des Pakets.
  • Die Version SOLLTE angegeben werden, wenn die Version als stabil bekannt ist (d. h. wenn eine sdist oder Wheels angegeben sind).
  • Die Version DARF NICHT enthalten sein, wenn nicht garantiert werden kann, dass sie mit dem verwendeten Code übereinstimmt (d. h. wenn ein Quellbaum verwendet wird).
packages.marker
  • Typ: String
  • Erforderlich?: Nein
  • Inspiration: PDM
  • Der Umgebungsmarker, der angibt, wann das Paket installiert werden soll.
packages.requires-python
[[packages.dependencies]]
  • Typ: Array von Tabellen
  • Erforderlich?: Nein
  • Inspiration: PDM, Poetry, uv
  • Zeichnet die anderen Einträge in [[packages]] auf, die direkte Abhängigkeiten dieses Pakets sind.
  • Jeder Eintrag ist eine Tabelle, die die minimalen Informationen enthält, die erforderlich sind, um anzugeben, welchem anderen Paketeintrag er entspricht, wo ein Schlüssel-für-Schlüssel-Vergleich das entsprechende Paket ohne Mehrdeutigkeit findet (z. B. wenn es zwei Einträge für das Paket spam gibt, dann können Sie die Versionsnummer einbeziehen, wie {name = "spam", version = "1.0.0"}, oder nach Quelle, wie {name = "spam", vcs = { url = "..."}).
  • Werkzeuge DÜRFEN diese Informationen bei der Installation NICHT verwenden; sie dient rein informativen Zwecken zur Prüfung.
[packages.vcs]
  • Typ: Tabelle
  • Erforderlich?: Nein; gegenseitig ausschließend mit packages.directory, packages.archive, packages.sdist und packages.wheels
  • Inspiration: Direct URL Data Structure
  • Aufzeichnung der Versionskontrollsystemdetails für den Quellbaum, den er enthält.
  • Werkzeuge KÖNNEN wählen, keine Versionskontrollsysteme zu unterstützen, sowohl aus Sperr- als auch/oder Installationsperspektive.
  • Werkzeuge KÖNNEN wählen, nur eine Teilmenge der verfügbaren VCS-Typen zu unterstützen.
  • Werkzeuge SOLLTEN eine Möglichkeit bieten, dass Benutzer die Verwendung von Versionskontrollsystemen ein-/ausschalten können.
  • Die Installation aus einem Versionskontrollsystem gilt als Ursprung einer Direct-URL-Referenz.
packages.vcs.type
  • Typ: String; unterstützte Werte sind in Registrierte VCS angegeben
  • Erforderlich?: Ja
  • Inspiration: VCS-URLs
  • Der Typ des verwendeten Versionskontrollsystems.
packages.vcs.url
  • Typ: String
  • Erforderlich?: wenn path nicht angegeben ist
  • Inspiration: VCS-URLs
  • Die URL zum Quellbaum.
packages.vcs.path
  • Typ: String
  • Erforderlich?: wenn url nicht angegeben ist
  • Inspiration: VCS-URLs
  • Der Pfad zum lokalen Verzeichnis des Quellbaums.
  • Wenn ein relativer Pfad verwendet wird, MUSS dieser relativ zum Speicherort dieser Datei sein.
  • Wenn der Pfad relativ ist, KANN er explizit POSIX-Pfadtrenner für Portabilität verwenden.
packages.vcs.requested-revision
  • Typ: String
  • Erforderlich?: Nein
  • Inspiration: VCS-URLs
  • Der Branch/Tag/Ref/Commit/Revision/etc., den der Benutzer angefordert hat.
  • Dies dient rein informativen Zwecken und erleichtert das Schreiben der Direct URL Data Structure; er darf NICHT zum Auschecken des Repositorys verwendet werden.
packages.vcs.commit-id
  • Typ: String
  • Erforderlich?: Ja
  • Inspiration: VCS-URLs
  • Die exakte Commit-/Revisionsnummer, die installiert werden soll.
  • Wenn das VCS Commit-Hash-basierte Revisionsbezeichner unterstützt, MUSS ein solcher Commit-Hash als Commit-ID verwendet werden, um eine unveränderliche Version des Quellcodes zu referenzieren.
packages.vcs.subdirectory
  • Typ: String
  • Erforderlich?: Nein
  • Inspiration: Projekte in Unterverzeichnissen
  • Das Unterverzeichnis innerhalb des Quellbaums, in dem sich der Projektstamm befindet (z. B. der Speicherort der pyproject.toml-Datei).
  • Der Pfad MUSS relativ zum Stamm der Quellbaumstruktur sein.
[packages.directory]
  • Typ: Tabelle
  • Erforderlich?: Nein; gegenseitig ausschließend mit packages.vcs, packages.archive, packages.sdist und packages.wheels
  • Inspiration: Lokale Verzeichnisse
  • Aufzeichnung der lokalen Verzeichnisdetails für den Quellbaum, den er enthält.
  • Werkzeuge KÖNNEN wählen, keine lokalen Verzeichnisse zu unterstützen, sowohl aus Sperr- als auch/oder Installationsperspektive.
  • Werkzeuge SOLLTEN eine Möglichkeit bieten, dass Benutzer die Verwendung von lokalen Verzeichnissen ein-/ausschalten können.
  • Die Installation aus einem lokalen Verzeichnis gilt als Ursprung einer Direct-URL-Referenz.
packages.directory.path
  • Typ: String
  • Erforderlich?: Ja
  • Inspiration: Lokale Verzeichnisse
  • Das lokale Verzeichnis, in dem sich der Quellbaum befindet.
  • Wenn der Pfad relativ ist, MUSS er relativ zum Speicherort der Sperrdatei sein.
  • Wenn der Pfad relativ ist, KANN er POSIX-Stil-Pfadtrenner für Portabilität verwenden.
packages.directory.editable
  • Typ: Boolean
  • Erforderlich?: Nein; Standardwert ist false
  • Inspiration: Lokale Verzeichnisse
  • Ein Flag, das darstellt, ob der Quellbaum zum Zeitpunkt der Sperrung ein editierbarer Install war.
  • Installer KÖNNEN wählen, dieses Flag zu ignorieren, wenn Benutzeraktionen oder der Kontext eine editierbare Installation unnötig oder unerwünscht machen (z. B. ein Container-Image, das nicht zu Entwicklungszwecken gemountet, sondern stattdessen in der Produktion bereitgestellt wird, wo es als schreibgeschützt behandelt würde).
packages.directory.subdirectory

Siehe packages.vcs.subdirectory.

[packages.archive]
  • Typ: Tabelle
  • Erforderlich?: Nein
  • Inspiration: Archiv-URLs
  • Eine direkte Referenz auf eine Archivdatei zur Installation (dies kann Wheels und Sdists sowie andere Archivformate enthalten, die einen Quellbaum enthalten).
  • Werkzeuge KÖNNEN wählen, keine Archivdateien zu unterstützen, sowohl aus Sperr- als auch/oder Installationsperspektive.
  • Werkzeuge SOLLTEN eine Möglichkeit bieten, dass Benutzer die Verwendung von Archivdateien ein-/ausschalten können.
  • Die Installation aus einer Archivdatei gilt als Ursprung einer Direct-URL-Referenz.
packages.archive.url

Siehe packages.vcs.url.

packages.archive.path

Siehe packages.vcs.path.

packages.archive.size
  • Typ: Ganzzahl
  • Erforderlich?: Nein
  • Inspiration: uv, Simple Repository API
  • Die Größe der Archivdatei.
  • Werkzeuge SOLLTEN die Dateigröße angeben, wenn dies vernünftigerweise möglich ist (z. B. ist die Dateigröße über den Content-Length-Header einer HEAD-HTTP-Anfrage verfügbar).
packages.archive.upload-time
  • Typ: Datum und Uhrzeit
  • Erforderlich?: Nein
  • Inspiration: Simple Repository API
  • Der Zeitpunkt, zu dem die Datei hochgeladen wurde.
  • Das Datum und die Uhrzeit MÜSSEN in UTC aufgezeichnet werden.
[packages.archive.hashes]
  • Typ: Tabelle von Strings
  • Erforderlich?: Ja
  • Inspiration: PDM, Poetry, uv, Simple Repository API
  • Eine Tabelle, die bekannte Hash-Werte der Datei auflistet, wobei der Schlüssel der Hash-Algorithmus und der Wert der Hash-Wert ist.
  • Die Tabelle MUSS mindestens einen Eintrag enthalten.
  • Hash-Algorithmus-Schlüssel SOLLTEN kleingeschrieben werden.
  • Mindestens ein sicherer Algorithmus aus hashlib.algorithms_guaranteed SOLLTE immer enthalten sein (zum Zeitpunkt der Erstellung wird insbesondere sha256 empfohlen.
packages.archive.subdirectory

Siehe packages.vcs.subdirectory.

packages.index
  • Typ: String
  • Erforderlich?: Nein
  • Inspiration: uv
  • Die Basis-URL für den Paketindex aus der Simple Repository API, von der die sdist und/oder Wheels gefunden wurden (z. B. https://pypi.org/simple/).
  • Wenn möglich, SOLLTE dies angegeben werden, um die Generierung von Software Bill of Materials – auch bekannt als SBOMs – zu unterstützen und um bei der Suche nach einer Datei zu helfen, wenn eine URL ungültig wird.
  • Werkzeuge KÖNNEN die Installation aus einem Index unterstützen, wenn die für eine bestimmte Datei aufgezeichnete URL nicht mehr gültig ist (z. B. einen 404-HTTP-Fehlercode zurückgibt).
[packages.sdist]
  • Typ: Tabelle
  • Erforderlich?: Nein; gegenseitig ausschließend mit packages.vcs, packages.directory und packages.archive
  • Inspiration: uv
  • Details einer Source Distribution-Datei für das Paket.
  • Werkzeuge KÖNNEN wählen, keine sdist-Dateien zu unterstützen, sowohl aus Sperr- als auch/oder Installationsperspektive.
  • Werkzeuge SOLLTEN eine Möglichkeit bieten, dass Benutzer die Verwendung von sdist-Dateien ein-/ausschalten können.
packages.sdist.name
packages.sdist.upload-time

Siehe packages.archive.upload-time.

packages.sdist.url

Siehe packages.archive.url.

packages.sdist.path

Siehe packages.archive.path.

packages.sdist.size

Siehe packages.archive.size.

packages.sdist.hashes

Siehe packages.archive.hashes.

[[packages.wheels]]
  • Typ: Array von Tabellen
  • Erforderlich?: Nein; gegenseitig ausschließend mit packages.vcs, packages.directory und packages.archive
  • Inspiration: PDM, Poetry, uv
  • Zur Aufzeichnung der Wheel-Dateien gemäß der Binary Distribution Format für das Paket.
  • Werkzeuge MÜSSEN Wheel-Dateien unterstützen, sowohl aus Sperr- als auch aus Installationsperspektive.
packages.wheels.name
packages.wheels.upload-time

Siehe packages.archive.upload-time.

packages.wheels.url

Siehe packages.archive.url.

packages.wheels.path

Siehe packages.archive.path.

packages.wheels.size

Siehe packages.archive.size.

packages.wheels.hashes

Siehe packages.archive.hashes.

[[packages.attestation-identities]]
  • Typ: Array von Tabellen
  • Erforderlich?: Nein
  • Inspiration: Herkunftsobjekte
  • Eine Aufzeichnung der Bestätigungen für *jede* für dieses Paket aufgezeichnete Datei.
  • Wenn verfügbar, SOLLTEN Werkzeuge die gefundenen Bestätigungsidentitäten enthalten.
  • Verlegerspezifische Schlüssel werden unverändert in die Tabelle aufgenommen (d. h. auf der obersten Ebene), gemäß der Spezifikation unter Index Hosted Attestations.
packages.attestation-identities.kind
  • Typ: String
  • Erforderlich?: Ja
  • Inspiration: Herkunftsobjekte
  • Die eindeutige Identität des vertrauenswürdigen Verlegers.
[packages.tool]
  • Typ: Tabelle
  • Erforderlich?: Nein
  • Inspiration: Beliebige Werkzeugkonfiguration: die [tool]-Tabelle
  • Ähnliche Verwendung wie die [tool]-Tabelle aus der pyproject.toml-Spezifikation, jedoch auf der Ebene der Paketversion anstatt auf der Ebene der Sperrdatei (die auch über [tool] verfügbar ist).
  • Daten, die in der Tabelle aufgezeichnet werden, MÜSSEN verwerfbar sein (d. h. sie dürfen die Installation NICHT beeinflussen).

[tool]

Ergänzungen zur Syntax von Markerausdrücken

Dieses PEP schlägt vor, die Spezifikation für Umgebungsmarker um Extras und Abhängigkeitsgruppenbeziehungen für einen Eintrag in [[packages]] zu erweitern, sodass diese in packages.marker ausgedrückt werden können. Die in diesem PEP dargelegten Ergänzungen gelten NUR im Kontext von Lock-Dateien, wie sie in diesem PEP definiert sind, und nicht in anderen Kontexten, in denen Marker-Syntax verwendet wird (z. B. METADATA, pyproject.toml).

Zunächst werden zwei neue Marker eingeführt: extras und dependency_groups. Sie repräsentieren die Extras und Abhängigkeitsgruppen, die zur Installation angefordert wurden, bzw.

diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst
index 06897da2..c9ab247f 100644
--- a/source/specifications/dependency-specifiers.rst
+++ b/source/specifications/dependency-specifiers.rst
@@ -87,7 +87,7 @@ environments::
                      'platform_system' | 'platform_version' |
                      'platform_machine' | 'platform_python_implementation' |
                      'implementation_name' | 'implementation_version' |
-                     'extra' # ONLY when defined by a containing layer
+                     'extra' | 'extras' | 'dependency_groups' # ONLY when defined by a containing layer
                      )
    marker_var    = wsp* (env_var | python_str)
    marker_expr   = marker_var marker_op marker_var

Dies schließt NICHT die Verwendung desselben Syntax-Parsers in anderen Kontexten aus, nur dort, wo die neuen Marker kontextbedingt als gültig betrachtet werden.

Zweitens wird die Marker-Spezifikation geändert, um Mengen (Sets) für Werte zuzulassen (zusätzlich zur aktuellen Unterstützung für Zeichenketten und Versionen). NUR die in diesem PEP eingeführten neuen Marker erlauben Mengen als Werte (die standardmäßig eine leere Menge sind). Dies aktualisiert die Spezifikation ausdrücklich NICHT, um Mengenliterale zuzulassen.

Drittens wird die Spezifikation der Marker-Ausdruckssyntax aktualisiert, um Operationen mit Mengen zuzulassen.

diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst
index 06897da2..ac29d796 100644
--- a/source/specifications/dependency-specifiers.rst
+++ b/source/specifications/dependency-specifiers.rst
@@ -196,15 +196,16 @@ safely evaluate it without running arbitrary code that could become a security
vulnerability. Markers were first standardised in :pep:`345`. This document
fixes some issues that were observed in the design described in :pep:`426`.

-Comparisons in marker expressions are typed by the comparison operator.  The
-<marker_op> operators that are not in <version_cmp> perform the same as they
-do for strings in Python. The <version_cmp> operators use the version comparison
-rules of the :ref:`Version specifier specification <version-specifiers>`
-when those are defined (that is when both sides have a valid
-version specifier). If there is no defined behaviour of this specification
-and the operator exists in Python, then the operator falls back to
-the Python behaviour. Otherwise an error should be raised. e.g. the following
-will result in  errors::
+Comparisons in marker expressions are typed by the comparison operator and the
+type of the marker value. The <marker_op> operators that are not in
+<version_cmp> perform the same as they do for strings or sets in Python based on
+whether the marker value is a string or set itself. The <version_cmp> operators
+use the version comparison rules of the
+:ref:`Version specifier specification <version-specifiers>` when those are
+defined (that is when both sides have a valid version specifier). If there is no
+defined behaviour of this specification and the operator exists in Python, then
+the operator falls back to the Python behaviour for the types involved.
+Otherwise an error should be raised. e.g. the following will result in errors::

    "dog" ~= "fred"
    python_version ~= "surprise"

Viertens wird die Verwendung von extras und dependency_groups außerhalb einer Lock-Datei als Fehler betrachtet (ähnlich wie extra außerhalb der Core-Metadaten-Spezifikationen).

diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst
index 06897da2..2914ef66 100644
--- a/source/specifications/dependency-specifiers.rst
+++ b/source/specifications/dependency-specifiers.rst
@@ -235,6 +235,11 @@ no current specification for this. Regardless, outside of a context where this
special handling is taking place, the "extra" variable should result in an
error like all other unknown variables.

+The "extras" and "dependency_groups" variables are also special. They are used
+to specify any requested extras or dependency groups when installing from a lock
+file. Outside of the context of lock files, these two variables should result in
+an error like all other unknown variables.
+
.. list-table::
    :header-rows: 1

Diese Änderungen, zusammen mit packages.extras/ packages.dependency-groups und der Unterstützung für boolesche Logik in Marker-Ausdrücken, ermöglichen die Ausdruck von beliebigen, erschöpfenden Anforderungen dafür, wann ein Paket installiert werden soll, basierend auf den angeforderten (und nicht angeforderten) Extras und Abhängigkeitsgruppen. Wenn beispielsweise eine Lock-Datei extras = ["extra-1", "extra-2"] hat, können Sie angeben, ob ein Paket installiert werden soll, wenn

  • Irgendeines der Extras angegeben ist ('extra-1' in extras or 'extra-2' in extras)
  • Nur „extra-1“ angegeben ist ('extra-1' in extras and 'extra-2' not in extras)
  • Keines der Extras angegeben ist ('extra-1' not in extras and 'extra-2' not in extras)

(Diese Liste ist nicht erschöpfend für alle möglichen booleschen Logikausdrücke.)

Die gleiche Flexibilität gilt für Abhängigkeitsgruppen.

Wie Benutzer einem Werkzeug mitteilen, welche Extras und/oder Abhängigkeitsgruppen sie installiert haben möchten, bleibt dem Werkzeug überlassen. Installer MÜSSEN die durch dieses PEP vorgeschlagenen Erweiterungen der Marker-Ausdruckssyntax unterstützen. Locker KÖNNEN Lock-Dateien schreiben, die die vorgeschlagenen Erweiterungen der Marker-Ausdruckssyntax nutzen (d. h. Locker können wählen, nur einseitige Lock-Dateien zu unterstützen).

Beispiel

lock-version = '1.0'
environments = ["sys_platform == 'win32'", "sys_platform == 'linux'"]
requires-python = '==3.12'
created-by = 'mousebender'

[[packages]]
name = 'attrs'
version = '25.1.0'
requires-python = '>=3.8'
wheels = [
  {name = 'attrs-25.1.0-py3-none-any.whl', upload-time = 2025-01-25T11:30:10.164985+00:00, url = 'https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl', size = 63152, hashes = {sha256 = 'c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a'}},
]
[[packages.attestation-identities]]
environment = 'release-pypi'
kind = 'GitHub'
repository = 'python-attrs/attrs'
workflow = 'pypi-package.yml'

[[packages]]
name = 'cattrs'
version = '24.1.2'
requires-python = '>=3.8'
dependencies = [
    {name = 'attrs'},
]
wheels = [
  {name = 'cattrs-24.1.2-py3-none-any.whl', upload-time = 2024-09-22T14:58:34.812643+00:00, url = 'https://files.pythonhosted.org/packages/c8/d5/867e75361fc45f6de75fe277dd085627a9db5ebb511a87f27dc1396b5351/cattrs-24.1.2-py3-none-any.whl', size = 66446, hashes = {sha256 = '67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0'}},
]

[[packages]]
name = 'numpy'
version = '2.2.3'
requires-python = '>=3.10'
wheels = [
  {name = 'numpy-2.2.3-cp312-cp312-win_amd64.whl', upload-time = 2025-02-13T16:51:21.821880+00:00, url = 'https://files.pythonhosted.org/packages/42/6e/55580a538116d16ae7c9aa17d4edd56e83f42126cb1dfe7a684da7925d2c/numpy-2.2.3-cp312-cp312-win_amd64.whl', size = 12626357, hashes = {sha256 = '83807d445817326b4bcdaaaf8e8e9f1753da04341eceec705c001ff342002e5d'}},
  {name = 'numpy-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl', upload-time = 2025-02-13T16:50:00.079662+00:00, url = 'https://files.pythonhosted.org/packages/39/04/78d2e7402fb479d893953fb78fa7045f7deb635ec095b6b4f0260223091a/numpy-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl', size = 16116679, hashes = {sha256 = '3b787adbf04b0db1967798dba8da1af07e387908ed1553a0d6e74c084d1ceafe'}},
]

[tool.mousebender]
command = ['.', 'lock', '--platform', 'cpython3.12-windows-x64', '--platform', 'cpython3.12-manylinux2014-x64', 'cattrs', 'numpy']
run-on = 2025-03-06T12:28:57.760769

Installation

Das Folgende beschreibt die Schritte zur Installation aus einer Lock-Datei (während die Anforderungen vorschreibend sind, sind die allgemeinen Schritte und die Reihenfolge ein Vorschlag)

  1. Sammeln Sie die zu installierenden Extras und Abhängigkeitsgruppen und setzen Sie extras und dependency_groups für die Marker-Auswertung.
    1. extras SOLLTE standardmäßig auf die leere Menge gesetzt werden.
    2. dependency_groups SOLLTE standardmäßig die Menge sein, die aus default-groups erstellt wird.
  2. Prüfen Sie, ob die von lock-version angegebene Metadaten-Version unterstützt wird; es muss gegebenenfalls ein Fehler oder eine Warnung ausgegeben werden.
  3. Wenn requires-python angegeben ist, prüfen Sie, ob die Installationsumgebung die Anforderung erfüllt; es muss ein Fehler ausgegeben werden, wenn sie nicht erfüllt ist.
  4. Wenn environments angegeben ist, prüfen Sie, ob mindestens einer der Umgebungsmarker-Ausdrücke erfüllt ist; es muss ein Fehler ausgegeben werden, wenn kein Ausdruck erfüllt ist.
  5. Für jedes Paket, das in [[packages]] aufgeführt ist
    1. Wenn marker angegeben ist, prüfen Sie, ob er erfüllt ist; wenn nicht, springen Sie zum nächsten Paket.
    2. Wenn requires-python angegeben ist, prüfen Sie, ob er erfüllt ist; es muss ein Fehler ausgegeben werden, wenn er nicht erfüllt ist.
    3. Prüfen Sie, ob keine andere widersprüchliche Instanz des Pakets zur Installation vorgesehen ist; andernfalls muss ein Fehler wegen der Mehrdeutigkeit ausgegeben werden.
    4. Prüfen Sie, ob die Quelle des Pakets ordnungsgemäß angegeben ist (d. h. es gibt keine widersprüchlichen Quellen im Paketeintrag); andernfalls muss ein Fehler wegen etwaiger Probleme ausgegeben werden.
    5. Fügen Sie das Paket der Menge der zu installierenden Pakete hinzu.
  6. Für jedes zu installierende Paket
    • Wenn vcs gesetzt ist
      1. Klonen Sie das Repository bis zum in commit-id angegebenen Commit-ID.
      2. Bauen Sie das Paket unter Berücksichtigung von subdirectory.
      3. Installieren Sie.
    • Andernfalls, wenn directory gesetzt ist
      1. Bauen Sie das Paket unter Berücksichtigung von subdirectory.
      2. Installieren Sie.
    • Andernfalls, wenn archive gesetzt ist
      1. Holen Sie sich die Datei.
      2. Validieren Sie die Dateigröße und den Hash.
      3. Bauen Sie das Paket unter Berücksichtigung von subdirectory.
      4. Installieren Sie.
    • Andernfalls, wenn Einträge für wheels vorhanden sind
      1. Suchen Sie nach der entsprechenden Wheel-Datei basierend auf name; wenn keine gefunden wird, fahren Sie mit sdist fort oder es muss ein Fehler wegen fehlender Quelle für das Projekt ausgegeben werden.
      2. Holen Sie sich die Datei
        • Wenn path gesetzt ist, verwenden Sie ihn.
        • Wenn url gesetzt ist, versuchen Sie, ihn zu verwenden; optional KÖNNEN Werkzeuge packages.index oder einen werkzeugspezifischen Mechanismus verwenden, um die ausgewählte Wheel-Datei herunterzuladen (Werkzeuge DÜRFEN NICHT versuchen, die herunterzuladende Wheel-Datei basierend auf Verfügbarkeit zu ändern; welche Datei installiert werden soll, sollte offline zur Reproduzierbarkeit ermittelt werden).
      3. Validieren Sie die Dateigröße und den Hash.
      4. Installieren Sie.
    • Andernfalls, wenn keine wheel-Datei gefunden wird oder nur sdist gesetzt ist
      1. Holen Sie sich die Datei.
        • Wenn path gesetzt ist, verwenden Sie ihn.
        • Wenn url gesetzt ist, versuchen Sie, ihn zu verwenden; Werkzeuge KÖNNEN packages.index oder einen werkzeugspezifischen Mechanismus verwenden, um die Datei herunterzuladen.
      2. Validieren Sie die Dateigröße und den Hash.
      3. Bauen Sie das Paket.
      4. Installieren Sie.

Semantische Unterschiede zu requirements.txt-Dateien

Abgesehen von der Formatierung gibt es einige Unterschiede zwischen Lock-Dateien, wie sie von diesem PEP vorgeschlagen werden, und denen, die über eine requirements-Datei möglich sind.

Einige der Unterschiede betreffen die Sicherheit. Das Erfordernis von Hashes, die Aufzeichnung von Dateigrößen und wo eine Datei gefunden wurde – sowohl der Index als auch der Speicherort der Datei selbst – helfen bei der Überprüfung und Validierung der gesperrten Dateien. Vergleichen Sie dies mit Anforderungen, die optional Hashes enthalten können, aber dies ist eine Opt-in-Funktion und kann umgangen werden. Die optionale Aufnahme der Upload-Zeit einer Datei und wo die Dateien zu finden sind, ist ebenfalls unterschiedlich.

Die explizite Angabe der unterstützten Python-Versionen und Umgebungen für die Datei insgesamt ist einzigartig für dieses PEP. Dies soll das Problem lindern, nicht zu wissen, wann eine Anforderungen-Datei auf eine bestimmte Plattform abzielt.

Die [tool]-Tabellen haben keine direkte Entsprechung in Anforderungen-Dateien. Sie unterstützen Kommentare, sind aber dank der TOML-Struktur nicht inhärent strukturiert wie die [tool]-Tabelle.

Während Kommentare in einer Anforderungen-Datei Details enthalten könnten, die für die Überprüfung und das Verständnis des Inhalts der Lock-Datei hilfreich sind, erleichtert die Bereitstellung der strukturierten Unterstützung für die Aufzeichnung solcher Dinge die Überprüfung. Die Aufzeichnung der erforderlichen Python-Version für ein Paket hilft dabei, ebenso wie das frühzeitige Auslösen von Fehlern, wenn eine Installation fehlschlägt. Die Aufzeichnung des Wheel-Dateinamens getrennt von der URL oder dem Pfad dient ebenfalls dazu, das Lesen der Liste der Wheel-Dateien zu erleichtern, da er Informationen enthält, die für das Verständnis und die Überprüfung einer Datei nützlich sein können. Die Aufzeichnung des sdist-Dateinamens dient demselben Zweck.

Dieses PEP unterstützt Multi-Use Lock-Dateien, während Anforderungen-Dateien Single-Use sind.

Dieses PEP ersetzt Anforderungen-Dateien NICHT vollständig, weil

Abwärtskompatibilität

Da es kein bestehendes Lock-Datei-Format gibt, gibt es keine expliziten Kompatibilitätsprobleme im Hinblick auf Python-Packaging-Standards.

Was die Packaging-Tools selbst betrifft, so wird es eine pro-Tool-Entscheidung sein, ob sie dieses PEP unterstützen und in welcher Weise (d. h. als Exportziel oder als primäre Methode zur Aufzeichnung ihrer Lock-Datei).

Sicherheitsimplikationen

Die Hoffnung ist, dass durch die Standardisierung auf ein Lock-Datei-Format, das von einem Sicherheits-First-Ansatz ausgeht, die gesamte Paketinstallation sicherer wird. Dieses PEP löst jedoch nicht alle potenziellen Sicherheitsprobleme.

Ein potenzielles Problem ist die Manipulation einer Lock-Datei. Wenn eine Lock-Datei nicht im Quellcodeverwaltungssystem aufbewahrt und ordnungsgemäß überprüft wird, könnte ein böswilliger Akteur die Datei auf hinterhältige Weise ändern (z. B. auf eine Malware-Version eines Pakets verweisen). Manipulationen könnten auch während der Übertragung erfolgen, z. B. an einen Cloud-Anbieter, der eine Installation im Auftrag des Benutzers durchführt. Beides könnte durch die Signierung der Lock-Datei entweder innerhalb der Datei in einem [tool]-Eintrag oder über einen seitlichen Kanal außerhalb der Lock-Datei selbst gemildert werden.

Dieses PEP verhindert nicht, dass ein Benutzer falsche Pakete installiert. Obwohl viele Details zur Überprüfung der Aufnahme eines Pakets enthalten sind, gibt es keinen Mechanismus, um z. B. Namensverwechslungsangriffe durch Tippfehler zu verhindern. Werkzeuge können möglicherweise eine Benutzererfahrung bieten, um dabei zu helfen (z. B. durch Angabe von Download-Anzahlen für ein Paket).

Wie man das lehrt

Benutzer sollten darüber informiert werden, dass, wenn sie die Installation eines Pakets anfordern, das Paket eigene Abhängigkeiten haben kann, diese Abhängigkeiten wiederum Abhängigkeiten haben können usw. Ohne aufzuzeichnen, was als Teil der Installation des angeforderten Pakets installiert wird, könnten sich Dinge unter ihren Füßen ändern (z. B. Paketversionen). Änderungen an den zugrunde liegenden Abhängigkeiten können zu versehentlichen Brüchen ihres Codes führen. Lock-Dateien helfen dabei, indem sie eine Möglichkeit bieten, aufzuzeichnen, was installiert wurde, damit Sie in Zukunft genau dasselbe installieren können.

Das Aufzeichnen, was installiert werden soll, hilft auch bei der Zusammenarbeit mit anderen. Durch die Einigung auf den Inhalt einer Lock-Datei erhalten alle die gleichen installierten Pakete. Dies hilft sicherzustellen, dass niemand auf z. B. eine API angewiesen ist, die nur in einer bestimmten Version verfügbar ist, die nicht alle Projektmitarbeiter installiert haben.

Lock-Dateien helfen auch bei der Sicherheit, indem sie sicherstellen, dass Sie immer die gleichen Dateien installieren und nicht eine bösartige, die jemand eingeschleust hat. Sie ermöglichen auch eine bewusstere Aktualisierung ihrer Abhängigkeiten und stellen so sicher, dass die Änderung beabsichtigt ist und nicht von einem böswilligen Akteur eingeschleust wurde.

Lock-Dateien können nur bestimmte Umgebungen unterstützen. Was für die zu installierende Umgebung installiert werden muss, kann sich von einer anderen, anderen Umgebung unterscheiden. Einige Lock-Dateien versuchen jedoch, universell zu sein und für jede mögliche Umgebung zu funktionieren (vorausgesetzt, sdists und Quellcode-Tree-Installationen sind erfolgreich).

Lock-Dateien können Single-Use oder Multi-Use sein. Single-Use Lock-Dateien sind für einzelne Anwendungsfälle. Multi-Use Lock-Dateien können für mehrere Anwendungsfälle basierend auf Extras und Abhängigkeitsgruppen verwendet werden. Es liegt am Werkzeug (an den Werkzeugen), das Sie verwenden, zu entscheiden, ob Multi-Use Lock-Dateien möglich sind. Alle Werkzeuge, die sich mit Lock-Dateien befassen, unterstützen mindestens Single-Use Lock-Dateien. Keine der beiden Lock-Datei-Arten ist besser oder schlechter als die andere, es ändert nur, wie viel in einer einzigen Datei geschrieben werden kann.

Lock-Dateien, die diesem PEP folgen, können von jedem Installer installiert werden, der die Spezifikation implementiert. Dies ermöglicht es Benutzern einer Lock-Datei, eine Installation durchzuführen, ohne an den Locker gebunden zu sein, der von der Person verwendet wurde, die die Lock-Datei erstellt hat. Aber es ist nicht so, dass die Verwendung eines anderen Lockers zum gleichen Ergebnis führt. Dies kann verschiedene Gründe haben, darunter die Verwendung unterschiedlicher Algorithmen zur Bestimmung dessen, was gesperrt werden soll.

Referenzimplementierung

Ein Proof-of-Concept, der Single-Use Lock-Dateien implementiert, ist unter https://github.com/brettcannon/mousebender/tree/pep zu finden. Andere Werkzeuge wie PDM und Poetry implementieren semantisch ähnliche Ansätze verschiedener Teile dieses PEP.

Abgelehnte Ideen

Aufzeichnung des Abhängigkeitsgraphen für Installationszwecke

Eine frühere Version dieses PEP zeichnete den Abhängigkeitsgraphen von Paketen auf, anstatt einer Menge von zu installierenden Paketen. Die Idee war, dass durch die Aufzeichnung des Abhängigkeitsgraphen nicht nur mehr Informationen erhalten wurden, sondern auch mehr Flexibilität durch die inhärente Unterstützung weiterer Features (z. B. plattformspezifische Abhängigkeiten ohne explizites Propagieren von Markern) geboten wurde.

Letztendlich wurde jedoch entschieden, dass dies zu einem Komplexitätsgrad führt, der den Aufwand nicht wert war (z. B. beeinträchtigte es die Auditierbarkeit von Details, die für die Erreichung der Ziele dieses PEP nicht notwendig waren).

Festlegung einer neuen Kernmetadatenversion, die konsistente Metadaten über Dateien hinweg erfordert

Zu einem Zeitpunkt wurde die Idee in den Raum gestellt, eine neue Kern-Metadaten-Version einzuführen, um das Problem der zwischen Dateien variierenden Metadaten zu lösen und somit jede veröffentlichte Datei eines Pakets und seiner Version zu prüfen, um genaue Sperrergebnisse zu erzielen. Diese neue Version würde erfordern, dass alle Metadaten für alle Wheel-Dateien für eine einzige Paketversion gleich sind. Letztendlich wurde jedoch entschieden, dass dies unnötig sei, da dieses PEP den Druck auf die Ersteller ausüben wird, Dateien aus Leistungsgründen konsistent zu machen, oder die Indizes werden alle Metadaten separat von den Wheel-Dateien bereitstellen. Außerdem gibt es keinen einfachen Durchsetzungsmechanismus, sodass die Erwartung der Community genauso gut funktionieren würde wie eine neue Metadatenversion.

Der Installer soll die Abhängigkeitsauflösung durchführen

Um ein Format zu unterstützen, das dem entspricht, wie Poetry dieses PEP entworfen hat, wurde vorgeschlagen, dass Locker im Wesentlichen die Pakete und ihre Versionen aufzeichnen, die für eine Installation in jedem möglichen Szenario erforderlich sein könnten, und dann der Installer auflöst, was installiert werden soll. Dies erschwert jedoch die Überprüfung einer Lock-Datei, da deutlich mehr mentale Anstrengung erforderlich ist, um zu wissen, welche Pakete in einem bestimmten Szenario installiert werden könnten. Außerdem schlug einer der Poetry-Entwickler vor, dass die im Paket-Locking-Ansatz dieses PEP dargestellten Marker ausreichen könnten, um die Bedürfnisse von Poetry zu erfüllen. Wenn der Installer keine Auflösung durchführt, vereinfacht dies seine Implementierung und zentralisiert die Komplexität in den Lockern.

Anforderung einer Mindestunterstützung für Hash-Algorithmen

Es wurde vorgeschlagen, einen Basis-Hash-Algorithmus für die Dateien vorzuschreiben. Dies wurde abgelehnt, da keine andere Python-Packaging-Spezifikation eine spezifische Hash-Algorithmus-Unterstützung vorschreibt. Außerdem könnte der vorgeschlagene minimale Hash-Algorithmus schließlich veraltet/unsicher werden und weitere Updates erfordern. Um die jederzeit beste Verwendung des besten Algorithmus zu fördern, wird keine Basis angegeben, um zu vermeiden, dass Werkzeuge einfach die Basis verwenden, ohne die Sicherheitsimplikationen dieses Hash-Algorithmus zu berücksichtigen.

Dateinamen

Verwendung von *.pylock.toml als Dateiname

Es wurde vorgeschlagen, den pylock-Konstante Teil des Dateinamens nach der Kennung für den Zweck der Lock-Datei zu setzen. Dies wurde abgelehnt, damit Lock-Dateien beim Betrachten von Verzeichnisinhalten zusammen sortiert werden und nicht rein nach ihrem Zweck, was sie in einem Verzeichnis verteilen könnte.

Verwendung von *.pylock als Dateiname

Es wurde vorgeschlagen, nicht .toml als Dateierweiterung zu verwenden und stattdessen .pylock selbst zu verwenden. Dies wurde abgelehnt, damit Code-Editoren die Syntaxhervorhebung für eine Lock-Datei ohne spezielle Kenntnisse der Dateierweiterung bereitstellen können.

Keine Namenskonvention für die Datei

Es wurde erwogen, keine Anforderungen oder Anleitungen für den Namen einer Lock-Datei zu haben, dies wurde jedoch letztendlich abgelehnt. Durch eine standardisierte Namenskonvention ist es einfach, eine Lock-Datei sowohl für einen Menschen als auch für einen Code-Editor zu identifizieren. Dies erleichtert die Entdeckung, wenn z. B. ein Werkzeug alle verfügbaren Lock-Dateien identifizieren möchte.

Dateiformat

JSON statt TOML verwenden

Da das Vorhandensein eines maschinenbeschreibbaren Formats ein Ziel dieses PEP war, wurde JSON vorgeschlagen. Dies wurde jedoch als weniger lesbar als TOML angesehen, ohne den maschinenbeschreibbaren Aspekt ausreichend zu verbessern, um die Änderung zu rechtfertigen.

YAML statt TOML verwenden

Einige argumentierten, dass YAML die Anforderung maschinenbeschreibbar/menschenlesbar besser erfüllt als TOML. Da dies jedoch subjektiv ist und pyproject.toml bereits als menschenlesbare Datei existierte, die von Python-Packaging-Standards verwendet wurde, wurde es als wichtiger erachtet, weiterhin TOML zu verwenden.

Andere Schlüssel

Ein einziger Hash-Algorithmus für die gesamte Datei

Frühere Versionen dieses PEP schlugen vor, nur einen einzigen Hash-Algorithmus pro Datei anzugeben, anstatt eine beliebige Anzahl von Algorithmen pro Datei. Die Überlegung war, dass die Angabe eines einzelnen Algorithmus die Überprüfung der Datei erleichtert, wenn ein bestimmter Hash-Algorithmus zur Verwendung vorgeschrieben war.

Letztendlich gab es Einwände gegen diese Idee. Typischerweise drehten sie sich um die Kosten des Rehashing großer Wheel-Dateien (z. B. PyTorch). Es gab auch Bedenken, dass Hashing-Entscheidungen im Voraus vom Installer getroffen werden, mit denen dieser möglicherweise nicht einverstanden ist. Letztendlich wurde es als besser angesehen, Flexibilität zu bieten und den Leuten die Überprüfung der Lock-Datei nach Belieben zu überlassen.

Hashing des Inhalts der Sperrdatei selbst

Es wurde zu einem bestimmten Zeitpunkt vorgeschlagen, die Inhalte der Bytes der Datei zu hashen und den Hash-Wert in der Datei selbst zu speichern. Dies wurde entfernt, um das Zusammenführen von Änderungen an der Lock-Datei zu erleichtern, da jede Zusammenführung den Hash-Wert neu berechnen müsste, um einen Merge-Konflikt zu vermeiden.

Das Hashing des semantischen Inhalts der Datei wurde ebenfalls vorgeschlagen, aber es würde zu demselben Merge-Konfliktproblem führen.

Unabhängig davon, welche Inhalte gehasht wurden, könnte in beiden Fällen der Hash-Wert außerhalb der Datei gespeichert werden, wenn ein solcher Hash gewünscht wird.

Aufzeichnung des Erstellungsdatums der Sperrdatei

Um zu wissen, wie potenziell veraltet die Lock-Datei war, schlug ein früherer Vorschlag vor, das Erstellungsdatum der Lock-Datei aufzuzeichnen. Aus denselben Gründen wie beim Speichern des Hashs des Datei-Inhalts wurde diese Idee jedoch verworfen, um Merge-Konflikte zu vermeiden.

Aufzeichnung der verwendeten Paketindizes bei der Suche

Die Aufzeichnung, welche Paketindizes zur Erstellung der Lock-Datei verwendet wurden, wurde in Betracht gezogen. Letztendlich wurde dies jedoch abgelehnt, da es als unnötige Buchhaltung angesehen wurde.

Sperrung von Build-Anforderungen für sdists

Eine frühere Version dieses PEP versuchte, die Build-Anforderungen für sdists unter einem packages.build-requires-Schlüssel zu sperren. Leider hat es genügend Leute verwirrt, wie es betrieben werden sollte, und es gab genügend Randfälle, um zu entscheiden, dass es sich nicht lohnt, dies in diesem PEP im Voraus zu versuchen. Stattdessen könnte ein zukünftiges PEP eine Lösung vorschlagen.

Ein dedizierter direct-Schlüssel

Frühere Versionen hatten einen dedizierten packages.direct-Schlüssel, um zu kennzeichnen, wann etwas aus einer direkten URL-Referenz stammt. Es gibt jedoch explizit nur drei Fälle, in denen eine direkte URL-Referenz auftreten kann (VCS, Verzeichnis und Archiv). Da alle drei Fälle in [[packages]] explizit sind, war die Einstellung des Schlüssels technisch überflüssig.

Der einzige Nachteil, diesen Schlüssel nicht zu haben, betrifft Wheels und sdists, die nun unter packages.archive fallen. Mit dem separaten Schlüssel (oder wenn er als Teil von packages.sdist oder packages.wheels angegeben wird) wäre es möglich, in der Lock-Datei selbst zu identifizieren, dass eine Archivdatei ein sdist oder Wheel ist. Aktuell muss ein Installer dieses Detail selbst ableiten.

Vereinfachung

Löschen der Aufzeichnung der Paketversion

Die Paketversion ist optional, da sie nur zuverlässig aufgezeichnet werden kann, wenn eine sdist- oder Wheel-Datei verwendet wird. Da beide Quellen die Version in den Dateinamen aufzeichnen, ist sie technisch redundant.

In Diskussionen wurde jedoch entschieden, dass die Versionsnummer für die Überprüfung nützlich ist, um sie weiterhin separat anzugeben.

Löschen der Anforderung, den Speicherort einer sdist und/oder Wheels anzugeben

Mindestens eine Person hat kommentiert, dass ihre Arbeit instabile URLs für alle sdists und Wheels hat. Daher müssen sie bei der Installation nach allen Dateien suchen, unabhängig davon, wo die Datei zuvor gefunden wurde. Das Wegfallen der Anforderung, die URL oder den Pfad zu einer Datei anzugeben, hätte geholfen, das Problem der Aufzeichnung von als bekannt schlecht eingestuften Informationen zu lösen.

Die Entscheidung, Werkzeugen zu erlauben, nach einer Datei auf andere Weise als über die bereitgestellte URL zu suchen, beseitigte die Notwendigkeit, die URL optional zu machen.

Löschen der Anforderung von Dateigröße und Hashes

Mindestens eine Person hat gesagt, dass ihre Arbeit alle Wheels und sdists mit internen Dateien modifiziert. Das bedeutet, dass alle aufgezeichneten Hashes und Dateigrößen falsch sind. Indem die Dateigröße und die Hashes optional gemacht werden – sehr wahrscheinlich über einen Opt-out-Mechanismus –, könnten sie weiterhin Lock-Dateien produzieren, die die Anforderungen dieses PEP erfüllen.

Es wurde entschieden, dass dies die Sicherheit zu stark schwächt. Es verhindert auch die Installation von Dateien aus alternativen Speicherorten.

Löschen der Aufzeichnung des sdist-Dateinamens

Obwohl mit dem Wegfall der URL/Pfad-Anforderung, der Paketversion und der Hashes nicht kompatibel, ist die Aufzeichnung des sdist-Dateinamens technisch überhaupt nicht notwendig (derzeit ist die Aufzeichnung des Dateinamens optional). Der Dateiname kodiert nur den Projektnamen und die Version, sodass keine neuen Informationen über die Datei übermittelt werden (wenn die Paketversion angegeben ist). Und wenn der Speicherort aufgezeichnet wird, ist das Abrufen der Datei unabhängig vom Dateinamen erledigt.

Die Aufzeichnung des Dateinamens kann jedoch hilfreich sein, wenn nach einer geeigneten Datei gesucht wird, wenn der aufgezeichnete Dateispeicherort nicht mehr verfügbar ist (während sdist-Dateinamen dank PEP 625 inzwischen standardisiert sind, ist dies nur seit 2020 der Fall, und daher gibt es viele ältere sdists mit Namen, die möglicherweise nicht erratbar sind).

Es wurde die Entscheidung getroffen, den sdist-Dateinamen aus Gründen der Einfachheit vorzuschreiben.

Machen von packages.wheels zu einer Tabelle

Man könnte sich vorstellen, die Details von Wheel-Dateien als Tabelle mit dem Dateinamen als Schlüssel zu schreiben. Zum Beispiel

[[packages]]
name = "attrs"
version = "23.2.0"
requires-python = ">=3.7"
index = "https://pypi.org/simple/"

[packages.wheels]
"attrs-23.2.0-py3-none-any.whl" = {upload-time = 2023-12-31T06:30:30.772444Z, url = "https://files.pythonhosted.org/packages/e0/44/827b2a91a5816512fcaf3cc4ebc465ccd5d598c45cefa6703fcf4a79018f/attrs-23.2.0-py3-none-any.whl", size = 60752, hashes = {sha256 = "99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}

[[packages]]
name = "numpy"
version = "2.0.1"
requires-python = ">=3.9"
index = "https://pypi.org/simple/"

[packages.wheels]
"numpy-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl" = {upload-time = 2024-07-21T13:37:15.810939Z, url = "https://files.pythonhosted.org/packages/64/1c/401489a7e92c30db413362756c313b9353fb47565015986c55582593e2ae/numpy-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", size = 20965374, hashes = {sha256 = "6bf4e6f4a2a2e26655717a1983ef6324f2664d7011f6ef7482e8c0b3d51e82ac"}
"numpy-2.0.1-cp312-cp312-macosx_11_0_arm64.whl" = {upload-time = 2024-07-21T13:37:36.460324Z, url = "https://files.pythonhosted.org/packages/08/61/460fb524bb2d1a8bd4bbcb33d9b0971f9837fdedcfda8478d4c8f5cfd7ee/numpy-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", size = 13102536, hashes = {sha256 = "7d6fddc5fe258d3328cd8e3d7d3e02234c5d70e01ebe377a6ab92adb14039cb4"}
"numpy-2.0.1-cp312-cp312-macosx_14_0_arm64.whl" = {upload-time = 2024-07-21T13:37:46.601144Z, url = "https://files.pythonhosted.org/packages/c2/da/3d8debb409bc97045b559f408d2b8cefa6a077a73df14dbf4d8780d976b1/numpy-2.0.1-cp312-cp312-macosx_14_0_arm64.whl", size = 5037809, hashes = {sha256 = "5daab361be6ddeb299a918a7c0864fa8618af66019138263247af405018b04e1"}
"numpy-2.0.1-cp312-cp312-macosx_14_0_x86_64.whl" = {upload-time = 2024-07-21T13:37:58.784393Z, url = "https://files.pythonhosted.org/packages/6d/59/85160bf5f4af6264a7c5149ab07be9c8db2b0eb064794f8a7bf6d/numpy-2.0.1-cp312-cp312-macosx_14_0_x86_64.whl", size = 6631813, hashes = {sha256 = "ea2326a4dca88e4a274ba3a4405eb6c6467d3ffbd8c7d38632502eaae3820587"}
"numpy-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" = {upload-time = 2024-07-21T13:38:19.714559Z, url = "https://files.pythonhosted.org/packages/5e/e3/944b77e2742fece7da8dfba6f7ef7dccdd163d1a613f7027f4d5b/numpy-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", size = 13623742, hashes = {sha256 = "529af13c5f4b7a932fb0e1911d3a75da204eff023ee5e0e79c1751564221a5c8"}
"numpy-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" = {upload-time = 2024-07-21T13:38:48.972569Z, url = "https://files.pythonhosted.org/packages/2c/f3/61eee37decb58e7cb29940f19a1464b8608f2cab8a8616aba75fd/numpy-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", size = 19242336, hashes = {sha256 = "6790654cb13eab303d8402354fabd47472b24635700f631f041bd0b65e37298a"}
"numpy-2.0.1-cp312-cp312-musllinux_1_1_x86_64.whl" = {upload-time = 2024-07-21T13:39:19.213811Z, url = "https://files.pythonhosted.org/packages/77/b5/c74cc436114c1de5912cdb475145245f6e645a6a1a29b5d08c774/numpy-2.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", size = 19637264, hashes = {sha256 = "cbab9fc9c391700e3e1287666dfd82d8666d10e69a6c4a09ab97574c0b7ee0a7"}
"numpy-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl" = {upload-time = 2024-07-21T13:39:41.812321Z, url = "https://files.pythonhosted.org/packages/da/89/c8856e12e0b3f6af371ccb90d604600923b08050c58f0cd26eac9/numpy-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", size = 14108911, hashes = {sha256 = "99d0d92a5e3613c33a5f01db206a33f8fdf3d71f2912b0de1739894668b7a93b"}
"numpy-2.0.1-cp312-cp312-win32.whl" = {upload-time = 2024-07-21T13:39:52.932102Z, url = "https://files.pythonhosted.org/packages/15/96/310c6f6d146518479b0a6ee6eb92a537954ec3b1acfa2894d1347/numpy-2.0.1-cp312-cp312-win32.whl", size = 6171379, hashes = {sha256 = "173a00b9995f73b79eb0191129f2455f1e34c203f559dd118636858cc452a1bf"}
"numpy-2.0.1-cp312-cp312-win_amd64.whl" = {upload-time = 2024-07-21T13:40:17.532627Z, url = "https://files.pythonhosted.org/packages/b5/59/f6ad378ad85ed9c2785f271b39c3e5b6412c66e810d2c60934c9f/numpy-2.0.1-cp312-cp312-win_amd64.whl", size = 16255757, hashes = {sha256 = "bb2124fdc6e62baae159ebcfa368708867eb56806804d005860b6007388df171"}

Im Allgemeinen bevorzugten die Leute dies jedoch nicht gegenüber dem Ansatz, den dieses PEP verfolgt.

Selbstreferenziell

Löschen der [tool]-Tabelle

Die [tool]-Tabelle ist enthalten, da sie sich für pyproject.toml-Dateien als sehr nützlich erwiesen hat. Die Bereitstellung ähnlicher Flexibilität in diesem PEP soll hoffen, dass ähnliche Vorteile entstehen.

Einige Leute haben jedoch Bedenken geäußert, dass eine solche Tabelle für Werkzeuge zu verlockend sein wird und zu werkzeugspezifischen und von anderen Werkzeugen unbrauchbaren Dateien führen wird. Dies könnte Probleme für Werkzeuge verursachen, die Installationen, Überprüfungen usw. durchführen, da sie nicht wissen würden, welche Details in der [tool]-Tabelle kritisch sind.

Als Kompromiss legt dieses PEP fest, dass die in [tool] aufgezeichneten Details verwerfbar sein müssen und die Installation von Paketen nicht beeinträchtigen dürfen.

Auflistung der Anforderungseingaben für die Datei

Derzeit werden in der Datei nicht die Anforderungen aufgezeichnet, die als Eingaben für die Datei dienten. Dies geschieht aus Gründen der Einfachheit und um die Datei nicht auf eine unvorhergesehene Weise explizit einzuschränken (z. B. die Aktualisierung der Datei nach der anfänglichen Erstellung für eine neue Plattform mit anderen Anforderungen, ohne auflösen zu müssen, wie ein umfassendes Anforderungsspektrum geschrieben werden soll).

Es könnte jedoch bei der Überprüfung und jeder Neuerstellung der Datei helfen, wenn die ursprünglichen Anforderungen irgendwie aufgezeichnet wurden. Dies könnte eine einzelne Zeichenkette oder ein Array von Zeichenketten sein, wenn mehrere Anforderungen mit der Datei verwendet wurden.

Letztendlich wurde es als zu kompliziert erachtet, die Eingaben, die ein Werkzeug zum Erstellen der Lock-Datei verwendet hat, auf generische Weise zu erfassen.

Auditing

Aufzeichnung von Abhängigen

Die Aufzeichnung der Abhängigkeiten eines Pakets ist nicht erforderlich, um es zu installieren. Daher wurde es aus dem PEP ausgeschlossen, da es über [tool] enthalten werden kann.

Das Wissen, wie kritisch ein Paket für andere Pakete ist, kann jedoch von Vorteil sein. Diese Information ist in pip-tools enthalten, es gibt also bereits Beispiele dafür. Ein flexibler Ansatz könnte verwendet werden, um die Abhängigkeiten aufzuzeichnen, z. B. so viele Details wie nötig, um sie von jedem anderen Eintrag für dasselbe Paket in der Datei zu unterscheiden (inspiriert von uv).

Letztendlich wurde jedoch entschieden, dass die Aufzeichnung der Abhängigkeiten sinnvoller ist.

Danksagungen

Vielen Dank an alle, die an den Diskussionen auf discuss.python.org teilgenommen haben. Vielen Dank auch an Randy Döring, Seth Michael Larson, Paul Moore und Ofek Lev für ihr Feedback zu einer Entwurfsversion dieses PEP, bevor es veröffentlicht wurde. Dank an Randy Döring von Poetry, Charlie Marsh von uv und Frost Ming von PDM für ihr Feedback im Namen ihrer jeweiligen Projekte.


Quelle: https://github.com/python/peps/blob/main/peps/pep-0751.rst

Letzte Änderung: 2025-06-20 17:43:34 GMT