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

Python Enhancement Proposals

PEP 794 – Import-Name-Metadaten

Autor:
Brett Cannon <brett at python.org>
Discussions-To:
Discourse thread
Status:
Akzeptiert
Typ:
Standards Track
Thema:
Packaging
Erstellt:
05. Juni 2025
Post-History:
02. Mai 2025, 05. Juni 2025
Resolution:
05. Sep. 2025

Inhaltsverzeichnis

Zusammenfassung

Diese PEP schlägt vor, die Kernmetadatenspezifikation für Python-Packaging um zwei neue, wiederholbare Felder namens Import-Name und Import-Namespace zu erweitern, um die Importnamen aufzuzeichnen, die ein Projekt nach der Installation bereitstellt. Neue Schlüssel namens import-names und import-namespaces werden zur Tabelle [project] in pyproject.toml hinzugefügt, um die Werte für die neuen Kernmetadatenfelder bereitzustellen. Dies führt auch zur Einführung der Kernmetadatenversion 2.5.

Motivation

Im Python-Packaging gibt es keine Anforderung, dass ein Projektname mit dem oder den Namen übereinstimmt, die man für dieses Projekt importieren kann. Daher gibt es keine saubere, einfache und genaue Möglichkeit, vom Importnamen zum Projektnamen und umgekehrt zu gelangen. Dies kann es für Tools schwierig machen, die versuchen, Menschen bei der Ermittlung des richtigen Projekts zur Installation zu helfen, wenn sie den Importnamen kennen, oder zu wissen, welche Importnamen ein Projekt nach der Installation bereitstellen wird.

Zum Beispiel kann ein Code-Editor erkennen, dass ein Benutzer einen nicht erfüllten Import in einer ausgewählten virtuellen Umgebung hat. Aber ohne eine zuverlässige Möglichkeit zu wissen, welche Importnamen verschiedene Projekte bereitstellen, kann der Code-Editor dem Benutzer keine genaue Liste potenzieller Projekte zur Installation anbieten, um diese Importanforderung zu erfüllen (z. B. ist es nicht offensichtlich, dass import PIL sehr wahrscheinlich impliziert, dass der Benutzer das Projekt Pillow installiert haben möchte). Dies gilt auch, wenn sich ein Benutzer vage an den Projektnamen erinnert, sich aber nicht an den oder die Importnamen erinnert und durch eine Liste von Importnamen, die ein Paket bereitstellt, aufgeweckt werden möchte. Schließlich könnten Tools Benutzer darüber informieren, welche Importnamen nach der Installation eines Projekts verfügbar sein werden.

Es gibt auch keine einfache Möglichkeit zu wissen, ob die Installation zweier Projekte aufgrund der von ihnen bereitgestellten Importnamen miteinander in Konflikt gerät. Wenn beispielsweise zwei verschiedene Projekte ein _utils-Modul haben, führt die Installation beider Projekte zu einem Konflikt, da das _utils-Modul eines Projekts dem des anderen vorgeht, indem es die Datei des anderen Projekts überschreibt; dieses Problem wurde in der Praxis beobachtet.

Es kann auch bei der Spam-Erkennung helfen. Wenn ein Projekt dieselben Importnamen wie ein sehr beliebtes Projekt angibt, kann dies ein Signal sein, die Gültigkeit des weniger beliebten Projekts genauer zu prüfen. Ein Projekt, das sich über die von ihm bereitgestellten Importnamen irrt, wäre ein weiteres Signal.

Begründung

Diese PEP schlägt vor, die Kernmetadatenspezifikationen für Packaging zu erweitern, damit Projektbesitzer die höchsten Importnamen angeben können, die ein Projekt auf einer Plattform nach der Installation bereitstellt.

Das Ablegen dieser Metadaten in den Kernmetadaten bedeutet, dass die Daten von einem Indexserver (potenziell) bereitgestellt werden, unabhängig von sdists oder Wheels. Das macht es überflüssig, einen Weg zu finden, die Metadaten für Tools zugänglich zu machen, um zu vermeiden, dass ein ganzes z. B. Wheel heruntergeladen werden muss.

