Skip to content

Commit 3cb25e3

Browse files
authored
PEP 794: Import name metadata (#4448)
1 parent 69f421d commit 3cb25e3

File tree

1 file changed

+259
-0
lines changed

1 file changed

+259
-0
lines changed

peps/pep-0794.rst

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
PEP: 794
2+
Title: Import Name Metadata
3+
Author: Brett Cannon <brett@python.org>
4+
Discussions-To: Pending
5+
Status: Draft
6+
Type: Standards Track
7+
Topic: Packaging
8+
Created: 05-Jun-2025
9+
Post-History: `02-May-2025 <https://discuss.python.org/t/90506>`__
10+
11+
12+
Abstract
13+
========
14+
15+
This PEP proposes extending the core metadata specification for Python
16+
packaging to include a new, repeatable field named ``Import-Name`` to record
17+
the import names that a project owns once installed. A new key named
18+
``import-names`` will be added to the ``[project]`` table in
19+
``pyproject.toml``. This also leads to the introduction of core metadata
20+
version 2.5.
21+
22+
23+
Motivation
24+
==========
25+
26+
In Python packaging there is no requirement that a project name match the
27+
name(s) that you can import for that project. As such, there is no clean,
28+
easy, accurate way to go from import name to project name and vice-versa.
29+
This can make it difficult for tools that try to help people in discovering
30+
the right project to install when they know the import name or knowing what
31+
import names a project will provide once installed.
32+
33+
As an example, a code editor may detect a user has an unsatisfied import in a
34+
selected virtual environment. But with no way to reliably gather the import
35+
names that various projects provide, the code editor cannot accurately
36+
provide a user with a list of potential projects to install to satisfy that
37+
import requirement (e.g. it is not obvious that ``import PIL`` very likely
38+
implies the user wants the `Pillow project
39+
<https://pypi.org/project/pillow/>`__ installed). This also applies to when a
40+
user vaguely remembers the project name but does not remember the import
41+
name(s) and would have their memory jogged when seeing a list of import names
42+
a package provides. Finally, tools would be able to notify users what import
43+
names will become available once they install a project.
44+
45+
It may also help with spam detection. If a project specifies the same import
46+
names as a very popular project it can act as a signal to take a closer look
47+
at the validity of the less popular project. A project found to be lying
48+
about what import names it provides would be another signal.
49+
50+
51+
Rationale
52+
=========
53+
54+
This PEP proposes extending the packaging :ref:`packaging:core-metadata` so
55+
that project owners can specify the highest-level import names that a project
56+
provides and owns if installed.
57+
58+
By keeping the information to the import names a project would own (i.e. not
59+
implicit namespace packages but modules, regular packages, submodules, and
60+
subpackages in an explicit namespace package), it makes it clear which
61+
project maps directly to what import name once the project is installed.
62+
63+
By keeping it to the highest-level name that's owned, it keeps the data small
64+
and allows for inferring implicit namespace packages that a project
65+
contributes to. This will hopefully encourage use when appropriate by not
66+
being a burden to provide appropriate information.
67+
68+
Putting this metadata in the core metadata means the data is (potentially)
69+
served independently of any sdist or wheel by an index server. That negates
70+
needing to come up with another way to expose the metadata to tools to avoid
71+
having to download an entire e.g. wheel.
72+
73+
Various other attempts have been made to solve this, but they all have to
74+
make various trade-offs. For instance, one could download every wheel for
75+
every project release and look at what files are provided via the
76+
:ref:`packaging:binary-distribution-format`, but that's a lot of CPU and
77+
bandwidth for something that is static information (although tricks can be
78+
used to lessen the data requests such as using HTTP range requests to only
79+
read the table of contents of the zip file). This sort of calculation is also
80+
currently repeated by everyone independently instead of having the metadata
81+
hosted by a central index server like PyPI. It also doesn't work for sdists as
82+
the structure of the wheel isn't known yet, and so inferring the structure of
83+
the code installed isn't known yet. As well, these solutions are not
84+
necessarily accurate as it is based on inference instead of being explicitly
85+
provided by the project owners.
86+
87+
88+
Specification
89+
=============
90+
91+
Because this PEP introduces a new field to the core metadata, it bumps the
92+
latest core metadata version to 2.5.
93+
94+
The ``Import-Name`` field is a "multiple uses" field. Each entry of
95+
``Import-Name`` represents an importable name that the project provides. The
96+
names provided MUST be importable via *some* artifact the project provides
97+
for that version, i.e. the metadata MUST be consistent across all sdists and
98+
wheels for a project release to avoid having to read every file to find
99+
variances. It also avoids having to declare this field as dynamic in an
100+
sdist due to the import names varying across wheels. This does imply that the
101+
information isn't specific to the distribution artifact it is found in, but
102+
for the release version the distribution artifact belongs to.
103+
104+
The names provided MUST be one of the following:
105+
106+
- Highest-level, regular packages
107+
- Top-level modules
108+
- The submodules and regular subpackages within implicit namespace packages
109+
110+
provided by the project. This makes the vast majority of projects only
111+
needing a single ``Import-Name`` entry which represents the top-level,
112+
regular package the project provides. But it also allows for implicit
113+
namespace packages to be able to differentiate among themselves (e.g., it
114+
avoids having all projects contributing to the ``azure`` namespace via an
115+
implicit namespace package all having ``azure`` as their entry for
116+
``Import-Name``, but instead a more accurate entry like
117+
``azure.mgmt.search``)
118+
119+
If a project chooses not to provide any ``Import-Name`` entries, tools MAY
120+
assume the import name matches the project name.
121+
122+
Project owners MUST specify accurate information when provided and SHOULD be
123+
exhaustive in what they provide. Project owners SHOULD NOT filter out names
124+
that they consider private. This is because even "private" names can be
125+
imported by anyone and can "take up space" in the namespace of the
126+
environment. Tools consuming the metadata SHOULD consider the information
127+
provided in ``Import-Name`` as accurate, but not exhaustive.
128+
129+
The :ref:`declaring-project-metadata` will gain an ``import-names`` key. It
130+
will be an array of strings that stores what will be written out to
131+
``Import-Name``. Build back-ends MAY support dynamically calculating the
132+
value on the user's behalf if desired, if the user declares the key to be
133+
dynamic.
134+
135+
136+
Examples
137+
--------
138+
139+
`In httpx 0.28.1
140+
<https://pypi-browser.org/package/httpx/httpx-0.28.1-py3-none-any.whl>`__
141+
there would be only a single entry for the ``httpx`` package as it's a
142+
regular package and there are no other regular packages or modules at the top
143+
of the project.
144+
145+
`In pytest 8.3.5
146+
<https://pypi-browser.org/package/pytest/pytest-8.3.5-py3-none-any.whl>`__
147+
there would be 3 entries:
148+
149+
1. ``_pytest`` (a top-level, regular package)
150+
2. ``py`` (a top-level module)
151+
3. ``pytest`` (a top-level, regular package)
152+
153+
In `azure-mgmt-search 9.1.0
154+
<https://pypi-browser.org/package/azure-mgmt-search/azure_mgmt_search-9.1.0-py3-none-any.whl>`__,
155+
there would be a single entry for ``azure.mgmt.search`` as ``azure`` and
156+
``azure.mgmt`` are implicit namespace packages.
157+
158+
159+
Backwards Compatibility
160+
=======================
161+
162+
As this is a new field for the core metadata and a new core metadata version,
163+
there should be no backwards compatibility concerns.
164+
165+
166+
Security Implications
167+
=====================
168+
169+
Tools should treat the metadata as potentially inaccurate. As such, any
170+
decisions made based on the provided metadata should be assumed to be
171+
malicious in some way.
172+
173+
174+
How to Teach This
175+
=================
176+
177+
Project owners should be taught that they can now record what namespaces
178+
their project provides. They should be told that if their project has a
179+
non-obvious namespace from the file structure of the project that they should
180+
specify the appropriate information. They should have it explained to them
181+
that they should use the shortest name possible that appropriately explains
182+
what the project provides (i.e. what the specification requires to be
183+
recorded).
184+
185+
Users of projects don't necessarily need to know about this new metadata.
186+
While they may be exposed to it via tooling, the details of where that data
187+
came from isn't critical. It's possible they may come across it if an index
188+
server exposed it (e.g., listed the values from ``Import-Name`` and marked
189+
whether the file structure backed up the claims the metadata makes), but that
190+
still wouldn't require users to know the technical details of this PEP.
191+
192+
193+
Reference Implementation
194+
========================
195+
196+
https://github.com/brettcannon/packaging/tree/pep-794 is a branch to update
197+
'packaging' to support this PEP.
198+
199+
200+
Rejected Ideas
201+
==============
202+
203+
Re-purpose the ``Provides`` field
204+
----------------------------------
205+
206+
Introduced in metadata version 1.1 and deprecated in 1.2, the ``Provides``
207+
field was meant to provide similar information, except for **all** names
208+
provided by a project instead of the distinguishing namespaces as this PEP
209+
proposes. Based on that difference and the fact that ``Provides`` is
210+
deprecated and thus could be ignored by preexisting code, the decision was
211+
made to go with a new field.
212+
213+
214+
Name the field ``Namespace``
215+
----------------------------
216+
217+
While the term "namespace" name is technically accurate from an import
218+
perspective, it could be confused with implicit namespace packages.
219+
220+
221+
Serving the ``RECORD`` file
222+
---------------------------
223+
224+
During `discussions about a pre-PEP version
225+
<https://discuss.python.org/t/90506/>`__ of this
226+
PEP, it was suggested that the ``RECORD`` file from wheels be served from
227+
index servers instead of this new metadata. That would have the benefit of
228+
being implementable immediately. But in order to provide the equivalent
229+
information there would be necessary inference based on the file structure of
230+
what would be installed by the wheel. That could lead to inaccurate
231+
information. It also doesn't support sdists.
232+
233+
In the end a `poll
234+
<https://discuss.python.org/t/90506/46>`__ was
235+
held and the approach this PEP takes won out.
236+
237+
238+
Open Issues
239+
===========
240+
241+
N/A
242+
243+
244+
Acknowledgments
245+
===============
246+
247+
Thanks to HeeJae Chang for ~~complaining about~~ bringing up regularly the
248+
usefulness that this metadata would provide. Thanks to Josh Cannon (no
249+
relation) for reviewing drafts of this PEP and providing feedback. Also,
250+
thanks to everyone who participated in a `previous discussion
251+
<https://discuss.python.org/t/29494>`__
252+
on this topic.
253+
254+
255+
Copyright
256+
=========
257+
258+
This document is placed in the public domain or under the
259+
CC0-1.0-Universal license, whichever is more permissive.

0 commit comments

Comments
 (0)