Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 794 – Import Name Metadata

PEP 794 – Import Name Metadata

Author:
Brett Cannon <brett at python.org>
Discussions-To:
Discourse thread
Status:
Accepted
Type:
Standards Track
Topic:
Packaging
Created:
05-Jun-2025
Post-History:
02-May-2025,05-Jun-2025
Resolution:
05-Sep-2025

Table of Contents

Abstract

This PEP proposes extending the core metadata specification for Pythonpackaging to include two new, repeatable fields namedImport-Name andImport-Namespace to record the import names that a project provides onceinstalled. New keys namedimport-names andimport-namespaces will beadded to the[project] table inpyproject.toml for providing thevalues for the new core metadata fields. This also leads to the introduction ofcore metadata version 2.5.

Motivation

In Python packaging there is no requirement that a project name match thename(s) that you can import for that project. As such, there is no clean,easy, accurate way to go from import name to project name and vice versa.This can make it difficult for tools that try to help people in discoveringthe right project to install when they know the import name or knowing whatimport names a project will provide once installed.

As an example, a code editor may detect a user has an unsatisfied import in aselected virtual environment. But with no way to reliably know what importnames various projects provide, the code editor cannot accuratelyprovide a user with a list of potential projects to install to satisfy thatimport requirement (e.g. it is not obvious thatimportPIL very likelyimplies the user wants thePillow project installed). This also applies to when auser vaguely remembers the project name but does not remember the importname(s) and would have their memory jogged when seeing a list of import namesa package provides. Finally, tools would be able to notify users what importnames will become available once they install a project.

There is also no easy way to know whether installing two projects will conflictwith one another based on the import names they provide. For instance, if twodifferent projects have a_utils module, installing both projects will leadto a clash as one project’s_utils module would take precedence over theother’s, by overwriting the other project’s file; this issuehas beenseen in the wild.

It may also help with spam detection. If a project specifies the same importnames as a very popular project it can act as a signal to take a closer lookat the validity of the less popular project. A project found to be lyingabout what import names it provides would be another signal.

Rationale

This PEP proposes extending the packagingCore metadata specifications sothat project owners can specify the highest-level import names that a projectprovides if installed on some platform.

Putting this metadata in the core metadata means the data is (potentially)served by an index server, independent of any sdist or wheel. That negatesneeding to come up with a way to expose the metadata to tools to avoidhaving to download an entire e.g. wheel.

Having this metadata be the same across all release artifacts would allow forprojects to only have to check a single file’s core metadata to get allpossible import names instead of checking all the released files. This alsomeans one does not need to worry if a file is missing when reading the coremetadata or one can work solely from an sdist if the metadata is provided. Aswell, it simplifies havingproject.import-names andproject.import-namespaces keys inpyproject.toml by having it beconsistent for the entire project version and not unique per released file forthe same version.

A distribution file containing modules and packages can have any combination ofpublic and private APIs at the module/package level. Distribution files can alsocontain no modules or packages of any kind. Being able to distinguish betweenthe situations all have various tool uses that could be beneficial to users. Forinstance, knowing all import names regardless of whether they are public orprivate helps detect clashes at install time. But knowing what is explicitlypublic or private allows tools such as editors to not suggest private importnames as part of auto-complete.

This PEP is not overly strict on what to (not) list in the proposed metadata onpurpose. Having build back-ends verify that a project is accurately followinga specification that is somehow strict about what can be listed would be nearlyimpossible to get right due to how flexible Python’s import system is. As such,this PEP only requires that valid import names be used and that projects don’tlie (and it is acknowledged the latter requirement cannot be validatedprogrammatically). Projects do, though, need to account for all levels of thenames they list (e.g. you can’t lista.b.c and not account fora anda.b).

