@@ -929,32 +929,93 @@ def getabsfile(object, _filename=None):
929929modulesbyfile = {}
930930_filesbymodname = {}
931931
932- def _getframemodule (frame , filename ):
933- """Resolve a frame's registered globals owner with a matching origin."""
932+ def _getframemodule (frame , explicit_filename ):
933+ """Return a matching globals owner and a reusable fallback filename.
934+
935+ The filename is only returned if the owner does not match and the
936+ filename-based lookup can reuse the normalized frame filename.
937+ """
934938 namespace = frame .f_globals
935- name = namespace .get ('__name__' )
939+ name = dict .get (namespace , '__name__' )
936940 if type (name ) is not str :
937- return None
941+ return None , None
938942 module = sys .modules .get (name )
939- # Leave module subclasses and dynamically supplied filenames to the fallback .
943+ # Leave subclasses and dynamic filenames to the existing lookup .
940944 if (type (module ) is not types .ModuleType
941- or module .__dict__ is not namespace
942- or type (namespace .get ('__file__' )) is not str ):
943- return None
945+ or module .__dict__ is not namespace ):
946+ return None , None
947+ module_filename = namespace .get ('__file__' )
948+ filename = frame .f_code .co_filename
949+ # Avoid invoking user-defined comparisons when matching filenames.
950+ if type (module_filename ) is not str or type (filename ) is not str :
951+ return None , None
952+ if explicit_filename is not None and explicit_filename != filename :
953+ return None , None
954+ # Equal filenames need no normalization. An explicit bytecode
955+ # filename must retain the source/bytecode distinction.
956+ if module_filename == filename and (
957+ explicit_filename is None or not filename .endswith (
958+ tuple (importlib .machinery .BYTECODE_SUFFIXES ))):
959+ return module , None
960+ bytecode_suffixes = tuple (importlib .machinery .BYTECODE_SUFFIXES )
961+ is_bytecode = filename .endswith (bytecode_suffixes )
944962 try :
945- if filename == getabsfile (module ):
946- return module
947- except FileNotFoundError , TypeError :
963+ # Resolve bytecode aliases using the owner's loader to avoid
964+ # looking up the frame recursively through getsourcefile().
965+ if explicit_filename is None and is_bytecode :
966+ source = (os .path .splitext (filename )[0 ]
967+ + importlib .machinery .SOURCE_SUFFIXES [0 ])
968+ if (source in linecache .cache or os .path .exists (source )
969+ or getattr (module , '__loader__' , None ) is not None
970+ or getattr (getattr (module , '__spec__' , None ),
971+ 'loader' , None ) is not None ):
972+ filename = source
973+ if module_filename .endswith (bytecode_suffixes ):
974+ source = (os .path .splitext (module_filename )[0 ]
975+ + importlib .machinery .SOURCE_SUFFIXES [0 ])
976+ if source == filename and namespace .get ('__loader__' ) is not None :
977+ return module , None
978+ origin = getabsfile (module )
979+ else :
980+ origin = getabsfile (module , module_filename )
981+ file = getabsfile (frame , filename )
982+ if origin == file :
983+ return module , None
984+ # Reuse the path only if it preserves explicit-filename
985+ # precedence and bytecode source resolution.
986+ if explicit_filename is None and not is_bytecode :
987+ return None , file
988+ except (FileNotFoundError , TypeError ):
948989 pass
949- return None
990+ return None , None
950991
951992
952993def getmodule (object , _filename = None ):
953994 """Return the module an object was defined in, or None if not found."""
954- if ismodule (object ):
955- return object
956- if hasattr (object , '__module__' ):
957- return sys .modules .get (object .__module__ )
995+ object_type = type (object )
996+ if object_type is types .FrameType :
997+ frame = object
998+ elif object_type is types .TracebackType :
999+ frame = object .tb_frame
1000+ else :
1001+ if isinstance (object , types .ModuleType ):
1002+ return object
1003+ if hasattr (object , '__module__' ):
1004+ return sys .modules .get (object .__module__ )
1005+ frame = None
1006+ if frame is not None :
1007+ # A module with these exact globals is the only possible globals
1008+ # owner. Otherwise verify ownership before using a cached result.
1009+ if _filename is not None and _filename in modulesbyfile :
1010+ module = sys .modules .get (modulesbyfile [_filename ])
1011+ if (type (module ) is types .ModuleType
1012+ and module .__dict__ is frame .f_globals ):
1013+ return module
1014+ module , fallback_filename = _getframemodule (frame , _filename )
1015+ if module is not None :
1016+ return module
1017+ if fallback_filename is not None :
1018+ _filename = fallback_filename
9581019
9591020 # Try the filename to modulename cache
9601021 if _filename is not None and _filename in modulesbyfile :
@@ -966,19 +1027,6 @@ def getmodule(object, _filename=None):
9661027 return None
9671028 if file in modulesbyfile :
9681029 return sys .modules .get (modulesbyfile [file ])
969- if isframe (object ):
970- frame = object
971- elif istraceback (object ):
972- frame = object .tb_frame
973- else :
974- frame = None
975- if frame is not None and (
976- _filename is None or _filename == frame .f_code .co_filename ):
977- module = _getframemodule (frame , file )
978- if module is not None :
979- modulesbyfile [file ] = module .__name__
980- return module
981-
9821030 # Update the filename to module name cache and check yet again
9831031 # Copy sys.modules in order to cope with changes while iterating
9841032 for modname , module in sys .modules .copy ().items ():
0 commit comments