Wenn diese Metadaten für alle Release-Artefakte gleich sind, können Projekte nur eine einzige Kernmetadatendatei prüfen, um alle möglichen Importnamen zu erhalten, anstatt alle veröffentlichten Dateien zu prüfen. Dies bedeutet auch, dass man sich keine Sorgen machen muss, wenn eine Datei beim Lesen der Kernmetadaten fehlt, oder man kann ausschließlich von einem sdist arbeiten, wenn die Metadaten bereitgestellt werden. Außerdem vereinfacht dies die Schlüssel project.import-names und project.import-namespaces in pyproject.toml, indem sie für die gesamte Projektversion konsistent und nicht pro veröffentlichte Datei für dieselbe Version eindeutig sind.

Eine Distributionsdatei, die Module und Pakete enthält, kann beliebige Kombinationen von öffentlichen und privaten APIs auf Modul-/Paketebene enthalten. Distributionsdateien können auch keinerlei Module oder Pakete enthalten. Die Unterscheidbarkeit der Situationen hat verschiedene Werkzeuganwendungen, die für Benutzer vorteilhaft sein könnten. Zum Beispiel hilft die Kenntnis aller Importnamen, unabhängig davon, ob sie öffentlich oder privat sind, bei der Erkennung von Konflikten während der Installation. Die Kenntnis dessen, was explizit öffentlich oder privat ist, ermöglicht es Tools wie Editoren, private Importnamen nicht als Teil der Autovervollständigung vorzuschlagen.

Diese PEP ist absichtlich nicht übermäßig streng, was in den vorgeschlagenen Metadaten aufgeführt (oder nicht aufgeführt) werden darf. Es wäre nahezu unmöglich, Build-Backends zu veranlassen, zu überprüfen, ob ein Projekt eine Spezifikation genau befolgt, die irgendwie streng ist, was aufgeführt werden kann, aufgrund der Flexibilität des Python-Importsystems. Daher verlangt diese PEP nur, dass gültige Importnamen verwendet werden und dass Projekte nicht lügen (und es wird anerkannt, dass letztere Anforderung nicht programmgesteuert validiert werden kann). Projekte müssen jedoch alle Ebenen der von ihnen aufgeführten Namen berücksichtigen (z. B. kann man nicht a.b.c auflisten und nicht a und a.b berücksichtigen).

Es gab verschiedene andere Versuche, dieses Problem zu lösen, aber sie alle beinhalten Kompromisse. Man könnte zum Beispiel jedes Wheel für jede Projektveröffentlichung herunterladen und nachsehen, welche Dateien über das Binary Distribution Format bereitgestellt werden, aber das ist viel CPU und Bandbreite für etwas, das statische Informationen sind (obwohl Tricks verwendet werden können, um die Datenanfragen zu reduzieren, wie z. B. die Verwendung von HTTP-Bereichsanfragen, um nur die Inhaltsverzeichnisse der Zip-Datei zu lesen). Diese Art der Berechnung wird auch derzeit von jedem unabhängig wiederholt, anstatt die Metadaten von einem zentralen Indexserver wie PyPI hosten zu lassen. Sie funktioniert auch nicht für sdists, da die Struktur des Wheels noch nicht bekannt ist und somit die Struktur des installierten Codes nicht abgeleitet werden kann. Außerdem sind diese Lösungen nicht unbedingt genau, da sie auf Inferenz basieren und nicht explizit von den Projektbesitzern bereitgestellt werden. All diese Genauigkeitsprobleme betreffen auch die Hosterstellung von Informationen durch einen Index, um die Berechnungskosten für deren Erfassung zu vermeiden.

Spezifikation

Da diese PEP ein neues Feld für die Kernmetadaten einführt, wird die neueste Kernmetadatenversion auf 2.5 angehoben.

