Skip to content

Commit 8099249

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

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+
module spec. If *parent* is *None*, :meth:`PathEntryFinder.discover` will
282+
search for 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+
module spec. If *parent* is *None*, :meth:`PathEntryFinder.discover` will
324+
search for 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
@@ -1323,6 +1323,21 @@ def find_spec(cls, fullname, path=None, target=None):
13231323
else:
13241324
return spec
13251325

1326+
@classmethod
1327+
def discover(cls, parent=None):
1328+
if parent is None:
1329+
path = sys.path
1330+
else:
1331+
path = parent.submodule_search_locations
1332+
1333+
for entry in path:
1334+
if not isinstance(entry, str):
1335+
continue
1336+
if (finder := cls._path_importer_cache(entry)) is None:
1337+
continue
1338+
if discover := getattr(finder, 'discover', None):
1339+
yield from discover(parent)
1340+
13261341
@staticmethod
13271342
def find_distributions(*args, **kwargs):
13281343
"""
@@ -1472,6 +1487,27 @@ def path_hook_for_FileFinder(path):
14721487

14731488
return path_hook_for_FileFinder
14741489

1490+
def _find_children(self):
1491+
for entry in _os.scandir(self.path):
1492+
if entry.name == _PYCACHE:
1493+
continue
1494+
# packages
1495+
if entry.is_dir() and '.' not in entry.name:
1496+
yield entry.name
1497+
# files
1498+
if entry.is_file():
1499+
yield from [
1500+
entry.name.removesuffix(suffix)
1501+
for suffix, _ in self._loaders
1502+
if entry.name.endswith(suffix)
1503+
]
1504+
1505+
def discover(self, parent=None):
1506+
module_prefix = f'{parent.name}.' if parent else ''
1507+
for child_name in self._find_children():
1508+
if spec := self.find_spec(module_prefix + child_name):
1509+
yield spec
1510+
14751511
def __repr__(self):
14761512
return f'FileFinder({self.path!r})'
14771513

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)