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
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 test_c_module(self) -> None: with ModuleInspect() as m: p = m.get_package_properties('_socket') assert p is not None assert p.name == '_socket' assert p.path is None assert p.is_c_module is True assert p.subpackages == []
def test_python_module(self) -> None: with ModuleInspect() as m: p = m.get_package_properties('inspect') assert p is not None assert p.name == 'inspect' assert p.file assert p.path is None assert p.is_c_module is False assert p.subpackages == []
def test_python_package(self) -> None: with ModuleInspect() as m: p = m.get_package_properties('unittest') assert p is not None assert p.name == 'unittest' assert p.file assert p.path assert p.is_c_module is False assert p.subpackages assert all(sub.startswith('unittest.') for sub in p.subpackages)
def test_walk_packages(self) -> None: with ModuleInspect() as m: assert_equal(set(walk_packages(m, ["mypy.errors"])), {"mypy.errors"}) assert_equal( set(walk_packages(m, ["mypy.errors", "mypy.stubgen"])), {"mypy.errors", "mypy.stubgen"}) all_mypy_packages = set(walk_packages(m, ["mypy"])) self.assertTrue( all_mypy_packages.issuperset({ "mypy", "mypy.errors", "mypy.stubgen", "mypy.test", "mypy.test.helpers", }))
def test_non_existent(self) -> None: with ModuleInspect() as m: with self.assertRaises(InspectError) as e: m.get_package_properties('foobar-non-existent') assert str(e.exception) == "No module named 'foobar-non-existent'"