diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index e9ae0d19..76ccacbc 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -31,7 +31,7 @@ from importlib import import_module from importlib.abc import MetaPathFinder from itertools import starmap -from typing import List, Mapping, Optional, cast +from typing import Iterable, Iterator, List, Mapping, Optional, cast __all__ = [ @@ -961,10 +961,32 @@ def _top_level_declared(dist): return (dist.read_text('top_level.txt') or '').split() +def _walk_dirs(package_paths: Iterable[PackagePath]) -> Iterator[PackagePath]: + for package_path in package_paths: + + def make_file(name): + result = PackagePath(name) + result.hash = None + result.size = None + result.dist = package_path.dist + return result + + real_path = package_path.locate() + real_sitedir = package_path.dist.locate_file("") # type: ignore + if real_path.is_dir() and real_path.is_symlink(): + # .files only mentions symlink, we must recurse into it ourselves: + for root, dirs, files in os.walk(real_path): + for filename in files: + real_file = pathlib.Path(root, filename) + yield make_file(real_file.relative_to(real_sitedir)) + else: + yield package_path + + def _top_level_inferred(dist): opt_names = { f.parts[0] if len(f.parts) > 1 else inspect.getmodulename(f) - for f in always_iterable(dist.files) + for f in _walk_dirs(always_iterable(dist.files)) } @pass_none