Skip to content

Commit 35d5068

Browse files
authored
bpo-43428: Improve documentation for importlib.metadata changes. (GH-24858)
* bpo-43428: Sync with importlib_metadata 3.7.3 (16ac3a95) * Add 'versionadded' for importlib.metadata.packages_distributions * Add section in what's new for Python 3.10 highlighting most salient changes and relevant backport.
1 parent 5e29021 commit 35d5068

File tree

3 files changed

+73
-3
lines changed

3 files changed

+73
-3
lines changed

Doc/library/importlib.metadata.rst

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,43 @@ Entry points are represented by ``EntryPoint`` instances;
7979
each ``EntryPoint`` has a ``.name``, ``.group``, and ``.value`` attributes and
8080
a ``.load()`` method to resolve the value. There are also ``.module``,
8181
``.attr``, and ``.extras`` attributes for getting the components of the
82-
``.value`` attribute::
82+
``.value`` attribute.
83+
84+
Query all entry points::
8385

8486
>>> eps = entry_points() # doctest: +SKIP
87+
88+
The ``entry_points()`` function returns an ``EntryPoints`` object,
89+
a sequence of all ``EntryPoint`` objects with ``names`` and ``groups``
90+
attributes for convenience::
91+
8592
>>> sorted(eps.groups) # doctest: +SKIP
8693
['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']
94+
95+
``EntryPoints`` has a ``select`` method to select entry points
96+
matching specific properties. Select entry points in the
97+
``console_scripts`` group::
98+
8799
>>> scripts = eps.select(group='console_scripts') # doctest: +SKIP
100+
101+
Equivalently, since ``entry_points`` passes keyword arguments
102+
through to select::
103+
104+
>>> scripts = entry_points(group='console_scripts') # doctest: +SKIP
105+
106+
Pick out a specific script named "wheel" (found in the wheel project)::
107+
88108
>>> 'wheel' in scripts.names # doctest: +SKIP
89109
True
90110
>>> wheel = scripts['wheel'] # doctest: +SKIP
111+
112+
Equivalently, query for that entry point during selection::
113+
114+
>>> (wheel,) = entry_points(group='console_scripts', name='wheel') # doctest: +SKIP
115+
>>> (wheel,) = entry_points().select(group='console_scripts', name='wheel') # doctest: +SKIP
116+
117+
Inspect the resolved entry point::
118+
91119
>>> wheel # doctest: +SKIP
92120
EntryPoint(name='wheel', value='wheel.cli:main', group='console_scripts')
93121
>>> wheel.module # doctest: +SKIP
@@ -106,6 +134,17 @@ group. Read `the setuptools docs
106134
<https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins>`_
107135
for more information on entry points, their definition, and usage.
108136

137+
*Compatibility Note*
138+
139+
The "selectable" entry points were introduced in ``importlib_metadata``
140+
3.6 and Python 3.10. Prior to those changes, ``entry_points`` accepted
141+
no parameters and always returned a dictionary of entry points, keyed
142+
by group. For compatibility, if no parameters are passed to entry_points,
143+
a ``SelectableGroups`` object is returned, implementing that dict
144+
interface. In the future, calling ``entry_points`` with no parameters
145+
will return an ``EntryPoints`` object. Users should rely on the selection
146+
interface to retrieve entry points by group.
147+
109148

110149
.. _metadata:
111150

@@ -199,6 +238,8 @@ Python packages or modules::
199238
>>> packages_distributions()
200239
{'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...}
201240

241+
.. versionadded:: 3.10
242+
202243

203244
Distributions
204245
=============

Doc/whatsnew/3.10.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,19 @@ Added the *root_dir* and *dir_fd* parameters in :func:`~glob.glob` and
690690
:func:`~glob.iglob` which allow to specify the root directory for searching.
691691
(Contributed by Serhiy Storchaka in :issue:`38144`.)
692692
693+
importlib.metadata
694+
------------------
695+
696+
Feature parity with ``importlib_metadata`` 3.7.
697+
698+
:func:`importlib.metadata.entry_points` now provides a nicer experience
699+
for selecting entry points by group and name through a new
700+
:class:`importlib.metadata.EntryPoints` class.
701+
702+
Added :func:`importlib.metadata.packages_distributions` for resolving
703+
top-level Python modules and packages to their
704+
:class:`importlib.metadata.Distribution`.
705+
693706
inspect
694707
-------
695708

Lib/importlib/metadata.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44
import csv
55
import sys
66
import email
7-
import inspect
87
import pathlib
98
import zipfile
109
import operator
1110
import warnings
1211
import functools
1312
import itertools
1413
import posixpath
15-
import collections.abc
14+
import collections
1615

1716
from ._itertools import unique_everseen
1817

@@ -33,6 +32,7 @@
3332
'entry_points',
3433
'files',
3534
'metadata',
35+
'packages_distributions',
3636
'requires',
3737
'version',
3838
]
@@ -158,21 +158,33 @@ class EntryPoints(tuple):
158158
__slots__ = ()
159159

160160
def __getitem__(self, name): # -> EntryPoint:
161+
"""
162+
Get the EntryPoint in self matching name.
163+
"""
161164
try:
162165
return next(iter(self.select(name=name)))
163166
except StopIteration:
164167
raise KeyError(name)
165168

166169
def select(self, **params):
170+
"""
171+
Select entry points from self that match the
172+
given parameters (typically group and/or name).
173+
"""
167174
return EntryPoints(ep for ep in self if ep.matches(**params))
168175

169176
@property
170177
def names(self):
178+
"""
179+
Return the set of all names of all entry points.
180+
"""
171181
return set(ep.name for ep in self)
172182

173183
@property
174184
def groups(self):
175185
"""
186+
Return the set of all groups of all entry points.
187+
176188
For coverage while SelectableGroups is present.
177189
>>> EntryPoints().groups
178190
set()
@@ -185,6 +197,9 @@ def _from_text_for(cls, text, dist):
185197

186198

187199
def flake8_bypass(func):
200+
# defer inspect import as performance optimization.
201+
import inspect
202+
188203
is_flake8 = any('flake8' in str(frame.filename) for frame in inspect.stack()[:5])
189204
return func if not is_flake8 else lambda: None
190205

@@ -813,6 +828,7 @@ def packages_distributions() -> Mapping[str, List[str]]:
813828
Return a mapping of top-level packages to their
814829
distributions.
815830
831+
>>> import collections.abc
816832
>>> pkgs = packages_distributions()
817833
>>> all(isinstance(dist, collections.abc.Sequence) for dist in pkgs.values())
818834
True

0 commit comments

Comments
 (0)