Die Felder Import-Name und Import-Namespace sind Felder mit „mehreren Verwendungen“. Jeder Eintrag beider Felder MUSS ein gültiger Importname sein oder im Fall von Import-Name leer sein. Alle angegebenen Namen MÜSSEN importierbar sein, wenn das Projekt auf *einer* Plattform für dieselbe Version des Projekts installiert ist (z. B. MÜSSEN die Metadaten über alle sdists und Wheels für eine Projektveröffentlichung konsistent sein). Dies impliziert, dass die Informationen nicht spezifisch für das Distributionsartefakt sind, in dem sie gefunden werden, sondern für die Release-Version, zu der das Distributionsartefakt gehört.

Ein Importname KANN von einem Semikolon und dem Begriff „private“ gefolgt werden (z. B. ; private). Dies signalisiert Tools, dass der Importname nicht Teil der öffentlichen API für das Projekt ist. Beliebige Leerzeichen um das ; sind zulässig.

Import-Name listet Importnamen auf, die ein Projekt nach der Installation *ausschließlich* bereitstellen würde (d. h., wenn zwei Projekte mit denselben in Import-Name aufgeführten Importnamen installiert würden, würde eines der Projekte den Namen für das andere verdecken). Import-Namespace listet Importnamen auf, die nach der Installation vom Projekt bereitgestellt würden, aber nicht ausschließlich (d. h., wenn Projekte denselben Importnamen in Import-Namespace auflisten und zusammen installiert werden, würden diese gemeinsamen Namen nicht verdeckt werden).

Die pyproject.toml-Spezifikation erhält einen Schlüssel import-names. Es handelt sich um ein Array von Strings, das speichert, was in Import-Name geschrieben wird. Build-Backends KÖNNEN optional die Berechnung des Werts im Auftrag des Benutzers unterstützen, wenn der Benutzer den Schlüssel in project.dynamic deklariert. Dasselbe gilt für import-namespaces für Import-Namespace.

Projekte SOLLTEN alle kürzesten Importnamen auflisten, die exklusiv von einem Projekt bereitgestellt werden und die alle Importnamenszenarien abdecken würden. Wenn einer der kürzesten Namen ein Punkt-getrennter Name ist, sollten alle dazwischenliegenden Namen von diesem Namen bis zum Top-Level-Namen entsprechend in Import-Namespace und/oder Import-Name aufgeführt werden. Zum Beispiel würde ein Projekt, das ein einzelnes Paket namens spam mit mehreren Untermodulen ist, nur project.import-names = ["spam"] auflisten. Ein Projekt, das spam.bacon.eggs auflistet, müsste auch spam und spam.bacon entsprechend in import-names und import-namespaces berücksichtigen. Das Auflisten aller Namen dient als Überprüfung, dass die Absicht der Importnamen wie erwartet ist. Ebenso SOLLTEN Projekte alle Importnamen, öffentlich oder privat, unter Verwendung des Modifikators ; private entsprechend auflisten.

Wenn ein Projekt denselben Namen sowohl in Import-Name als auch in Import-Namespace auflistet, MÜSSEN Tools einen Fehler aufgrund von Mehrdeutigkeit auslösen; dies gilt auch für import-names und import-namespaces.

Tools SOLLTEN einen Fehler auslösen, wenn zwei Projekte, die von einem Tool installiert werden sollen, Namen auflisten, die sich in den Import-Name-Einträgen des jeweils anderen überschneiden (d. h. in derselben Befehls-/Aktionsequenz installiert werden). Dies soll verhindern, dass Projekte unerwartet den Code eines anderen Projekts verdecken. Dasselbe gilt, wenn ein Projekt einen Eintrag in Import-Name hat, der sich mit den Import-Namespace-Einträgen eines anderen Projekts überschneidet. Dies gilt nicht für überschneidende Import-Namespace-Einträge, da dies der Zweck von Namespace-Paketen ist. Tools KÖNNEN eine Warnung ausgeben oder einen Fehler auslösen, wenn ein Projekt in eine bereits vorhandene Umgebung installiert wird, in der es eine Importnamen-Überschneidung mit einem bereits installierten Projekt gibt. Dies ist ein „MAY“ und kein „SHOULD“, da einige Benutzer Importnamen absichtlich überschreiben, wenn die Installation in mehreren Schritten erfolgt (z. B. durch die Verwendung verschiedener Installer in derselben Umgebung).

