def walk_packages(inspect: ModuleInspect, packages: List[str], verbose: bool = False) -> Iterator[str]: """Iterates through all packages and sub-packages in the given list. This uses runtime imports (in another process) to find both Python and C modules. For Python packages we simply pass the __path__ attribute to pkgutil.walk_packages() to get the content of the package (all subpackages and modules). However, packages in C extensions do not have this attribute, so we have to roll out our own logic: recursively find all modules imported in the package that have matching names. """ for package_name in packages: if package_name in NOT_IMPORTABLE_MODULES: print('%s: Skipped (blacklisted)' % package_name) continue if verbose: print('Trying to import %r for runtime introspection' % package_name) try: prop = inspect.get_package_properties(package_name) except InspectError: report_missing(package_name) continue yield prop.name if prop.is_c_module: # Recursively iterate through the subpackages for submodule in walk_packages(inspect, prop.subpackages, verbose): yield submodule else: for submodule in prop.subpackages: yield submodule
def find_module_path_and_all_py3( inspect: ModuleInspect, module: str, verbose: bool) -> Optional[Tuple[Optional[str], Optional[List[str]]]]: """Find module and determine __all__ for a Python 3 module. Return None if the module is a C module. Return (module_path, __all__) if it is a Python module. Raise CantImport if import failed. """ if module in NOT_IMPORTABLE_MODULES: raise CantImport(module, '') # TODO: Support custom interpreters. if verbose: print('Trying to import %r for runtime introspection' % module) try: mod = inspect.get_package_properties(module) except InspectError as e: # Fall back to finding the module using sys.path. path = find_module_path_using_sys_path(module, sys.path) if path is None: raise CantImport(module, str(e)) from e return path, None if mod.is_c_module: return None return mod.file, mod.all