Various other attempts have been made to solve this, but they all have tomake trade-offs. For instance, one could download every wheel forevery project release and look at what files are provided via theBinary distribution format, but that’s a lot of CPU andbandwidth for something that is static information (although tricks can beused to lessen the data requests such as using HTTP range requests to onlyread the table of contents of the zip file). This sort of calculation is alsocurrently repeated by everyone independently instead of having the metadatahosted by a central index server like PyPI. It also doesn’t work for sdistsas the structure of the wheel isn’t known yet, and so inferring the structureof the code installed isn’t possible. As well, these solutions are notnecessarily accurate as they are based on inference instead of being explicitlyprovided by the project owners. All of these accuracy issues affect even havingan index host the information to avoid the compute costs of gathering it.

Specification

Because this PEP introduces a new field to the core metadata, it bumps thelatest core metadata version to 2.5.

TheImport-Name andImport-Namespace fields are “multiple uses” fields.Each entry of both fields MUST be a valid import name or can be empty in thecase ofImport-Name. Any names specified MUST be importable when the projectis installed onsome platform for the same version of the project (e.g. themetadata MUST be consistent across all sdists and wheels for a project release).This does imply that the information isn’t specific to the distribution artifactit is found in, but to the release version the distribution artifact belongs to.

An import name MAY be followed by a semicolon and the term “private” (e.g.;private). This signals to tools that the import name is not part of thepublic API for the project. Any number of spaces surrounding the; isallowed.

Import-Name lists import names which a project, when installed, wouldexclusively provide (i.e. if two projects were installed with the same importnames listed inImport-Name, then one of the projects would shadow thename for the other).Import-Namespace lists import names that, wheninstalled, would be provided by the project, but not exclusively (i.e.projects all listing the same import name inImport-Namespace beinginstalled together would not shadow those shared names).

Thepyproject.toml specification will gain animport-names key. Itwill be an array of strings that stores what will be written out toImport-Name. Build back-ends MAY support dynamically calculating thevalue on the user’s behalf if desired, if the user declares the key inproject.dynamic. The same applies toimport-namespaces forImport-Namespace.

Projects SHOULD list all the shortest import names that are exclusively providedby a project which would cover all import name scenarios. If any of the shortestnames are dotted names, all intervening names from that name to the top-levelname should also be listed appropriately inImport-Namespace and/orImport-Name. For instance, a project which is a single package namedspam with multiple submodules would only listproject.import-names=["spam"]. A project that listsspam.bacon.eggswould also need to account forspam andspam.bacon appropriately inimport-names andimport-namespaces. Listing all names acts as a checkthat the intent of the import names is as expected. As well, projects SHOULDlist all import names, public or private, using the;private modifieras appropriate.

If a project lists the same name in bothImport-Name andImport-Namespace, then tools MUST raise an error due to ambiguity; this alsoapplies toimport-names andimport-namespaces, respectively.

Tools SHOULD raise an error when two projects that are about to be installed bya tool list names that overlap in each other’sImport-Name entries (i.e.installed in the same command/action). This is to avoid projects unexpectedlyshadowing another project’s code. The same applies to when a project has anentry inImport-Name that overlaps with another project’sImport-Namespace entries. This does not apply to overlappingImport-Namespace entries as that’s the purpose of namespace packages. ToolsMAY warn or raise an error when installing a project into a preexistingenvironment where there is import name overlap with a project that is alreadyinstalled. This is a “MAY” and not a “SHOULD” due to some users purposefullyoverwriting import names when installation is done in multiple steps (e.g.using different installers with the same environment).

Projects MAY setimport-names an empty array and not setimport-namespaces at all in apyproject.toml file (e.g.import-names=[]). To match this, projects MAY have an emptyImport-Name field in their metadata. This represents a project with NOimport names, public or private (i.e. there are no Python modules of any kindin the distribution file).

Since projects MAY have noImport-Name metadata (either because the projectuses an older metadata version, or because it didn’t specify any), then toolshave no information about what names the project provides. However, in practicethe majority of projects have their project name match what their import namewould be. As such, it is a reasonable assumption to make that a project namethat is normalized in some way to an import name (e.g.packaging.utils.canonicalize_name(name,validate=True).replace("-","_"))can be used if some answer is needed.

Projects MAY setimport-names orimport-namespaces – as well asImport-Name orImport-Namespace, respectively – to an import name thatmatches the project name (normalized or not) to explicitly declare that theproject’s name is also the import name.

