|
31 | 31 | from importlib import import_module |
32 | 32 | from importlib.abc import MetaPathFinder |
33 | 33 | from itertools import starmap |
34 | | -from typing import Iterable, Iterator, List, Mapping, Optional, Set, cast |
35 | | - |
| 34 | +from typing import Iterable, List, Mapping, Optional, Set, cast |
36 | 35 |
|
37 | 36 | __all__ = [ |
38 | 37 | 'Distribution', |
@@ -974,35 +973,42 @@ def _top_level_declared(dist): |
974 | 973 | return (dist.read_text('top_level.txt') or '').split() |
975 | 974 |
|
976 | 975 |
|
977 | | -def _walk_dirs(package_paths: Iterable[PackagePath]) -> Iterator[PackagePath]: |
978 | | - for package_path in package_paths: |
| 976 | +def _topmost(name: PackagePath) -> Optional[str]: |
| 977 | + """ |
| 978 | + Return the top-most parent as long as there is a parent. |
| 979 | + """ |
| 980 | + top, *rest = name.parts |
| 981 | + return top if rest else None |
979 | 982 |
|
980 | | - def make_file(name): |
981 | | - result = PackagePath(name) |
982 | | - result.hash = None |
983 | | - result.size = None |
984 | | - result.dist = package_path.dist |
985 | | - return result |
986 | 983 |
|
987 | | - real_path = package_path.locate() |
988 | | - real_sitedir = package_path.dist.locate_file("") # type: ignore |
989 | | - if real_path.is_dir() and real_path.is_symlink(): |
990 | | - # .files only mentions symlink, we must recurse into it ourselves: |
991 | | - for root, dirs, files in os.walk(real_path): |
992 | | - for filename in files: |
993 | | - real_file = pathlib.Path(root, filename) |
994 | | - yield make_file(real_file.relative_to(real_sitedir)) |
995 | | - else: |
996 | | - yield package_path |
| 984 | +def _get_toplevel_name(name: PackagePath) -> str: |
| 985 | + """ |
| 986 | + Infer a possibly importable module name from a name presumed on |
| 987 | + sys.path. |
| 988 | +
|
| 989 | + >>> _get_toplevel_name(PackagePath('foo.py')) |
| 990 | + 'foo' |
| 991 | + >>> _get_toplevel_name(PackagePath('foo')) |
| 992 | + 'foo' |
| 993 | + >>> _get_toplevel_name(PackagePath('foo.pyc')) |
| 994 | + 'foo' |
| 995 | + >>> _get_toplevel_name(PackagePath('foo.dist-info')) |
| 996 | + 'foo.dist-info' |
| 997 | + >>> _get_toplevel_name(PackagePath('foo.pth')) |
| 998 | + 'foo.pth' |
| 999 | + >>> _get_toplevel_name(PackagePath('foo/__init__.py')) |
| 1000 | + 'foo' |
| 1001 | + """ |
| 1002 | + return _topmost(name) or ( |
| 1003 | + # python/typeshed#10328 |
| 1004 | + inspect.getmodulename(name) # type: ignore |
| 1005 | + or str(name) |
| 1006 | + ) |
997 | 1007 |
|
998 | 1008 |
|
999 | 1009 | def _top_level_inferred(dist): |
1000 | | - opt_names = { |
1001 | | - f.parts[0] if len(f.parts) > 1 else inspect.getmodulename(f) |
1002 | | - for f in _walk_dirs(always_iterable(dist.files)) |
1003 | | - } |
| 1010 | + opt_names = set(map(_get_toplevel_name, always_iterable(dist.files))) |
1004 | 1011 |
|
1005 | | - @pass_none |
1006 | 1012 | def importable_name(name): |
1007 | 1013 | return '.' not in name |
1008 | 1014 |
|
|
0 commit comments