DEV Community

Flávia Bastos
Flávia Bastos

Posted on • Originally published at flaviabastos.ca on

4 2

A caller id for your python function

Most of you might be too young to know this but there was time that the phone in your house – not in your pocket! – would ring and gasp! you had no idea who were calling! You had to ANSWER the phone to find out. 🤦‍♀️ Now we have caller ID and know exactly who is calling – and can completely ignore the call decide if we are answering the call or not.

When working with large applications, for debugging purposes, I find very helpful to know which function is calling what function. Breakpoints and print statements are useful tools but sometimes you just need more information. In a large codebase it’s fairly easy to get lost with breakpoints so I’ve been using the chunk of code below to print extra info and learn a little bit more about my application.

import inspect
func = inspect.currentframe().f_back.f_code
print(f"in function 'my_function' called from NAME: {func.co_name} in FILENAME: {func.co_filename} on LINE#: {func.co_firstlineno}")
Enter fullscreen mode Exit fullscreen mode

How to use

Consider a *very* simple program (which honestly doesn’t even need our helper function, but for the sake of example, stay with me here):


def helper_function(value):
    return value.isnumeric()

def adder(num1, num2):
    return int(num1) + int(num2)

def main():
    print("The most useless calculator!")
    first_number = input("Please enter a number: ")
    second_number = input("Please enter another number: ")
    print(f"Let's add {first_number} and {second_number}")

    if helper_function(first_number) and helper_function(second_number):
        total = adder(first_number, second_number)
        print(f"The total is {total}")
    else:
        print("Sorry, we cannot add these values...")

main()

Enter fullscreen mode Exit fullscreen mode

The function above takes two pieces of input form the command line (lines 11 and 12), calls a helper function to check if the values entered are numbers (line 15) and if so, calls the function to add the numbers (line 16).

Now, just for a moment let’s pretend that each of these functions are way more complicated than this and live in separate files. Add some more functionality, a framework, 2 cups of all-purpose flour and a webserver. Voilà! You have a web application. What if you still want to know which function called what? Let’s add our chunk of code to adder:


def helper_function(value):
    return value.isnumeric()

def adder(num1, num2):
    import inspect
    func = inspect.currentframe().f_back.f_code
    print(
        f" **** in function 'adder' called from NAME: {func.co_name} in FILENAME: {func.co_filename} on LINE#: {func.co_firstlineno}"
    )

    return int(num1) + int(num2)

def main():
    print("The most useless calculator!")
    first_number = input("Please enter a number: ")
    second_number = input("Please enter another number: ")
    print(f"Let's add {first_number} and {second_number}")

    if helper_function(first_number) and helper_function(second_number):
        total = adder(first_number, second_number)
        print(f"The total is {total}")
    else:
        print("Sorry, we cannot add these values...")

main()

Enter fullscreen mode Exit fullscreen mode

When you run this script now (let’s save it as “watcher.py”), it will output the information about the function that called adder, in this case, main:

>>> python3 watcher.py 
The most useless calculator!
Please enter a number: 4
Please enter another number: 2
Let's add 4 and 2
**** in function 'adder' called from NAME: main in FILENAME: watcher.py on LINE#: 15
The total is 6
Enter fullscreen mode Exit fullscreen mode

Note that the line number is the line where the parent function, in this case “main”, starts, not where our function was called from!

This has been very helpful and I’ve used a lot lately. I hope it helps you too!

Fancypants 👖

You will need to copy this chunk of code into every function you would like to debug but that’s a bit tedious. Instead, you can turn it into a decorator and decorate the functions you want to inspect. Start by creating your decorator:


def caller_id(my_func):
    def wrapper(*args, **kwargs):
        import inspect

        my_func(*args, **kwargs)

        func = inspect.currentframe().f_back.f_code
        print(
            f"in function {my_func. __name__ } called from NAME: {func.co_name} in FILENAME: {func.co_filename} on LINE#: {func.co_firstlineno}"
        )

    return wrapper

Enter fullscreen mode Exit fullscreen mode

Then, you can decorate your function with it. Let’s add it to adder again. Now adder looks like:

@caller_id
def adder(num1, num2):
    return int(num1) + int(num2)
Enter fullscreen mode Exit fullscreen mode

That’s it.


If you found this helpful, let me know on Twitter!

The post A caller id for your python function _was originally published at _flaviabastos.ca

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay