Skip to content

Commit 38468f9

Browse files
authored
Use importlib in walk-modules.py (#173)
1 parent 913bae7 commit 38468f9

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

support/walk-modules.py

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
#!/usr/bin/env python
2+
from __future__ import annotations
23

4+
import importlib
35
import inspect
46
import pkgutil
57
import sys
68

9+
TYPE_CHECKING = False
10+
if TYPE_CHECKING:
11+
from collections.abc import Sequence
12+
from types import ModuleType
13+
from typing import Protocol
14+
15+
class Writer(Protocol):
16+
def write(self, s: str, /) -> object: ...
17+
718
SEEN_MODS = set()
819

920

10-
def walk_pkgutil(mod_name, mod, io):
11-
for pkg in pkgutil.walk_packages(mod.__path__, mod_name + "."):
21+
def walk_pkgutil(mod_name: str, locations: Sequence[str], io: Writer) -> None:
22+
for pkg in pkgutil.walk_packages(locations, f"{mod_name}."):
1223
if pkg.name in SEEN_MODS:
1324
continue
1425
else:
@@ -18,7 +29,7 @@ def walk_pkgutil(mod_name, mod, io):
1829
print(pkg.name, file=io)
1930

2031

21-
def walk_naive(mod_name, mod, io):
32+
def walk_naive(mod_name: str, mod: ModuleType, io: Writer) -> None:
2233
for attr in dir(mod):
2334
attr_obj = getattr(mod, attr, None)
2435
# Shouldn't happen, but who knows.
@@ -33,8 +44,8 @@ def walk_naive(mod_name, mod, io):
3344
# and import the submodule by its qualified name.
3445
# If the import fails, we know it's a re-exported module.
3546
try:
36-
submod_name = mod_name + "." + attr
37-
__import__(submod_name)
47+
submod_name = f"{mod_name}.{attr}"
48+
importlib.import_module(submod_name)
3849
walk(submod_name, io)
3950
except ImportError:
4051
# ...but sometimes we do want to include re-exports, since
@@ -45,13 +56,13 @@ def walk_naive(mod_name, mod, io):
4556
# Again, try and import to avoid module-looking object
4657
# that don't actually appear on disk. Experimentally,
4758
# there are a few of these (like "TK").
48-
__import__(attr)
59+
importlib.import_module(attr)
4960
walk(attr, io)
5061
except ImportError:
5162
continue
5263

5364

54-
def walk(mod_name, io):
65+
def walk(mod_name: str, io: Writer) -> None:
5566
if mod_name in SEEN_MODS:
5667
return
5768
else:
@@ -60,15 +71,16 @@ def walk(mod_name, io):
6071

6172
# Try and import it.
6273
try:
63-
mod = __import__(mod_name)
64-
65-
if hasattr(mod, "__path__"):
66-
walk_pkgutil(mod_name, mod, io)
67-
else:
68-
walk_naive(mod_name, mod, io)
69-
74+
mod = importlib.import_module(mod_name)
7075
except ImportError:
71-
pass
76+
return
77+
78+
try:
79+
locations = mod.__spec__.submodule_search_locations
80+
except AttributeError:
81+
walk_naive(mod_name, mod, io)
82+
else:
83+
walk_pkgutil(mod_name, locations, io)
7284

7385

7486
if __name__ == "__main__":

0 commit comments

Comments
 (0)