pythoninspect

Python - Get the source code of the line that called me


Using the python inspect module, in a function, I would like to get the source code of the line that called that function.

So in the following situation:

def fct1():
    # Retrieve the line that called me and extract 'a'
    return an object containing name='a'

a = fct1()

I would like to retrieve the string "a = fct1()" in fct1

All I can do so far is to retrieve the code of the whole module with :

code = inspect.getsource(sys._getframe().f_back)

Please note that fct1() can be called many times in the main module.

Eventually, what I want is to retrieve the variable name "a" which is easy if I can get s = "a = fct1()" in fct1() :

a_name = s.split("=")[0].strip()

Solution

  • A really dumb solution would be to capture a stack trace and take the 2nd line:

    import traceback
    
    def fct1():
        stack = traceback.extract_stack(limit=2)
        print(traceback.format_list(stack)[0].split('\n')[1].strip())  # prints "a = fct1()"
        return None
    
    a = fct1()
    

    @jtlz2 asked for it in a decorator

    import traceback
    
    def add_caller(func):
        def wrapper(*args, **kwargs):
            stack = traceback.extract_stack(limit=2)
            func(*args, caller=traceback.format_list(stack)[0].split('\n')[1].strip(), **kwargs)
        return wrapper
    
    @add_caller
    def fct1(caller):
        print(caller)
    
    fct1()
    

    And it does work.

    UPDATE Here's a functional version (which needed limit=3 for the caller of the caller):

    import traceback
    
    def source_line_of_caller():
        """Return the Python source code line that called your function."""
        stack = traceback.extract_stack(limit=3)
        return traceback.format_list(stack)[0].split('\n')[1].strip()
    
    def _tester():
        assert "_tester() # whoa, comments too" == source_line_of_caller()
    
    _tester() # whoa, comments too