Soid
Soid

Reputation: 2859

For python is there a way to print variables scope from context where exception happens?

Is there a way to print variables scope from context where exception happens?

For example:

def f():
    a = 1
    b = 2
    1/0

try:
    f()
except:
    pass # here I want to print something like "{'a': 1, 'b': 2}"

Upvotes: 15

Views: 6650

Answers (5)

Jan Pokorný
Jan Pokorný

Reputation: 1868

Zero dependency solution for Python 3:

import traceback

def format_traceback_with_locals(exc):
    traceback_segments = traceback.format_exception(exc)
    traceback_string = traceback_segments[0]
    tb = exc.__traceback__
    while tb is not None:
        locals_dict = {k: v for k, v in tb.tb_frame.f_locals.items() if not k.startswith("__")}
        traceback_segment = traceback.format_tb(tb)[0]
        traceback_string += traceback_segment
        traceback_string += "  -> local variables: " + str(locals_dict) + "\n"
        tb = tb.tb_next
    traceback_string += traceback_segments[-1]
    return traceback_string

Usage:

try:
    ...
except Exception as e:
    print(format_traceback_with_locals(e))

This iterates over traceback segments (the header, then each frame, and finally the exception) and prints the corresponding local variables after each frame.

Upvotes: 0

Kroshka Kartoshka
Kroshka Kartoshka

Reputation: 1178

Depending on what you need, there are 2 general best practices.

Just print the variables with minimal code edits

Have a look at some related packages. For simple usage you might pick traceback-with-variables (pip install traceback-with-variables), here is it's postcard

enter image description here

Or try tbvaccine, or better-exceptions, or any other package

Programmatically access variables to use them in your code

Use inspect module

except ... as ...:
    x = inspect.trace()[-1][0].f_locals['x']

Upvotes: 2

Sylvain Defresne
Sylvain Defresne

Reputation: 44493

You can use the function sys.exc_info() to get the last exception that occurred in the current thread in you except clause. This will be a tuple of exception type, exception instance and traceback. The traceback is a linked list of frame. This is what is used to print the backtrace by the interpreter. It does contains the local dictionnary.

So you can do:

import sys

def f():
    a = 1
    b = 2
    1/0

try:
    f()
except:
    exc_type, exc_value, tb = sys.exc_info()
    if tb is not None:
        prev = tb
        curr = tb.tb_next
        while curr is not None:
            prev = curr
            curr = curr.tb_next
        print prev.tb_frame.f_locals

Upvotes: 23

ondra
ondra

Reputation: 9331

You have to first extract traceback, in your example something like this would print it:

except:
    print sys.exc_traceback.tb_next.tb_frame.f_locals

I'm not sure about the tb_next, I would guess you have to go through the complete traceback, so something like this (untested):

except:
    tb_last = sys.exc_traceback
    while tb_last.tb_next:
        tb_last = tb_last.tb_next
    print tb_last.tb_frame.f_locals

Upvotes: 7

Mark Hildreth
Mark Hildreth

Reputation: 43061

Perhaps you're looking for locals() and globals()?

Upvotes: 3

Related Questions