101

I need to get the caller info (what file/what line) from callee. I learned that I can use inpect module for that for purposes, but not exactly how.

How to get those info with inspect? Or is there any other way to get the info?

import inspect

print __file__
c=inspect.currentframe()
print c.f_lineno

def hello():
    print inspect.stack
    ?? what file called me in what line?

hello()
prosseek
  • 182,215
  • 215
  • 566
  • 871

4 Answers4

126

The caller's frame is one frame higher than the current frame. You can use inspect.currentframe().f_back to find the caller's frame. Then use inspect.getframeinfo to get the caller's filename and line number.

import inspect


def hello():
    previous_frame = inspect.currentframe().f_back

    (
        filename,
        line_number,
        function_name,
        lines,
        index,
    ) = inspect.getframeinfo(previous_frame)

    return (filename, line_number, function_name, lines, index)


print(hello())

# ('/home/unutbu/pybin/test.py', 10, '<module>', ['hello()\n'], 0) 
ijoseph
  • 6,505
  • 4
  • 26
  • 26
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 7
    @prosseek: To get the caller's caller, just change the index `[1]` to `[2]`. (`inspect.getouterframes` returns a list of frames...). Python is beautifully organized. – unutbu Sep 14 '10 at 17:38
  • 3
    You can also use inspect.currentframe().f_back. – yoyo Jul 29 '15 at 16:26
  • This doesn't seem to provide a way to get the full path of the filename. – Jason S Sep 02 '16 at 18:49
  • 2
    @JasonS: "the filename in the stack frame is [relative to the start up directory](https://doughellmann.com/blog/2012/04/30/determining-the-name-of-a-process-from-python/) of the application". – unutbu Sep 02 '16 at 19:06
  • @unutbu: you somehow read my mind; this is in sphinx and it changed the current directory so i need the startup directory via sys.path[0]. – Jason S Sep 02 '16 at 19:12
  • 9
    This code sample works but performs pretty poorly. If you're only interested in a single frame and not the whole stack trace, you can get the previous frame and inspect it for the frame info: ```filename, line_number, clsname, lines, index = inspect.getframeinfo(sys._getframe(1))``` – Mouscellaneous Sep 28 '17 at 11:21
  • 3
    @Mouscellaneous that is a huge savings, brings my time from ~30 ms to ~4 ms per call. One nice feature also is I can do this: `calling_function = inspect.getframeinfo(sys._getframe(1))[2]` so I don't have to waste memory with all those other variables that I don't care about. I just pull the calling function name – eric Oct 22 '17 at 00:46
  • @Mouscellaneous: Thanks for the improvement! – unutbu Oct 22 '17 at 12:29
  • The years roll past, yet this answer os still amazingly useful. – James Phillips Jul 18 '19 at 16:45
52

I would suggest to use inspect.stack instead:

import inspect

def hello():
    frame,filename,line_number,function_name,lines,index = inspect.stack()[1]
    print(frame,filename,line_number,function_name,lines,index)
hello()
Dmitry K.
  • 1,145
  • 1
  • 9
  • 16
  • How is it better than using `getouterframes` as suggested by @unutbu? – ixe013 Sep 04 '14 at 03:02
  • 8
    It is more compact and better reflects the intent. – Dmitry K. Sep 04 '14 at 08:40
  • 1
    Note that `getouterframes(currentframe())` and `stack()` are equivalent under the hood https://github.com/python/cpython/blob/master/Lib/inspect.py#L1442 – ubershmekel May 12 '16 at 21:14
  • 1
    Another reason using stack() is nice is that it shows how to easily get other frames. If, for example. your hello() function is called by another function first, you can update it to go two levels back. – Charles Plager May 03 '18 at 18:02
  • 1
    I have profiled my code and it turned out that `stack()` is much slower that `sys._getframe(1).f_lineno`. In 1e6 calls it add 10 mins in my Linux environment. – TrueY Feb 25 '22 at 20:04
2

I published a wrapper for inspect with simple stackframe addressing covering the stack frame by a single parameter spos:

E.g. pysourceinfo.PySourceInfo.getCallerLinenumber(spos=1)

where spos=0 is the lib-function, spos=1 is the caller, spos=2 the caller-of-the-caller, etc.

acue
  • 381
  • 3
  • 6
-9

If the caller is the main file, simply use sys.argv[0]