Projekte KÖNNEN import-names als leeres Array festlegen und import-namespaces überhaupt nicht in einer pyproject.toml-Datei festlegen (z. B. import-names = []). Um dem Rechnung zu tragen, KÖNNEN Projekte ein leeres Feld Import-Name in ihren Metadaten haben. Dies repräsentiert ein Projekt OHNE Importnamen, weder öffentlich noch privat (d. h. es gibt keine Python-Module jeglicher Art in der Distributionsdatei).

Da Projekte möglicherweise keine Import-Name-Metadaten haben (entweder weil das Projekt eine ältere Metadatenversion verwendet oder weil es keine angegeben hat), haben Tools keine Informationen darüber, welche Namen das Projekt bereitstellt. In der Praxis stimmt jedoch der Großteil der Projekte mit dem Namen überein, der auch dem Importnamen entsprechen würde. Daher ist es eine vernünftige Annahme, dass ein Projektname, der auf eine bestimmte Weise in einen Importnamen normalisiert wird (z. B. packaging.utils.canonicalize_name(name, validate=True).replace("-", "_")), verwendet werden kann, wenn eine Antwort benötigt wird.

Projekte KÖNNEN import-names oder import-namespaces – sowie Import-Name oder Import-Namespace, beziehungsweise – auf einen Importnamen setzen, der dem (normalisierten oder nicht normalisierten) Projektnamen entspricht, um explizit zu deklarieren, dass der Projektname auch der Importname ist.

Beispiele

Für scikit-learn 1.7.0

[project]
import-names = ["sklearn"]

Für pytest 8.3.5 wären 3 erwartete Einträge zu erwarten

[project]
# The pytest docs list code out of all of these modules, so it isn't
# obvious whether they would mark any as private.
import-names = ["_pytest", "py", "pytest"]

Für azure-mgmt-search 9.1.0 sollten es zwei Namespace-Einträge und ein Namenseintrag für azure.mgmt.search sein.

[project]
import-names = ["azure.mgmt.search"]
import-namespaces = ["azure", "azure.mgmt"]

Abwärtskompatibilität

Da dies ein neues Feld für die Kernmetadaten und eine neue Kernmetadatenversion ist, sollten keine Kompatibilitätsprobleme nach hinten bestehen.

Sicherheitsimplikationen

Tools sollten die Metadaten als potenziell ungenau behandeln. Daher sollten alle Entscheidungen, die auf den bereitgestellten Metadaten basieren, als auf irgendeine Weise bösartig angesehen werden.

Wie man das lehrt

Projektbesitzer sollten darüber informiert werden, dass sie nun aufzeichnen können, welche Namen ihre Projekte für den Import bereitstellen. Wenn der Projektname mit dem Modul- oder Paketnamen übereinstimmt, den ihr Projekt bereitstellt, müssen sie nichts tun. Wenn es jedoch einen Unterschied gibt, sollten sie alle von ihrem Projekt bereitgestellten Importnamen unter Verwendung der kürzestmöglichen Namen aufzeichnen. Wenn einer der Namen implizite Namespaces sind, kommen diese in project.import-namespaces in pyproject.toml, andernfalls kommt der Name in project.import-names.

Benutzer von Projekten müssen diese neuen Metadaten nicht unbedingt kennen. Obwohl sie möglicherweise über Tools damit konfrontiert werden, sind die Details, woher die Daten stammen, nicht entscheidend. Es ist möglich, dass sie darauf stoßen, wenn ein Indexserver sie bereitstellt (z. B. die Werte aus Import-Name auflistet und angibt, ob die Dateistruktur die Behauptungen der Metadaten unterstützt), aber das würde immer noch keine Kenntnis der technischen Details dieser PEP durch die Benutzer erfordern.

