File tree Expand file tree Collapse file tree 3 files changed +25
-6
lines changed
Filter options
Expand file tree Collapse file tree 3 files changed +25
-6
lines changed
Original file line number Diff line number Diff line change @@ -232,12 +232,11 @@ def __getattribute__(self, attr):
232
232
# Only the first thread to get the lock should trigger the load
233
233
# and reset the module's class. The rest can now getattr().
234
234
if object .__getattribute__ (self , '__class__' ) is _LazyModule :
235
- # The first thread comes here multiple times as it descends the
236
- # call stack. The first time, it sets is_loading and triggers
237
- # exec_module(), which will access module.__dict__, module.__name__,
238
- # and/or module.__spec__, reentering this method. These accesses
239
- # need to be allowed to proceed without triggering the load again.
240
- if loader_state ['is_loading' ] and attr .startswith ('__' ) and attr .endswith ('__' ):
235
+ # Reentrant calls from the same thread must be allowed to proceed without
236
+ # triggering the load again.
237
+ # exec_module() and self-referential imports are the primary ways this can
238
+ # happen, but in any case we must return something to avoid deadlock.
239
+ if loader_state ['is_loading' ]:
241
240
return object .__getattribute__ (self , attr )
242
241
loader_state ['is_loading' ] = True
243
242
Original file line number Diff line number Diff line change @@ -178,6 +178,24 @@ def access_module():
178
178
# Or multiple load attempts
179
179
self .assertEqual (loader .load_count , 1 )
180
180
181
+ def test_lazy_self_referential_modules (self ):
182
+ # Directory modules with submodules that reference the parent can attempt to access
183
+ # the parent module during a load. Verify that this common pattern works with lazy loading.
184
+ # json is a good example in the stdlib.
185
+ json_modules = [name for name in sys .modules if name .startswith ('json' )]
186
+ with test_util .uncache (* json_modules ):
187
+ # Standard lazy loading, unwrapped
188
+ spec = util .find_spec ('json' )
189
+ loader = util .LazyLoader (spec .loader )
190
+ spec .loader = loader
191
+ module = util .module_from_spec (spec )
192
+ sys .modules ['json' ] = module
193
+ loader .exec_module (module )
194
+
195
+ # Trigger load with attribute lookup, ensure expected behavior
196
+ test_load = module .loads ('{}' )
197
+ self .assertEqual (test_load , {})
198
+
181
199
182
200
if __name__ == '__main__' :
183
201
unittest .main ()
Original file line number Diff line number Diff line change
1
+ Fix regression in lazy loading of self-referential modules, introduced in
2
+ gh-114781.
You can’t perform that action at this time.
0 commit comments