Skip to content

Commit 29215a0

Browse files
committed
gh-139899: Introduce MetaPathFinder.discover and PathEntryFinder.discover
Signed-off-by: Filipe Laíns <lains@riseup.net>
1 parent 5c942f1 commit 29215a0

File tree

4 files changed

+75
-0
lines changed

4 files changed

+75
-0
lines changed

Doc/library/importlib.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,16 @@ ABC hierarchy::
275275
.. versionchanged:: 3.4
276276
Returns ``None`` when called instead of :data:`NotImplemented`.
277277

278+
.. method:: discover(parent=None)
279+
280+
An optional method which searches for possible specs with given *parent*.
281+
If *parent* is *None*, :meth:`MetaPathFinder.discover` will search for
282+
top-level modules.
283+
284+
Returns an iterable of possible specs.
285+
286+
.. versionadded:: next
287+
278288

279289
.. class:: PathEntryFinder
280290

@@ -307,6 +317,16 @@ ABC hierarchy::
307317
:meth:`importlib.machinery.PathFinder.invalidate_caches`
308318
when invalidating the caches of all cached finders.
309319

320+
.. method:: discover(parent=None)
321+
322+
An optional method which searches for possible specs with given *parent*.
323+
If *parent* is *None*, :meth:`PathEntryFinder.discover` will search for
324+
top-level modules.
325+
326+
Returns an iterable of possible specs.
327+
328+
.. versionadded:: next
329+
310330

311331
.. class:: Loader
312332

Lib/importlib/_bootstrap_external.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,21 @@ def find_spec(cls, fullname, path=None, target=None):
13171317
else:
13181318
return spec
13191319

1320+
@classmethod
1321+
def discover(cls, parent=None):
1322+
if parent is None:
1323+
path = sys.path
1324+
else:
1325+
path = parent.__spec__.submodule_search_locations
1326+
1327+
for entry in path:
1328+
if not isinstance(entry, str):
1329+
continue
1330+
if (finder := cls._path_importer_cache(entry)) is None:
1331+
continue
1332+
if discover := getattr(finder, 'discover', None):
1333+
yield from discover(parent)
1334+
13201335
@staticmethod
13211336
def find_distributions(*args, **kwargs):
13221337
"""
@@ -1466,6 +1481,27 @@ def path_hook_for_FileFinder(path):
14661481

14671482
return path_hook_for_FileFinder
14681483

1484+
def _find_children(self):
1485+
for entry in _os.scandir(self.path):
1486+
if entry.name == _PYCACHE:
1487+
continue
1488+
# packages
1489+
if entry.is_dir() and '.' not in entry.name:
1490+
yield entry.name
1491+
# files
1492+
if entry.is_file():
1493+
yield from [
1494+
entry.name.removesuffix(suffix)
1495+
for suffix, _ in self._loaders
1496+
if entry.name.endswith(suffix)
1497+
]
1498+
1499+
def discover(self, parent=None):
1500+
module_prefix = f'{parent.__name__}.' if parent else ''
1501+
for child_name in self._find_children():
1502+
if spec := self.find_spec(module_prefix + child_name):
1503+
yield spec
1504+
14691505
def __repr__(self):
14701506
return f'FileFinder({self.path!r})'
14711507

Lib/importlib/abc.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ def invalidate_caches(self):
4545
This method is used by importlib.invalidate_caches().
4646
"""
4747

48+
def discover(self, parent=None):
49+
"""An optional method which searches for possible specs with given *parent*.
50+
If *parent* is *None*, MetaPathFinder.discover will search for top-level modules.
51+
52+
Returns an iterable of possible specs.
53+
"""
54+
return ()
55+
56+
4857
_register(MetaPathFinder, machinery.BuiltinImporter, machinery.FrozenImporter,
4958
machinery.PathFinder, machinery.WindowsRegistryFinder)
5059

@@ -58,6 +67,14 @@ def invalidate_caches(self):
5867
This method is used by PathFinder.invalidate_caches().
5968
"""
6069

70+
def discover(self, parent=None):
71+
"""An optional method which searches for possible specs with given *parent*.
72+
If *parent* is *None*, PathEntryFinder.discover will search for top-level modules.
73+
74+
Returns an iterable of possible specs.
75+
"""
76+
return ()
77+
6178
_register(PathEntryFinder, machinery.FileFinder)
6279

6380

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Introduced :meth:`MetaPathFinder.discover` and
2+
:meth:`PathEntryFinder.discover`.

0 commit comments

Comments
 (0)