@@ -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
0 commit comments