Referenzimplementierung

https://github.com/brettcannon/packaging/tree/pep-794 ist ein Branch zur Aktualisierung von „packaging“, um diese PEP zu unterstützen.

Abgelehnte Ideen

Den Wert für Import-Namespace ableiten

Eine frühere Version dieser PEP leitete ab, was die Werte für Import-Namespace basierend auf Punkt-getrennten Namen in Import-Name wären. Es wurde entschieden, dass es besser wäre, explizit zu sein, nicht nur um Fehler durch versehentliches Auflisten von etwas zu vermeiden, das als impliziter Namespace interpretiert würde, sondern auch, um die Daten selbsterklärender zu machen.

Verlangen, dass Namen, die in Import-Namespace aufgeführt sind, niemals von einem Namen in Import-Name enthalten sind

Die Funktionsweise des Python-Importsystems bedeutet standardmäßig, dass ein Importname keinen Namespace enthalten kann. Das Python-Importsystem ist jedoch flexibel genug, dass Benutzercode dies ermöglichen könnte. Daher die Anforderung, dass Tools einen Fehler auslösen, wenn ein Importname einen Namespace-Namen enthält – import-names = ["spam"] und import-namespaces = ["spam.bacon"] – wurde entfernt.

Das Feld Provides neu zweckentfremden

Das Feld Provides, das in der Metadatenversion 1.1 eingeführt und in 1.2 als veraltet markiert wurde, sollte ähnliche Informationen liefern, jedoch für *alle* von einem Projekt bereitgestellten Namen anstatt für die Unterscheidung von Namespaces, wie diese PEP vorschlägt. Basierend auf diesem Unterschied und der Tatsache, dass Provides veraltet ist und daher von vorhandenem Code ignoriert werden könnte, wurde die Entscheidung getroffen, ein neues Feld zu verwenden.

Das Feld Namespace benennen

Obwohl der Begriff „Namespace“ aus Importsicht technisch korrekt ist, könnte er mit impliziten Namespace-Paketen verwechselt werden.

Die RECORD-Datei bereitstellen

Während Diskussionen über eine Vor-PEP-Version dieser PEP wurde vorgeschlagen, die RECORD-Datei aus Wheels von Indexservern anstelle dieser neuen Metadaten bereitzustellen. Dies hätte den Vorteil, dass es sofort implementiert werden könnte. Um jedoch die gleichen Informationen bereitzustellen, wäre eine Inferenz basierend auf der Dateistruktur dessen, was von dem Wheel installiert würde, notwendig. Das könnte zu ungenauen Informationen führen. Außerdem unterstützt es keine sdists.

Am Ende wurde eine Abstimmung durchgeführt, und der Ansatz, den diese PEP verfolgt, setzte sich durch.

Präskriptiver sein, was Projekte angeben

Eine frühere Version dieser PEP war viel strenger, was in Import-Name eingefügt werden konnte. Dies beinhaltete die Umwandlung einiger „SHOULD“-Richtlinien in „MUST“-Anforderungen und die Spezifikation, wie die Berechnung dessen, was ein Projekt „besitzt“, erfolgte. Letztendlich wurde entschieden, dass dies zu restriktiv war und risikobehaftet, falsch implementiert zu werden oder die Spezifikation unerwartet zu streng zu machen.

Da die Metadaten nie als erschöpfend angesehen wurden, da sie nicht verifiziert werden können, wurde stattdessen die lockerere Spezifikation gewählt, die derzeit in dieser PEP enthalten ist.

Offene Fragen

N/A

Danksagungen

Vielen Dank an HeeJae Chang dafür, dass er ~~sich über~~ regelmäßig über die Nützlichkeit dieser Metadaten beschwert hat. Danke an Josh Cannon (keine Verwandtschaft) für die Überprüfung von Entwürfen dieser PEP und für Feedback. Ebenso Dank an alle, die an einer früheren Diskussion zu diesem Thema teilgenommen haben.


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

Zuletzt geändert: 2025-09-05 19:53:27 GMT