PEP 804 – Ein externes Abhängigkeitsregister und Namensabbildungsmechanismus
- Autor:
- Pradyun Gedam <pradyunsg at gmail.com>, Ralf Gommers <ralf.gommers at gmail.com>, Michał Górny <mgorny at quansight.com>, Jaime Rodríguez-Guerra <jaime.rogue at gmail.com>, Michael Sarahan <msarahan at gmail.com>
- Discussions-To:
- Discourse thread
- Status:
- Entwurf
- Typ:
- Standards Track
- Thema:
- Packaging
- Benötigt:
- 725
- Erstellt:
- 03-Sep-2025
- Post-History:
- 22-Sep-2025
Inhaltsverzeichnis
- Zusammenfassung
- Motivation
- Begründung
- Spezifikation
- Abwärtskompatibilität
- Sicherheitsimplikationen
- Wie man das lehrt
- Referenzimplementierung
- Abgelehnte Ideen
- Zentralisierte Abbildungen, die vom selben Gremium verwaltet werden
- Ermöglichung von Ökosystem-spezifischen Varianten von Paketen
- Hinzufügen weiterer Paketmetadaten zum zentralen Register
- Abbildung von PyPI-Projekten auf umgepackte Gegenstücke in Ziel-Ökosystemen
- Strikte Validierung von Identifikatoren
- Offene Fragen
- Referenzen
- Anhang A: Betriebliche Vorschläge
- Anhang B: Vorschlag zur virtuellen Versionierung
- Urheberrecht
Zusammenfassung
Dieses PEP spezifiziert einen Namensabbildungsmechanismus, der es Packaging-Tools ermöglicht, externe Abhängigkeitsidentifikatoren (wie in PEP 725 eingeführt) auf ihre Gegenstücke in anderen Paket-Repositories abzubilden.
Motivation
Pakete auf PyPI erfordern oft Build-Zeit- und Laufzeitabhängigkeiten, die nicht auf PyPI vorhanden sind. PEP 725 führte Metadaten ein, um solche Abhängigkeiten auszudrücken. Die Verwendung konkreter externer Abhängigkeitsmetadaten für ein Python-Paket erfordert die Abbildung der angegebenen Abhängigkeitsidentifikatoren auf die in anderen Ökosystemen verwendeten Spezifizierer, was Folgendes ermöglichen würde:
- Ermöglichen von Tools, externe Abhängigkeiten automatisch auf Pakete in anderen Packaging-Repositories/Ökosystemen abzubilden,
- Einbeziehung der benötigten externen Abhängigkeiten *mit den Paketnamen, die vom relevanten System-Paketmanager auf dem System des Benutzers verwendet werden*, in Fehlermeldungen, die von Python-Paketinstallern und Build-Frontends ausgegeben werden, sowie die Ermöglichung für den Benutzer, diese Namen direkt abzufragen, um Installationsanweisungen zu erhalten.
Packaging-Ökosysteme wie Linux-Distributionen, Conda, Homebrew, Spack und Nix benötigen vollständige Abhängigkeitssätze für Python-Pakete und verfügen über Tools wie pyp2rpm (Fedora), Grayskull (Conda) und dh_python (Debian), die versuchen, Abhängigkeitsinformationen automatisch aus den Metadaten von Upstream-Python-Paketen zu generieren. Vor PEP 725 wurden externe Abhängigkeiten manuell behandelt, da es dafür keine Metadaten in pyproject.toml oder anderen Standard-Metadaten-Dateien gab. Die Ermöglichung der automatischen Konvertierung ist ein Hauptvorteil dieses PEP, der Python-Packaging einfacher und zuverlässiger macht. Darüber hinaus stellen sich die Autoren andere Arten von Tools vor, die diese Informationen nutzen, z. B. Abhängigkeitsanalyse-Tools wie Repology, Dependabot und libraries.io.
Begründung
Vorherige Technik
Die R-Sprache verfügt über ein System Requirements for R packages mit einem zentralen Register, das weiß, wie externe Abhängigkeitsmetadaten in Installationsbefehle für Paketmanager wie apt-get übersetzt werden. Dieses Register zentralisiert die Abbildungen für eine Reihe von Linux-Distributionen sowie für Windows. macOS ist nicht vorhanden. Die „Regelabdeckung“ seiner README zeigte früher, dass dieses System die Erfolgsquote beim Erstellen von Paketen aus CRAN von Grund auf verbessert. Über alle CRAN-Pakete hinweg verbesserte sich Ubuntu 18 von 78,1 % auf 95,8 %, CentOS 7 von 77,8 % auf 93,7 % und openSUSE 15.0 von 78,2 % auf 89,7 %. Die Erfolgsquote hängt davon ab, wie gut das Register gepflegt wird, aber der Gewinn ist erheblich: ~4x weniger Pakete scheitern beim Erstellen in einem Docker-Container unter Ubuntu und CentOS.
RPM-basierte Distributionen wie Fedora können eine regelbasierte Implementierung (NameConvertor) in pyp2rpm verwenden. Die Hauptregel ist, dass der RPM-Name für ein PyPI-Paket f"python-{pypi_package_name}" lautet. Dies scheint recht gut zu funktionieren; es gibt einige Varianten wie Python-versionsspezifische Namen, bei denen das Präfix die Haupt- und Nebenversionsnummern von Python enthält (z. B. python311- statt python-).
Gentoo folgt einem ähnlichen Ansatz bei der Benennung von Python-Paketen und verwendet die Kategorie dev-python/ und einige gut spezifizierte Regeln.
Conda-Forge hat eine explizitere Namensabbildung, da die Basisnamen in Conda-Forge die gleichen sind wie auf PyPI (z. B. wird numpy auf numpy abgebildet), aber es gibt viele Ausnahmen aufgrund von Namenskollisionen und Umbenennungen (z. B. ist der PyPI-Name für PyTorch torch, während er in Conda-Forge pytorch ist). Es gibt mehrere Namensabbildungsbemühungen, die von verschiedenen Teams gepflegt werden. Die Infrastruktur von Conda-Forge generiert eine in regro/cf-graph-countyfair. Grayskull pflegt seine eigene kuratierte Abbildung. Prefix.dev erstellte die Parselmout-Abbildungen, um Conda- und PyPI-Integrationen in ihren Werkzeugen zu unterstützen. Eine vollständigere Übersicht über ihre Ansätze, Stärken und Schwächen finden Sie in conda/grayskull#564.
Das OpenStack-Ökosystem muss sich ebenfalls mit einigen Abbildungsbemühungen befassen. Alle konzentrieren sich ausschließlich auf Linux-Distributionen. pkg-map begleitet diskimage-builder und stellt ein Dateiformat bereit, in dem der Benutzer beliebige Variablennamen und ihre entsprechenden Namen in der Ziel-Distribution (Red Hat, Debian, OpenSUSE usw.) definiert. Siehe Beispiel für PyYAML. bindep definiert eine Datei bindep.txt (siehe Beispiel), in der Benutzer Abhängigkeiten auflisten können, die nicht von PyPI installiert werden können. Das Format ist zeilenbasiert, wobei jede Zeile eine Abhängigkeit enthält, wie sie im Debian-Ökosystem gefunden wird. Für andere Distributionen bietet es eine „Filter“-Syntax in eckigen Klammern, in der Benutzer andere Zielplattformen, optionale Abhängigkeiten und Extras angeben können.
Die Notwendigkeit von Abbildungen findet sich auch in anderen Ökosystemen wie SageMath, aber auch bei Endbenutzern selbst, die PyPI-Pakete mit ihrem bevorzugten System-Paketmanager installieren möchten (Beispiel StackOverflow-Frage).
Governance und Wartungskosten von Namensabbildungen
Die Wartungskosten für externe Abhängigkeitsabbildungen für eine große Anzahl von Packaging-Ökosystemen sind potenziell hoch. Wir wählen die Definition des Registers so, dass
- Eine zentrale Autorität pflegt die Liste der anerkannten DepURLs und die bekannten Ökosystem-Abbildungen.
- Die Abbildungen selbst werden von den Ziel-Packaging-Ökosystemen gepflegt.
Daher ist dieses System für ein gegebenes Ökosystem opt-in und die damit verbundenen Wartungskosten werden verteilt.
Generierung von paketmanager-spezifischen Installationsbefehlen
Python-Paketautoren mit externen Abhängigkeiten haben in ihrer Dokumentation normalerweise Installationsanweisungen für diese externen Abhängigkeiten. Diese Anweisungen sind schwierig zu schreiben und aktuell zu halten und decken normalerweise nur eine oder höchstens eine Handvoll Plattformen ab. Als Beispiel hier die Anweisungen von SciPy für seine externen Build-Abhängigkeiten (C/C++/Fortran-Compiler, OpenBLAS, pkg-config)
- Debian/Ubuntu:
sudo apt install -y gcc g++ gfortran libopenblas-dev liblapack-dev pkg-config python3-pip python3-dev - Fedora:
sudo dnf install gcc-gfortran python3-devel openblas-devel lapack-devel pkgconfig - CentOS/RHEL:
sudo yum install gcc-gfortran python3-devel openblas-devel lapack-devel pkgconfig - Arch Linux:
sudo pacman -S gcc-fortran openblas pkgconf - Homebrew auf macOS:
brew install gfortran openblas pkg-config
Die Paketnamen variieren stark, und es gibt Unterschiede, z. B. teilen einige Distributionen Header und andere Build-Zeit-Abhängigkeiten in ein separates -dev/-devel-Paket auf, während andere dies nicht tun. Mit dem Register in diesem PEP könnte dies sowohl umfassender als auch einfacher zu warten gemacht werden, durch einen Tool-Befehl mit der Semantik „*Zeige die vom Paketmanager dieses Ökosystems bevorzugte Installationsanweisung für alle externen Abhängigkeiten*“. Dies kann als eigenständiges Tool oder als neuer Unterbefehl in jedem Python-Entwicklungs-Workflow-Tool (z. B. Pip, Poetry, Hatch, PDM, uv) erfolgen.
Zu diesem Zweck kann jede Ökosystem-Abbildung eine Liste von Paketmanagern bereitstellen, die als kompatibel bekannt sind, mit Vorlagenanweisungen, wie Pakete installiert und abgefragt werden. Die bereitgestellten Installationsbefehlsvorlagen sind mit Abfragebefehlsvorlagen gekoppelt, damit diese Tools prüfen können, ob die benötigten Pakete bereits vorhanden sind, ohne einen Installationsvorgang versuchen zu müssen (was teuer sein kann und unbeabsichtigte Nebeneffekte wie Versions-Upgrades haben kann).
Registerdesign
Die Abbildungsinfrastruktur wurde so konzipiert, dass sie die folgenden Komponenten und Eigenschaften aufweist
- Ein zentrales Register von PEP 725-Identifikatoren (DepURLs), einschließlich mindestens der bekannten generischen und virtuellen Identifikatoren, die als kanonisch gelten.
- Eine Liste bekannter Ökosysteme, bei denen Ökosystem-Betreuer ihre Namensabbildung(en) registrieren können.
- Ein standardisiertes Schema, das definiert, wie Abbildungen strukturiert sein sollen. Jede Abbildung kann auch programmatische Details darüber liefern, wie ihre unterstützten Paketmanager funktionieren.
Die oben genannten Dokumente werden als JSON-Dateien bereitgestellt, die von begleitenden JSON-Schemas validiert werden. Eine Python-Bibliothek und CLI wird bereitgestellt, um diese Ressourcen abzufragen und zu nutzen. Der Benutzer kann konfigurieren, welchen System-Paketmanager er für die Standard-Paketabbildungen und die Befehlsgenerierung bevorzugt (z. B. ein Benutzer unter Ubuntu bevorzugt möglicherweise conda, brew oder spack anstelle von apt als seinen bevorzugten Paketmanager für externe Abhängigkeiten).
Spezifikation
Drei Schemas werden vorgeschlagen
- Ein zentrales Register bekannter DepURLs, wie in PEP 725 eingeführt.
- Eine Liste bekannter Ökosysteme und die kanonische URL für ihre Abbildungen.
- Die Ökosystem-spezifischen Abbildungen von DepURLs auf ihre entsprechenden Ökosystem-Spezifizierer, zuzüglich Details zu ihren Paketmanagern.
Zentrales Register
Das zentrale Register definiert, welche Identifikatoren als kanonisch anerkannt sind, sowie bekannte Aliase. Jeder Eintrag MUSS eine gültige DepURL im Feld id enthalten, mit einer optionalen Freitextbeschreibung description. Zusätzlich kann ein Eintrag auf einen anderen Eintrag über sein Feld provides verweisen, das einen String oder eine Liste von Strings akzeptiert, die bereits als id im Register definiert sind. Dies ist nützlich sowohl für Aliase (z. B. dep:generic/arrow und dep:github/apache/arrow) als auch für konkrete Implementierungen eines dep:virtual/-Eintrags (z. B. würde dep:generic/gcc dep:virtual/compiler/c bereitstellen). Einträge ohne provides-Inhalt oder, wenn sie gefüllt sind, nur mit dep:virtual/-Identifikatoren gelten als kanonisch. Das Feld provides darf in dep:virtual/-Definitionen NICHT vorhanden sein.
Ein zentrales Register ermöglicht die Validierung der Tabelle [external]. Alle beteiligten Werkzeuge MÜSSEN prüfen, ob die angegebenen Identifikatoren wohlgeformt sind. Zusätzlich können einige Werkzeuge PRÜFEN, ob die verwendeten Identifikatoren als kanonisch anerkannt sind. Genauer gesagt:
- Build-Backends, Build-Frontends und Installer SOLLTEN standardmäßig keine Validierung durchführen, ob Identifikatoren kanonisch sind.
- Uploader wie
twineSOLLTEN prüfen, ob die Identifikatoren kanonisch sind und den Benutzer warnen oder einen Fehler melden, mit Opt-out-Mechanismen. Sie SOLLTEN einen kanonischen Ersatz vorschlagen, falls verfügbar. - Indexserver wie PyPI KÖNNEN die gleiche Validierung wie die Uploader durchführen und das Artefakt gegebenenfalls ablehnen.
Dieses Register SOLLTE auch autoritative Entscheidungen über seinen Inhalt zentralisieren, wie z. B. welche Aliase als kanonisch bevorzugt wird oder welches Versionierungsschema für virtuelle DepURLs gilt (siehe Anhang B). Die entsprechenden Antworten werden in diesem PEP nicht gegeben; stattdessen delegieren wir diese Verantwortung an die Betreuer des zentralen Registers.
Abbildungen
Die Abbildungen geben an, welche Ökosystem-spezifischen Identifikatoren die kanonischen Einträge im zentralen Register bereitstellen. Eine Abbildung besteht hauptsächlich aus einer Liste von Wörterbüchern, in denen jeder Eintrag Folgendes umfasst:
- ein Feld
idmit der kanonischen DepURL. - ein optionaler Freitext
description. - ein Feld
specs, dessen Wert eines der folgenden sein MUSS:- ein Wörterbuch mit drei Schlüsseln (
build,host,run). Die Werte müssen ein String oder eine Liste von Strings sein, die die Ökosystem-spezifischen Paketidentifikatoren darstellen, wie sie als Build-, Host- und Laufzeitabhängigkeiten benötigt werden (siehe PEP 725 für Details zu diesen Definitionen). - der Bequemlichkeit halber werden auch ein String oder eine Liste von Strings als Kurzform akzeptiert. In diesem Fall werden die Identifikatoren verwendet, um die drei oben genannten Kategorien zu befüllen.
- eine leere Liste, die verstanden wird, als hätte das Ökosystem keine Pakete, um eine solche Abhängigkeit bereitzustellen.
- ein Wörterbuch mit drei Schlüsseln (
- ein Feld
specs_from, dessen Wert eine DepURL ist, aus der das Feldspecsimportiert wird. Entwederspecsoderspecs_fromMUSS vorhanden sein. - ein optionales Feld
urls, dessen Wert eine URL, eine Liste von URLs oder ein Wörterbuch sein MUSS, das einen String einer URL zuordnet. Dies ist nützlich, um auf externe Ressourcen zu verlinken, die weitere Informationen über die abgebildeten Pakete liefern.
Die Abbildungen SOLLTEN auch einen weiteren Abschnitt package_managers angeben, der die im Ökosystem verfügbaren Paketmanager und deren Verwendung meldet. Dieses Feld MUSS eine Liste von Wörterbüchern akzeptieren, von denen jedes die folgenden Felder meldet
name(String), eindeutiger Bezeichner für diesen Paketmanager. Üblicherweise der ausführbare Name.commands(Liste von Wörterbüchern), die Befehle, die ausgeführt werden müssen, um die abgebildeten Pakete zu installieren und zu prüfen, ob sie bereits installiert sind.specifier_syntax: Anweisungen, wie eine Teilmenge von PEP 440-Spezifizierern auf den Ziel-Paketmanager abgebildet wird. Drei Unterstützungsstufen werden angeboten: nur Name, nur exakte Version und Kompatibilität mit Versionsbereichen (mit pro-Operator-Übersetzungen).
Jede Abbildung MUSS eine kanonische URL für den Online-Abruf haben. Diese Abbildungen KÖNNEN auch für die Offline-Verteilung auf jeder Plattform verpackt werden. Die Autoren empfehlen, sie am Standardort für Datenartefakte auf jedem Betriebssystem zu platzieren; z. B. $XDG_DATA_DIRS unter Linux und anderen, ~/Library/Application Support unter macOS und %LOCALAPPDATA% für Windows. Der Unterverzeichnisbezeichner MUSS external-packaging-metadata-mappings lauten. Dieses Datenverzeichnis SOLLTE nur Abbildungsdokumente mit dem Namen {ecosystem-identifier}.mapping.json enthalten. Das zentrale Register und die bekannten Ökosystem-Dokumente KÖNNEN ebenfalls in diesem Verzeichnis verteilt werden, als registry.json und known-ecosystems.json.
Bekannte Ökosysteme
Die Liste der bekannten Ökosysteme hat zwei Rollen:
- Meldung der kanonischen URL für ihre Abbildung.
- Zuweisung eines Kurzbezeichners zu jedem Ökosystem. Dies ist der Bezeichner, der in den oben genannten Abbildungsdateinamen verwendet werden MUSS, damit sie im lokalen Dateisystem gefunden werden können.
Für Ökosysteme, die Linux-Distributionen entsprechen, muss der Bezeichner derjenige sein, der von ihrem os-release ID-Parameter gemeldet wird. Für andere Ökosysteme muss dies bei der Einreichung des Dokuments mit den bekannten Ökosystemen entschieden werden. Es dürfen nur die Zeichen verwendet werden, die im Feld ID von os-release zulässig sind, gemäß diesem Regex [a-z0-9\-_.]+.
Schema-Details
Drei JSON-Schema-Dokumente werden bereitgestellt, um die Register und Abbildungen vollständig zu standardisieren.
Schema des zentralen Registers
Das zentrale Register wird durch das folgende JSON-Schema spezifiziert.
$schema
| Typ | string |
| Description | URL der Schema für die Definitionsliste, die für das Dokument verwendet wird. |
| Erforderlich | False |
schema_version
| Typ | integer |
| Erforderlich | False |
definitions
| Typ | array |
| Description | Liste der derzeit anerkannten DepURLs. |
| Erforderlich | True |
Jeder Eintrag in dieser Liste ist definiert als
| Feld. | Typ | Description | Erforderlich |
|---|---|---|---|
id |
DepURLField (string, das dem Regex ^dep:.+$ entspricht) |
DepURL | True |
description |
string |
Freitextfeld zum Hinzufügen von Details über das Paket. Erlaubt Markdown. | False |
provides |
DepURLField | list[DepURLField] |
Liste der Identifikatoren, auf die dieser Eintrag verweist. Nützlich zur Anmerkung von Aliassen oder virtuellen Paketimplementierungen. | False |
urls |
AnyUrl | list[AnyUrl] | dict[NonEmptyString, AnyUrl] |
Hyperlinks zu Webadressen, die weitere Informationen über die Definition liefern. | False |
Schema der bekannten Ökosysteme
Die Liste der bekannten Ökosysteme wird durch das folgende JSON-Schema spezifiziert.
$schema
| Typ | string |
| Description | URL des für das Dokument verwendeten Schemas für Abbildungen. |
| Erforderlich | False |
schema_version
| Typ | integer |
| Erforderlich | False |
ecosystems
| Typ | dict |
| Description | Namen von Ökosystemen und ihre entsprechenden Details. |
| Erforderlich | True |
Dieses Wörterbuch bildet nicht-leere String-Schlüssel, die auf die Ökosystem-Identifikatoren verweisen, auf ein Unter-Wörterbuch ab, das definiert ist als
| Key | Werttyp | Wertbeschreibung | Erforderlich |
|---|---|---|---|
Literal['mapping'] |
AnyURL |
URL zur Abbildung für dieses Ökosystem | True |
Schema der Abbildungen
Die Abbildungen werden durch das folgende JSON-Schema spezifiziert.
$schema
| Typ | string |
| Description | URL des für das Dokument verwendeten Schemas für Abbildungen. |
| Erforderlich | False |
schema_version
| Typ | integer |
| Erforderlich | False |
name
| Typ | string |
| Description | Name des Schemas |
| Erforderlich | True |
description
| Typ | string | None |
| Description | Freitextfeld zum Hinzufügen von Informationen zu dieser Abbildung. Erlaubt Markdown. |
| Erforderlich | False |
mappings
| Typ | array |
| Description | Liste von DepURL-zu-Specs-Abbildungen. |
| Erforderlich | True |
Jeder Eintrag in dieser Liste ist definiert als
| Feld. | Typ | Description | Erforderlich |
|---|---|---|---|
id |
DepURLField (string, das dem Regex ^dep:.+$ entspricht) |
DepURL, wie im zentralen Register angegeben | True |
description |
string |
Freitextfeld zum Hinzufügen von Details über das Paket. Erlaubt Markdown. | False |
urls |
AnyUrl | list[AnyUrl] | dict[NonEmptyString, AnyUrl] |
Hyperlinks zu Webadressen, die weitere Informationen über die Definition liefern. | False |
specs |
string | list[string] | dict[Literal['build', 'host', 'run'], string | list[string]] |
Ökosystem-spezifische Identifikatoren für dieses Paket. Die vollständige Form ist ein Wörterbuch, das die Kategorien build, host und run auf ihre entsprechenden Paketidentifikatoren abbildet. Als Kurzform kann ein einzelner String oder eine Liste von Strings angegeben werden, die dann verwendet werden, um alle drei Kategorien identisch zu befüllen. |
Entweder specs oder specs_from MUSS vorhanden sein. |
specs_from |
DepURLField (string, das dem Regex ^dep:.+$ entspricht) |
Übernimmt Specs aus einem anderen Abbildungseintrag. | Entweder specs oder specs_from MUSS vorhanden sein. |
extra_metadata |
dict[NonEmptyString, Any] |
Freitext-Schlüssel-Wert-Speicher für beliebige Metadaten. | False |
package_managers
| Typ | array |
| Description | Liste von Tools, die zur Installation von Paketen in diesem Ökosystem verwendet werden können. |
| Erforderlich | True |
Jeder Eintrag in dieser Liste ist als Wörterbuch mit diesen Feldern definiert.
| Feld. | Typ | Description | Erforderlich |
|---|---|---|---|
name |
string |
Kurzer Bezeichner für diesen Paketmanager (üblicherweise der Befehlsname) | True |
commands |
dict[Literal['install', 'query'], dict[Literal['command', 'requires_elevation', 'multiple_specifiers'], list[str] | bool | Literal['always', 'name-only', 'never']]] |
Befehle zur Installation oder Abfrage der angegebenen Pakete. Es sind nur zwei Schlüssel zulässig: install und query. Ihr Wert ist ein Wörterbuch mit
Genau einer der |
True |
specifier_syntax |
dict[Literal['name_only', 'exact_version', 'version_ranges'], None | list[str] | dict[Literal['and', 'equal', 'greater_than', 'greater_than_equal', 'less_than', 'less_than_equal', 'not_equal', 'syntax'], None | str | list[str]] |
Abbildung der zulässigen PEP440-Versions-Spezifizierer auf die in diesem Paketmanager verwendete Syntax. Drei übergeordnete Schlüssel sind erwartet und erforderlich
|
True |
Beispiele
Register, bekannte Ökosysteme und Abbildungen
Eine vereinfachte Registry würde wie folgt aussehen
{
"$schema": "https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/main/schemas/central-registry.schema.json",
"schema_version": 1,
"definitions": [
{
"id": "dep:generic/zlib",
"description": "A Massively Spiffy Yet Delicately Unobtrusive Compression Library"
},
{
"id": "dep:generic/libwebp",
"description": "WebP codec is a library to encode and decode images in WebP format. This package contains the library that can be used in other programs to add WebP support"
},
{
"id": "dep:generic/clang",
"description": "Language front-end and tooling infrastructure for languages in the C language family for the LLVM project."
}
]
}
Eine minimale Liste bekannter Ökosysteme mit einem einzigen Eintrag würde wie folgt aussehen
{
"$schema": "https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/main/schemas/known-ecosystems.schema.json",
"schema_version": 1,
"ecosystems": {
"conda-forge": {
"mapping": "https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/refs/heads/main/data/conda-forge.mapping.json"
}
}
Diese hypothetische conda-forge-Zuordnung (conda-forge.mapping.json), mit nur wenigen Einträgen zur Kürze, könnte wie folgt aussehen
{
"schema_version": 1,
"name": "conda-forge",
"description": "Mapping for the conda-forge ecosystem",
"mappings": [
{
"id": "dep:generic/zlib",
"description": "zlib data compression library for the next generation systems. From zlib-ng/zlib-ng.",
"specs": "zlib-ng", // Simplest form
"urls": {
"feedstock": "https://github.com/conda-forge/zlib-ng-feedstock"
}
},
{
"id": "dep:generic/libwebp",
"description": "WebP image library. libwebp-base ships libraries; libwebp ships the binaries.",
"specs": { // expanded form with single spec per category
"build": "libwebp",
"host": "libwebp-base",
"run": "libwebp"
},
"urls": {
"feedstock": "https://github.com/conda-forge/libwebp-feedstock"
}
},
{
"id": "dep:generic/clang",
"description": "Development headers and libraries for Clang",
"specs": { // expanded form with specs list
"build": [
"clang",
"clangxx"
],
"host": [
"clangdev"
],
"run": [
"clang",
"clangxx",
"clang-format",
"clang-tools"
]
},
"urls": {
"feedstock": "https://github.com/conda-forge/clangdev-feedstock"
}
},
],
"package_managers": [
{
"name": "conda",
"commands": {
"install": {
"command": [
"conda",
"install",
"{}"
],
"multiple_specifiers": "always",
"requires_elevation": false,
},
"query": {
"command": [
"conda",
"list",
"-f",
"{}"
],
"multiple_specifiers": "never",
"requires_elevation": false,
}
},
"specifier_syntax": {
"exact_version": [
"{name}=={version}"
],
"name_only": [
"{name}"
],
"version_ranges": {
"and": ",",
"equal": "={version}",
"greater_than": ">{version}",
"greater_than_equal": ">={version}",
"less_than": "<{version}",
"less_than_equal": "<={version}",
"not_equal": "!={version}",
"syntax": [
"{name}{ranges}"
]
}
}
}
]
}
Das folgende Repository enthält Beispiele dafür, wie diese Schemata in realen Fällen aussehen *könnten*. Sie sind nicht als vorschreibend gedacht, sondern nur als Veranschaulichung, wie diese Schemata angewendet werden können
- Zentrales Register.
- Bekannte Ökosysteme.
- Abbildungen
- Arch-linux.
- Chocolatey.
- Conan.
- Conda-forge.
- Fedora.
- Gentoo.
- Homebrew.
- Nix.
- PyPI.
- Scoop.
- Spack.
- Ubuntu.
- Vcpkg.
- Winget.
pyproject-external CLI
Die folgenden Beispiele veranschaulichen, wie der Namenszuordnungsmechanismus verwendet werden kann. Sie verwenden die CLI, die als Teil des Pakets pyproject-external implementiert ist.
Nehmen wir an, wir haben den Quellcode eines Python-Pakets namens my-cxx-pkg geklont, das ein einziges Erweiterungsmodul enthält, in C++ implementiert ist, mit zlib verknüpft und pybind11 verwendet, plus meson-python als Build-Backend
[build-system]
build-backend = 'mesonpy'
requires = [
"meson-python>=0.13.1",
"pybind11>=2.10.4",
]
[external]
build-requires = [
"dep:virtual/compiler/cxx",
]
host-requires = [
"dep:generic/zlib",
]
Mit vollständigen Namenszuordnungen für apt unter Ubuntu könnte dies dann wie folgt aussehen
# show all external dependencies as DepURLs
$ python -m pyproject_external show .
[external]
build-requires = [
"dep:virtual/compiler/cxx",
]
host-requires = [
"dep:generic/zlib",
]
# show all external dependencies, but mapped to the autodetected ecosystem
$ python -m pyproject_external show --output=mapped .
[external]
build_requires = [
"g++",
"python3",
]
host_requires = [
"zlib1g",
"zlib1g-dev",
]
# show how to install external dependencies
$ python -m pyproject_external show --output=command .
sudo apt install --yes g++ zlib1g zlib1g-dev python3
Wir haben diese Installationsbefehle noch nicht ausgeführt, daher kann die externe Abhängigkeit fehlen. Wenn wir einen Build-Fehler erhalten, könnte die Ausgabe wie folgt aussehen
$ pip install .
...
× Encountered error while generating package metadata.
╰─> See above for output.
note: This is an issue with the package mentioned above, not pip.
This package has the following external dependencies, if those are missing
on your system they are likely to be the cause of this build failure:
dep:virtual/compiler/cxx
dep:generic/zlib
Wenn Pip die Unterstützung für die Abfrage der Namenszuordnungsregistry implementiert hat, könnte das Ende dieser Meldung verbessert werden zu
The following external dependencies are needed to install the package
mentioned above. You may need to install them with `apt`:
g++
zlib1g
zlib1g-dev
Wenn der Benutzer Conda-Pakete und den Paketmanager mamba zur Installation externer Abhängigkeiten verwenden möchte, kann er dies in seiner Datei ~/.config/pyproject-external/config.toml (oder äquivalent) angeben
preferred_package_manager = "mamba"
Dies wird dann die Ausgabe von pyproject-external ändern
$ python -m pyproject_external show --output command .
mamba install --yes --channel=conda-forge --channel-priority=strict cxx-compiler zlib python
Die pyproject-external CLI bietet auch eine einfache Möglichkeit, [external]-Tabellen gegen die zentrale Registry zu validieren, um zu prüfen, ob die Bezeichner als kanonisch gelten oder nicht
$ python -m pyproject_external show --validate grpcio-1.71.0.tar.gz
WARNING Dep URL 'dep:virtual/compiler/cpp' is not recognized in the
central registry. Did you mean any of ['dep:virtual/compiler/c',
'dep:virtual/compiler/cxx', 'dep:virtual/compiler/cuda',
'dep:virtual/compiler/go', 'dep:virtual/compiler/c-sharp']?
[external]
build-requires = [
"dep:virtual/compiler/c",
"dep:virtual/compiler/cpp",
]
pyproject-external API
Die Python-API von pyproject-external ermöglicht es Benutzern auch, diese Operationen programmatisch durchzuführen
>>> from pyproject_external import External
>>> external = External.from_pyproject_data(
{
"external": {
"build-requires": [
"dep:virtual/compiler/c",
"dep:virtual/compiler/cpp",
]
}
}
)
>>> external.validate()
Dep URL 'dep:virtual/compiler/cpp' is not recognized in the central registry. Did you
mean any of ['dep:virtual/compiler/c', 'dep:virtual/compiler/cxx',
'dep:virtual/compiler/cuda', 'dep:virtual/compiler/go', 'dep:virtual/compiler/c-sharp']?
>>> external = External.from_pyproject_data(
{
"external": {
"build-requires": [
"dep:virtual/compiler/c",
"dep:virtual/compiler/cxx", # fixed
]
}
}
)
>>> external.validate()
>>> external.to_dict()
{'external': {'build_requires': ['dep:virtual/compiler/c', 'dep:virtual/compiler/cxx']}}
>>> from pyproject_external import detect_ecosystem_and_package_manager
>>> ecosystem, package_manager = detect_ecosystem_and_package_manager()
>>> ecosystem
'conda-forge'
>>> package_manager
'pixi'
>>> external.to_dict(mapped_for=ecosystem, package_manager=package_manager)
{'external': {'build_requires': ['c-compiler', 'cxx-compiler', 'python']}}
>>> external.install_command(ecosystem, package_manager=package_manager)
# {"command": ["pixi", "add", "{}"]}
['pixi', 'add', 'c-compiler', 'cxx-compiler', 'python']
>>> external.query_commands(ecosystem, package_manager=package_manager)
# {"command": ["pixi", "list", "{}"]}
[
['pixi', 'list', 'c-compiler'],
['pixi', 'list', 'cxx-compiler'],
['pixi', 'list', 'python'],
]
Grayskull
Eine Prototyp-Proof-of-Concept-Implementierung wurde zu Grayskull, einem Conda-Rezeptgenerator für Python-Pakete, über conda/grayskull#518 beigetragen.
Um die Namenszuordnungen für den Rezeptgenerator unseres Pakets zu verwenden, können wir jetzt Grayskull ausführen
$ grayskull pypi my-cxx-pkg
#### Initializing recipe for my-cxx-pkg (pypi) ####
Recovering metadata from pypi...
Starting the download of the sdist package my-cxx-pkg
my-cxx-pkg 100% Time: 0:00:10 5.3 MiB/s|###########|
Checking for pyproject.toml
...
Build requirements:
- python # [build_platform != target_platform]
- cross-python_{{ target_platform }} # [build_platform != target_platform]
- meson-python >= 0.13.1 # [build_platform != target_platform]
- pybind11 >= 2.10.4 # [build_platform != target_platform]
- ninja # [build_platform != target_platform]
- libboost-devel # [build_platform != target_platform]
- {{ compiler('cxx') }}
Host requirements:
- python
- meson-python >=0.13.1
- pybind11 >=2.10.4
- ninja
- libboost-devel
Run requirements:
- python
#### Recipe generated on /path/to/recipe/dir for my-cxx-pkg ####
Abwärtskompatibilität
Es gibt keine Auswirkungen auf die Abwärtskompatibilität.
Sicherheitsimplikationen
Dieser Vorschlag hat keine Auswirkungen auf die Sicherheit bestehender Projekte. Die vorgeschlagenen Schemata, Registries und Zuordnungen sind verfügbare Ressourcen, die von nachgelagerten Werkzeugen nach Belieben und auf eine für sie passende Weise genutzt werden können.
Wir haben einige Empfehlungen für zukünftige Implementierer. Das Zuordnungsschema schlägt Felder zur Kodierung von Anweisungen für die Befehlsausführung vor (package_managers[].commands). Eine manipulierte Zuordnung kann diese Anweisungen in etwas anderes ändern. Daher sollten sich Tools nicht auf die Internetverbindung verlassen, um die Zuordnungen aus ihren Online-Quellen abzurufen. Stattdessen
- sollten sie die relevanten Dokumente in den verteilten Paketen bündeln,
- oder auf vorab gepackte, Offline-Distributionen dieser Dokumente zurückgreifen,
- oder Best Practices für die Authentizitätsprüfung der abgerufenen Dokumente implementieren.
Die Installationsbefehle können die Systemkonfiguration des Benutzers ändern. Wenn verfügbar, sollten Tools vorzugsweise ephemere, isolierte Umgebungen für die Installation externer Abhängigkeiten erstellen. Wenn das Ökosystem diese Funktion nicht nativ unterstützt, können andere Lösungen wie Containerisierung verwendet werden. Zumindest sollten informative Meldungen über die Auswirkungen des Vorgangs bereitgestellt werden.
Wie man das lehrt
Es gibt mindestens vier Zielgruppen, die sich mit dem Inhalt dieser PEP vertraut machen müssen
- Betreuer der zentralen Registry, die für die Kuratierung der Liste der bekannten DepURLs und der zugeordneten Ökosysteme verantwortlich sind.
- Betreuer von Paket-Ökosystemen, die für die Aktualisierung der Zuordnung für ihr Ökosystem verantwortlich sind.
- Betreuer von Python-Projekten, die externe Abhängigkeiten erfordern.
- Endbenutzer von Paketen mit Metadaten zu externen Abhängigkeiten.
Betreuer des zentralen DepURL-Registers
Die Betreuer der zentralen DepURL-Registry kuratieren die Sammlung von DepURLs und die bekannten Ökosysteme. Diese Beitragenden müssen in der Lage sein, sich auf klar definierte Regeln zu beziehen, wann eine neue DepURL definiert werden kann. Es ist unerwünscht, bei kanonischen DepURL-Definitionen locker zu sein, da jede hinzugefügte Definition den Wartungsaufwand bei den Zuordnungen in den Zielökosystemen erhöht.
Die Betreuer der zentralen Registry sollten sich auf die Grundregeln einigen und diese als Teil der Repository-Dokumentation festhalten, möglicherweise unterstützt durch zusätzliche Hilfsmittel wie Issue- und Pull-Request-Vorlagen oder Linting-Tools.
Nutzung durch Paket-Ökosystem-Betreuer
Fehlende Zuordnungseinträge führen zum Fehlen maßgeschneiderter Fehlermeldungen und anderer UX-Hilfsmittel für Endbenutzer der betroffenen Ökosysteme. Es wird daher empfohlen, dass jedes Paket-Ökosystem seine Zuordnungen mit der zentralen Registry aktuell hält. Der Schlüssel dazu wird Automatisierung sein, wie z. B. Linting-Skripte (siehe Beispiel unter external-metadata-mappings) oder periodische Benachrichtigungen über Issues oder Entwurfs-Einreichungen.
Die Erstellung der anfänglichen Zuordnung wird wahrscheinlich viel Arbeit bedeuten, aber im Idealfall sollte der laufende Wartungsaufwand geringer sein.
Wenn Best Practices entdeckt und vereinbart werden, sollten sie im Repository der zentralen Registry als Lernmaterialien für die Zuordnungsbetreuer dokumentiert werden.
Betreuer von Python-Projekten
Die Verantwortung eines Paketbetreuers besteht darin, die DepURL zu entscheiden, die die externe Abhängigkeit am besten repräsentiert, die sein Paket benötigt. Dies wird in PEP 725 behandelt; das interaktive Zuordnungsbrowser-Demo unter external-metadata-mappings.streamlit.app kann nützlich sein. Die Dokumentation der zentralen Registry kann Beispiele und häufig gestellte Fragen enthalten, um Neulingen bei ihren Entscheidungen zu helfen.
Wenn keine geeignete DepURL für eine gegebene Abhängigkeit verfügbar ist, können Betreuer erwägen, eine Anfrage in der zentralen Registry einzureichen. Anweisungen zur Vorgehensweise sollten Teil der Dokumentation der zentralen Registry sein.
Endverbraucher von Paketen
Es wird standardmäßig keine Änderung der Benutzererfahrung geben. Dies gilt insbesondere, wenn der Benutzer nur auf Wheels zurückgreift, da die einzigen Auswirkungen von externen Laufzeitabhängigkeiten ausgehen (was selten erwartet wird), und selbst in diesen Fällen müssen sie durch die Installation eines kompatiblen Werkzeugs opt-in.
Benutzer, die sich für ein Opt-in entscheiden, können fehlende Einträge für ihre Ziel-Ökosysteme feststellen, für die sie informative Fehlermeldungen erhalten sollten, die auf die relevanten Dokumentationsabschnitte verweisen. Dies wird ihnen ermöglichen, sich mit der Art des Problems und seinen potenziellen Lösungen vertraut zu machen.
Wir hoffen, dass dies dazu führt, dass eine Teilmenge von ihnen die fehlenden Einträge meldet, eine Korrektur der betroffenen Zuordnung einreicht oder, wenn sie gänzlich fehlen, sogar selbst eine neue pflegt. Zu diesem Zweck sollten sie sich mit den Verantwortlichkeiten der Zuordnungsbetreuer (oben diskutiert) vertraut machen.
Referenzimplementierung
Eine Referenzimplementierung sollte drei Komponenten enthalten
- Eine zentrale Registry, die mindestens eine DepURL und ihre Beschreibung erfasst. Diese Registry darf keine spezifischen Informationen über Paket-Ökosystem-Zuordnungen enthalten.
- Eine Standard-Spezifikation für eine Sammlung von Zuordnungen. JSON Schema wird für Schemata in vielen Texteditoren häufig verwendet und wäre eine natürliche Wahl für den Ausdruck der Standardspezifikation.
- Eine Implementierung von (2), die Zuordnungen vom Inhalt der zentralen Registry zu den Ökosystem-spezifischen Paketnamen bereitstellt.
Für (1) ist das JSON-Schema unter central-registry.schema.json definiert. Eine Beispiel-Registry finden Sie unter registry.json. Für (2) ist das JSON-Schema unter external-mapping.schema.json definiert. Eine Sammlung von Beispielzuordnungen für eine Auswahl von Paketen finden Sie unter external-metadata-mappings. Für (3) ist das JSON-Schema unter known-ecosystems.schema.json definiert. Eine Beispieliste finden Sie unter known-ecosystems.json. Die JSON-Schemata werden mit diesen Pydantic-Modellen erstellt.
Die Referenz-CLI und die Python-API zum Konsumieren der verschiedenen JSON-Dokumente und [external]-Tabellen finden Sie in pyproject-external.
Abgelehnte Ideen
Zentralisierte Abbildungen, die vom selben Gremium verwaltet werden
Während eine zentrale Autorität für die Registry nützlich ist, ist die Wartungsbelastung für die Handhabung der Zuordnungen für mehrere Ökosysteme im Maßstab von PyPI nicht machbar. Daher schlagen wir vor, dass die zentrale Autorität nur die zentrale Registry und die Liste der bekannten Ökosysteme verwaltet, während die Wartung der Zuordnungen selbst von den Ziel-Ökosystemen übernommen wird.
Ermöglichung von Ökosystem-spezifischen Varianten von Paketen
Einige Ökosysteme haben ihre eigenen Varianten bekannter Pakete; z. B. Debians libsymspg2-dev. Während ein Bezeichner wie dep:debian/libsymspg2-dev syntaktisch gültig ist, sollte die zentrale Registry ihn nicht als bekannten Bezeichner anerkennen und stattdessen seinen generic Gegenpart bevorzugen. Benutzer können ihn immer noch verwenden, aber Tools können davor warnen und vorschlagen, den generischen zu verwenden. Dies soll eine ökosystemunabhängige Metadatenverwaltung fördern, wo immer dies möglich ist, um die Akzeptanz über verschiedene Plattformen und Betriebssysteme hinweg zu erleichtern.
Hinzufügen weiterer Paketmetadaten zum zentralen Register
Eine zentrale Registry sollte nur eine Liste von DepURLs und eine minimale Menge an Metadatenfeldern enthalten, um ihre Identifizierung zu erleichtern (eine Freitextbeschreibung und ein oder mehrere URLs zu relevanten Speicherorten).
Wir haben uns entschieden, zusätzliche Details aus der zentralen Registry herauszulassen und stattdessen externe Beitragende aufzufordern, ihre eigenen Zuordnungen zu pflegen, wo sie die Bezeichner mit zusätzlichen Metadaten über das Freitextfeld extra_metadata annotieren können.
Die Gründe dafür sind
- Die vorhandenen Felder sollten ausreichen, um den Projekt-Home zu identifizieren, wo diese zusätzlichen Metadaten bezogen werden können (z. B. das Repository unter der URL wird wahrscheinlich Details über Autorschaft und Lizenzierung enthalten).
- Diese Details können auch von den tatsächlichen Ziel-Ökosystemen bezogen werden. In einigen Fällen kann dies sogar vorzuziehen sein; z. B. für Lizenzen, wo die nachgelagerte Paketierung sie durch Entfernen von Abhängigkeiten oder Anpassen optionaler Teile beeinflussen kann.
- Diese Details können sich im Laufe der Lebensdauer des Projekts ändern, und ihre Aktualisierung würde die Wartungsbelastung für die Governance-Stelle erhöhen.
- Die Zentralisierung zusätzlicher Metadaten würde daher zu Mehrdeutigkeiten und Diskrepanzen zwischen den Ziel-Ökosystemen führen, wo unterschiedliche Versionen verfügbar oder erforderlich sein können.
Abbildung von PyPI-Projekten auf umgepackte Gegenstücke in Ziel-Ökosystemen
Es ist üblich, dass andere Ökosysteme Python-Projekte mit ihrem eigenen Paketierungssystem weiterverteilen. Während dies für Pakete mit kompilierten Erweiterungen erforderlich ist, ist es theoretisch für reine Python-Wheels unnötig; der einzige Bedarf dafür scheint die Metadatenübersetzung zu sein. Siehe Wanting a singular packaging tool/vision #68, Wanting a singular packaging tool/vision #103 und spack/spack#28282 für Beispiele für Diskussionen in diese Richtung.
Die in dieser PEP vorgeschlagenen Maßnahmen berücksichtigen keine PyPI -> *Ökosystem*-Zuordnungen, aber dieselben Schemata können für diesen Zweck wiederverwendet werden. Immerhin ist es trivial, eine PURL oder DepURL aus einem PyPI-Namen zu erstellen (z. B. wird numpy zu pkg:pypi/numpy). Ein hypothetischer Zuordnungsbetreuer könnte seine Neuverpackungsbemühungen mit dem Quell-PURL-Bezeichner annotieren und dann diese Metadaten verwenden, um kompatible Zuordnungen zu generieren, wie z. B.:
{
"$schema": "https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/main/schemas/external-mapping.schema.json",
"schema_version": 1,
"name": "PyPI packages in Ubuntu 24.04",
"description": "PyPI mapping for the Ubuntu 24.04 LTS (Noble) distro",
"mappings": [
{
"id": "dep:pypi/numpy",
"description": "The fundamental package for scientific computing with Python",
"specs": ["python3-numpy"],
"urls": {
"home": "https://numpy.org/"
}
}
]
}
Eine solche Zuordnung würde es nachgelagerten Neuverteilungsbemühungen ermöglichen, sich auf die kompilierten Pakete zu konzentrieren und stattdessen reine Wheels direkt an Python-Paketierungslösungen zu delegieren.
Strikte Validierung von Identifikatoren
Die zentrale Registry liefert eine Liste kanonischer Bezeichner, was Implementierer dazu verleiten kann, sicherzustellen, dass alle bereitgestellten Bezeichner tatsächlich kanonisch sind. Wir haben beschlossen, diese Praxis nur für einige Tool-Kategorien zu *empfehlen*, aber in keinem Fall diese Prüfungen zu *verlangen*.
Es wird erwartet, dass die Liste der *kanonischen* Bezeichner mit der Übernahme der [external]-Metadatentabellen durch die Paketgemeinschaft wächst, um die Anforderungen verschiedener Projekte zu erfüllen. Zum Beispiel wird eine neue C++-Bibliothek oder ein neuer Sprachcompiler eingeführt.
Wenn die Validierung zu streng ist und unbekannte Bezeichner ablehnt, würde dies unnötige Reibung bei der Übernahme von externen Metadaten verursachen und menschliches Eingreifen erfordern, um die neu angeforderten Bezeichner zeitkritisch zu überprüfen und zu akzeptieren, was potenziell die Veröffentlichung des Pakets blockieren könnte, das eine neue Identifizierung in der zentralen Registry benötigt.
Wir schlagen vor, einfach zu prüfen, ob die bereitgestellten Bezeichner korrekt formatiert sind. Zukünftige Arbeiten können erwägen, auch durchzusetzen, dass die Bezeichner als kanonisch anerkannt werden, sobald die zentrale Registry mit signifikanter Akzeptanz gereift ist.
Offene Fragen
Derzeit keine.
Referenzen
Anhang A: Betriebliche Vorschläge
Im Gegensatz zu den Ökosystem-Zuordnungen müssen die zentrale Registry und die Liste der bekannten Ökosysteme von einer zentralen Autorität gepflegt werden. Die Autoren schlagen vor
Anhang B: Vorschlag zur virtuellen Versionierung
Während virtuelle Abhängigkeiten mit derselben Syntax wie nicht-virtuelle Abhängigkeiten versioniert werden können, kann ihre Bedeutung mehrdeutig sein (z. B. kann es mehrere Implementierungen geben, und virtuelle Schnittstellen sind möglicherweise nicht eindeutig versionierbar). Nachfolgend finden Sie einige Vorschläge, die die Betreuer der zentralen Registry bei der Standardisierung dieser Bedeutung berücksichtigen können
- OpenMP: hat regelmäßige
MAJOR.MINOR-Versionen seines Standards, würde also wie>=4.5aussehen. - BLAS/LAPACK: sollte die Versionierung von Reference LAPACK verwenden, das definiert, was die API-Standards sind. Verwendet
MAJOR.MINOR.MICRO, würde also wie>=3.10.0aussehen. - Compiler: diese implementieren Sprachstandards. Für C, C++ und Fortran werden diese nach Jahren versioniert. Damit Versionen korrekt sortiert werden, empfehlen wir die Verwendung des vollen Jahres (vier Ziffern). "Mindestens C99" wäre also
>=1999, und die Auswahl von C++14 oder Fortran 77 wäre jeweils==2014oder==1977. Andere Sprachen können unterschiedliche Versionierungsschemata verwenden. Diese sollten irgendwo beschrieben werden, bevor sie inpyproject.tomlverwendet werden.
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-0804.rst
Zuletzt geändert: 2025-09-29 13:54:43 GMT