@@ -1090,6 +1090,76 @@ def test_filename_collision_uses_globals_owner(self):
10901090 for object in (frame , traceback ):
10911091 self .assertIs (inspect .getmodule (object ), self .module )
10921092
1093+ # An unrelated miss scans the registry and can replace that entry.
1094+ self .assertIsNone (inspect .getmodule (
1095+ compile ('pass' , '<inspect-unrelated-miss>' , 'exec' )))
1096+ for object in (frame , traceback ):
1097+ self .assertIs (inspect .getmodule (object ), other )
1098+
1099+ # Bare code uses the filename map, including entries populated
1100+ # by an earlier frame lookup.
1101+ inspect .modulesbyfile .clear ()
1102+ inspect ._filesbymodname .clear ()
1103+ self .assertIs (inspect .getmodule (frame .f_code ), other )
1104+ inspect .modulesbyfile .clear ()
1105+ inspect ._filesbymodname .clear ()
1106+ self .assertIs (inspect .getmodule (frame ), self .module )
1107+ self .assertIs (inspect .getmodule (frame .f_code ), self .module )
1108+
1109+ def test_static_filename_with_module_getattr_avoids_scan (self ):
1110+ def module_getattr (name ):
1111+ self .fail (f'unexpected module attribute lookup: { name } ' )
1112+
1113+ self .module .__getattr__ = module_getattr
1114+ frame , traceback = self .capture ()
1115+
1116+ class NoScanDict (dict ):
1117+ def copy (self ):
1118+ raise AssertionError ('registered frame scanned sys.modules' )
1119+
1120+ with unittest .mock .patch .object (sys , 'modules' , NoScanDict (sys .modules )):
1121+ for object in (frame , traceback ):
1122+ inspect .modulesbyfile .clear ()
1123+ inspect ._filesbymodname .clear ()
1124+ self .assertIs (inspect .getmodule (object ), self .module )
1125+
1126+ def test_filename_supplied_by_module_getattr_falls_back (self ):
1127+ del self .module .__file__
1128+
1129+ def module_getattr (name ):
1130+ if name == '__file__' :
1131+ return self .module .source
1132+ raise AttributeError (name )
1133+
1134+ self .module .__getattr__ = module_getattr
1135+ for suffix in ('.dynamic' , '.changed' ):
1136+ self .module .source = self .filename + suffix
1137+ frame , traceback = self .capture (filename = self .module .source )
1138+ for object in (frame , traceback ):
1139+ inspect .modulesbyfile .clear ()
1140+ inspect ._filesbymodname .clear ()
1141+ self .assertIs (inspect .getmodule (object ), self .module )
1142+
1143+ def test_loader_supplied_by_module_getattr (self ):
1144+ self .module .__file__ = self .filename + 'c'
1145+ del self .module .__loader__
1146+ loader = object ()
1147+ requested = []
1148+
1149+ def module_getattr (name ):
1150+ requested .append (name )
1151+ if name == '__loader__' :
1152+ return loader
1153+ raise AttributeError (name )
1154+
1155+ self .module .__getattr__ = module_getattr
1156+ frame , traceback = self .capture ()
1157+ for obj in (frame , traceback ):
1158+ inspect .modulesbyfile .clear ()
1159+ inspect ._filesbymodname .clear ()
1160+ self .assertIs (inspect .getmodule (obj ), self .module )
1161+ self .assertIn ('__loader__' , requested )
1162+
10931163 def test_unregistered_namespace_uses_filename_fallback (self ):
10941164 namespace = {'__name__' : self .module .__name__ }
10951165 frame , traceback = self .capture (namespace )
0 commit comments