Examples

Forscikit-learn 1.7.0:

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

Forpytest 8.3.5there would be 3 expected entries:

[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"]

Forazure-mgmt-search 9.1.0,there should be two namespace entries and one name entry forazure.mgmt.search:

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

Backwards Compatibility

As this is a new field for the core metadata and a new core metadata version,there should be no backwards compatibility concerns.

Security Implications

Tools should treat the metadata as potentially inaccurate. As such, anydecisions made based on the provided metadata should be assumed to bemalicious in some way.

How to Teach This

Project owners should be taught that they can now record what names theirprojects provide for importing. If their project name matches the module orpackage name their project provides they don’t have to do anything. If there isa difference, though, they should record all the import names their projectprovides, using the shortest names possible. If any of the names are implicitnamespaces, those go intoproject.import-namespaces inpyproject.toml, otherwise the name goes intoproject.import-names.

Users of projects don’t necessarily need to know about this new metadata.While they may be exposed to it via tooling, the details of where that datacame from isn’t critical. It’s possible they may come across it if an indexserver exposes it (e.g., lists the values fromImport-Name and markswhether the file structure backs up the claims the metadata makes), but thatstill wouldn’t require users to know the technical details of this PEP.

Reference Implementation

https://github.com/brettcannon/packaging/tree/pep-794 is a branch to update‘packaging’ to support this PEP.

Rejected Ideas

Infer the value forImport-Namespace

A previous version of this PEP inferred what would have been the values forImport-Namespace based on dotted names inImport-Name. It was decidedthat it would be better to be explicit not only to avoid mistakes by accidentallylisting something that would be interpreted as an implicit namespace, but italso made the data more self-documenting.

Require that names listed inImport-Namespace never be contained by a name inImport-Name

The way Python’s import system works by default means that it isn’t possible tohave an import name contain a namespace. But Python’s import system is flexibleenough that user code could make that possible. As such, the requirement thattools error out if an import name contained a namespace name –import-names=["spam"] andimport-namespaces=["spam.bacon"] – wasremoved.

Re-purpose theProvides field

Introduced in metadata version 1.1 and deprecated in 1.2, theProvidesfield was meant to provide similar information, except forall namesprovided by a project instead of the distinguishing namespaces as this PEPproposes. Based on that difference and the fact thatProvides isdeprecated and thus could be ignored by preexisting code, the decision wasmade to go with a new field.

Name the fieldNamespace

While the term “namespace” is technically accurate from an importperspective, it could be confused with implicit namespace packages.

Serving theRECORD file

Duringdiscussions about a pre-PEP version of thisPEP, it was suggested that theRECORD file from wheels be served fromindex servers instead of this new metadata. That would have the benefit ofbeing implementable immediately. But in order to provide the equivalentinformation, inference would be necessary based on the file structure ofwhat would be installed by the wheel. That could lead to inaccurateinformation. It also doesn’t support sdists.

In the end apoll washeld and the approach this PEP takes won out.

Be more prescriptive in what projects specify

An earlier version of this PEP was much more strict in what could be put intoImport-Name. This included turning some “SHOULD” guidelines into “MUST”requirements and being specific about how to calculate what a project “owned”.In the end it was decided that was too restrictive and risked being implementedincorrectly or the spec being unexpectedly too strict.

Since the metadata was never expected to be exhaustive as it can’t be verifiedto be, the looser spec that is currently in this PEP was chosen instead.

Open Issues

N/A

Acknowledgments

Thanks to HeeJae Chang for ~~complaining about~~ regularly bringing up theusefulness that this metadata would provide. Thanks to Josh Cannon (norelation) for reviewing drafts of this PEP and providing feedback. Also,thanks to everyone who participated in aprevious discussionon this topic.

Copyright

This document is placed in the public domain or under theCC0-1.0-Universal license, whichever is more permissive.


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

Last modified:2025-09-05 19:53:27 GMT


[8]ページ先頭

©2009-2026 Movatter.jp