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