10
10
if TYPE_CHECKING :
11
11
from collections .abc import Sequence
12
12
from types import ModuleType
13
- from typing import Protocol
14
-
15
- class Writer (Protocol ):
16
- def write (self , s : str , / ) -> object : ...
17
13
18
14
SEEN_MODS = set ()
19
15
20
16
21
- def walk_pkgutil (mod_name : str , locations : Sequence [str ], io : Writer ) -> None :
17
+ def walk_pkgutil (mod_name : str , locations : Sequence [str ]) -> None :
22
18
for pkg in pkgutil .walk_packages (locations , f"{ mod_name } ." ):
23
19
if pkg .name in SEEN_MODS :
24
20
continue
25
21
else :
26
22
# We don't recurse here because `walk_packages` takes care of
27
23
# it for us.
28
24
SEEN_MODS .add (pkg .name )
29
- print (pkg .name , file = io )
30
25
31
26
32
- def walk_naive (mod_name : str , mod : ModuleType , io : Writer ) -> None :
27
+ def walk_naive (mod_name : str , mod : ModuleType ) -> None :
33
28
for attr in dir (mod ):
34
29
attr_obj = getattr (mod , attr , None )
35
30
# Shouldn't happen, but who knows.
@@ -46,7 +41,7 @@ def walk_naive(mod_name: str, mod: ModuleType, io: Writer) -> None:
46
41
try :
47
42
submod_name = f"{ mod_name } .{ attr } "
48
43
importlib .import_module (submod_name )
49
- walk (submod_name , io )
44
+ walk (submod_name )
50
45
except ImportError :
51
46
# ...but sometimes we do want to include re-exports, since
52
47
# they might be things like "accelerator" modules that don't
@@ -57,17 +52,16 @@ def walk_naive(mod_name: str, mod: ModuleType, io: Writer) -> None:
57
52
# that don't actually appear on disk. Experimentally,
58
53
# there are a few of these (like "TK").
59
54
importlib .import_module (attr )
60
- walk (attr , io )
55
+ walk (attr )
61
56
except ImportError :
62
57
continue
63
58
64
59
65
- def walk (mod_name : str , io : Writer ) -> None :
60
+ def walk (mod_name : str ) -> None :
66
61
if mod_name in SEEN_MODS :
67
62
return
68
63
else :
69
64
SEEN_MODS .add (mod_name )
70
- print (mod_name , file = io )
71
65
72
66
# Try and import it.
73
67
try :
@@ -81,26 +75,35 @@ def walk(mod_name: str, io: Writer) -> None:
81
75
locations = None
82
76
83
77
if locations is not None :
84
- walk_pkgutil (mod_name , locations , io )
78
+ walk_pkgutil (mod_name , locations )
85
79
else :
86
- walk_naive (mod_name , mod , io )
80
+ walk_naive (mod_name , mod )
87
81
88
82
89
83
if __name__ == "__main__" :
90
84
output = sys .argv [1 ]
91
85
92
- with open (output , mode = "w" ) as io :
93
- for mod_name in sys .builtin_module_names :
94
- walk (mod_name , io )
86
+ for mod_name in sys .builtin_module_names :
87
+ walk (mod_name )
95
88
96
- if hasattr (sys , "stdlib_module_names" ):
97
- for mod_name in sys .stdlib_module_names :
98
- walk (mod_name , io )
99
- else :
100
- for mod_name in sys .stdin :
101
- # Our precomputed list might not start at the root, since it
102
- # might be a package rather than a module.
103
- if "." in mod_name :
104
- top_mod = mod_name .split ("." )[0 ]
105
- walk (top_mod , io )
106
- walk (mod_name .rstrip ("\n " ), io )
89
+ if hasattr (sys , "stdlib_module_names" ):
90
+ for mod_name in sys .stdlib_module_names :
91
+ walk (mod_name )
92
+ else :
93
+ for mod_name in sys .stdin :
94
+ # Our precomputed list might not start at the root, since it
95
+ # might be a package rather than a module.
96
+ if "." in mod_name :
97
+ top_mod = mod_name .split ("." )[0 ]
98
+ walk (top_mod )
99
+ walk (mod_name .rstrip ("\n " ))
100
+
101
+ try :
102
+ with open (output , encoding = "utf-8" ) as io :
103
+ SEEN_MODS .update (io .read ().splitlines ())
104
+ except FileNotFoundError :
105
+ pass
106
+
107
+ with open (output , mode = "w" , encoding = "utf-8" ) as io :
108
+ for line in sorted (SEEN_MODS ):
109
+ print (line , file = io )
0 commit comments