@@ -159,8 +159,8 @@ def addLevelName(level, levelName):
159159 finally :
160160 _releaseLock ()
161161
162- if hasattr (sys , ' _getframe' ):
163- currentframe = lambda : sys ._getframe (3 )
162+ if hasattr (sys , " _getframe" ):
163+ currentframe = lambda : sys ._getframe (1 )
164164else : #pragma: no cover
165165 def currentframe ():
166166 """Return the frame object for the caller's stack frame."""
@@ -184,13 +184,18 @@ def currentframe():
184184_srcfile = os .path .normcase (addLevelName .__code__ .co_filename )
185185
186186# _srcfile is only used in conjunction with sys._getframe().
187- # To provide compatibility with older versions of Python, set _srcfile
188- # to None if _getframe() is not available; this value will prevent
189- # findCaller() from being called. You can also do this if you want to avoid
190- # the overhead of fetching caller information, even when _getframe() is
191- # available.
192- #if not hasattr(sys, '_getframe'):
193- # _srcfile = None
187+ # Setting _srcfile to None will prevent findCaller() from being called. This
188+ # way, you can avoid the overhead of fetching caller information.
189+
190+ # The following is based on warnings._is_internal_frame. It makes sure that
191+ # frames of the import mechanism are skipped when logging at module level and
192+ # using a stacklevel value greater than one.
193+ def _is_internal_frame (frame ):
194+ """Signal whether the frame is a CPython or logging module internal."""
195+ filename = os .path .normcase (frame .f_code .co_filename )
196+ return filename == _srcfile or (
197+ "importlib" in filename and "_bootstrap" in filename
198+ )
194199
195200
196201def _checkLevel (level ):
@@ -1558,33 +1563,31 @@ def findCaller(self, stack_info=False, stacklevel=1):
15581563 f = currentframe ()
15591564 #On some versions of IronPython, currentframe() returns None if
15601565 #IronPython isn't run with -X:Frames.
1561- if f is not None :
1562- f = f .f_back
1563- orig_f = f
1564- while f and stacklevel > 1 :
1565- f = f .f_back
1566- stacklevel -= 1
1567- if not f :
1568- f = orig_f
1569- rv = "(unknown file)" , 0 , "(unknown function)" , None
1570- while hasattr (f , "f_code" ):
1571- co = f .f_code
1572- filename = os .path .normcase (co .co_filename )
1573- if filename == _srcfile :
1574- f = f .f_back
1575- continue
1576- sinfo = None
1577- if stack_info :
1578- sio = io .StringIO ()
1579- sio .write ('Stack (most recent call last):\n ' )
1566+ if f is None :
1567+ return "(unknown file)" , 0 , "(unknown function)" , None
1568+ while stacklevel > 0 :
1569+ next_f = f .f_back
1570+ if next_f is None :
1571+ ##TODO: We've got options here
1572+ ## If we want to use the last (deepest) frame:
1573+ break
1574+ ## If we want to mimic the warnings module:
1575+ #return ("sys", 1, "(unknown function)", None)
1576+ ## If we want to be pedantic:
1577+ #raise ValueError("call stack is not deep enough")
1578+ f = next_f
1579+ if not _is_internal_frame (f ):
1580+ stacklevel -= 1
1581+ co = f .f_code
1582+ sinfo = None
1583+ if stack_info :
1584+ with io .StringIO () as sio :
1585+ sio .write ("Stack (most recent call last):\n " )
15801586 traceback .print_stack (f , file = sio )
15811587 sinfo = sio .getvalue ()
15821588 if sinfo [- 1 ] == '\n ' :
15831589 sinfo = sinfo [:- 1 ]
1584- sio .close ()
1585- rv = (co .co_filename , f .f_lineno , co .co_name , sinfo )
1586- break
1587- return rv
1590+ return co .co_filename , f .f_lineno , co .co_name , sinfo
15881591
15891592 def makeRecord (self , name , level , fn , lno , msg , args , exc_info ,
15901593 func = None , extra = None , sinfo = None ):
0 commit comments