@@ -161,6 +161,10 @@ def test_module(module_name: str) -> Iterator[Error]:
161
161
with warnings .catch_warnings ():
162
162
warnings .simplefilter ("ignore" )
163
163
runtime = importlib .import_module (module_name )
164
+ # Also run the equivalent of `from module import *`
165
+ # This could have the additional effect of loading not-yet-loaded submodules
166
+ # mentioned in __all__
167
+ __import__ (module_name , fromlist = ["*" ])
164
168
except Exception as e :
165
169
yield Error ([module_name ], "failed to import: {}" .format (e ), stub , MISSING )
166
170
return
@@ -200,26 +204,29 @@ def verify_mypyfile(
200
204
to_check = set (
201
205
m
202
206
for m , o in stub .names .items ()
207
+ # TODO: change `o.module_public` to `not o.module_hidden`
203
208
if o .module_public and (not m .startswith ("_" ) or hasattr (runtime , m ))
204
209
)
205
210
runtime_public_contents = [
206
211
m
207
212
for m in dir (runtime )
208
213
if not m .startswith ("_" )
209
- # Ensure that the object's module is `runtime`, e.g. so that we don't pick up reexported
210
- # modules and infinitely recurse. Unfortunately, there's no way to detect an explicit
211
- # reexport missing from the stubs (that isn't specified in __all__)
214
+ # Ensure that the object's module is `runtime`, since in the absence of __all__ we don't
215
+ # have a good way to detect re-exports at runtime.
212
216
and getattr (getattr (runtime , m ), "__module__" , None ) == runtime .__name__
213
217
]
214
218
# Check all things declared in module's __all__, falling back to runtime_public_contents
215
219
to_check .update (getattr (runtime , "__all__" , runtime_public_contents ))
216
220
to_check .difference_update ({"__file__" , "__doc__" , "__name__" , "__builtins__" , "__package__" })
217
221
218
222
for entry in sorted (to_check ):
219
- stub_to_verify = stub .names [entry ].node if entry in stub .names else MISSING
220
- assert stub_to_verify is not None
223
+ stub_entry = stub .names [entry ].node if entry in stub .names else MISSING
224
+ if isinstance (stub_entry , nodes .MypyFile ):
225
+ # Don't recursively check exported modules, since that leads to infinite recursion
226
+ continue
227
+ assert stub_entry is not None
221
228
yield from verify (
222
- stub_to_verify ,
229
+ stub_entry ,
223
230
getattr (runtime , entry , MISSING ),
224
231
object_path + [entry ],
225
232
)
0 commit comments