When an exception occurs in Python, it's often crucial to get detailed information about it: the exception type, the file where it occurred, and the line number.
This guide explains how to retrieve this information using:
- Attributes of the exception object itself.
- The
sys.exc_info()function. - The
tracebackmodule.
We'll cover single exceptions and how to handle multiple exceptions in a traceback.
Getting Exception Information from the Exception Object
The exception object itself (the e in except Exception as e:) contains valuable information:
try:
raise ValueError('invalid value')
except ValueError as e: # Catch the exception
e_type = type(e).__name__ # Get the exception type (e.g., 'ValueError')
e_file = e.__traceback__.tb_frame.f_code.co_filename # Get the filename
e_line = e.__traceback__.tb_lineno # Get the line number
e_message = str(e) # Get the exception message
print(f'exception type: {e_type}') # Output: exception type: ValueError
print(f'exception filename: {e_file}') # Output: exception filename: /path/to/your/file.py
print(f'exception line number: {e_line}') # Output: exception line number: 2
print(f'exception message: {e_message}') # Output: exception message: invalid valuetype(e).__name__: Gets the name of the exception class (e.g., "ValueError", "TypeError"). This is generally more reliable than usinge.__class__.__name__directly.e.__traceback__: This is the traceback object associated with the exception. Traceback objects contain the call stack information.e.__traceback__.tb_frame.f_code.co_filename: This drills down into the traceback to get the filename.tb_frameis the current stack frame,f_codeis the code object, andco_filenameis the filename.e.__traceback__.tb_lineno: This gets the line number within the file where the exception occurred.str(e): This gets the exception's message (the string argument you passed toraise ValueError(...)).
Getting Exception Information with sys.exc_info()
The sys.exc_info() function returns a tuple containing information about the currently handled exception:
import sys
import os
try:
raise ValueError('invalid value')
except ValueError as e:
e_type, e_object, e_traceback = sys.exc_info() # Get exception info
e_filename = os.path.split(e_traceback.tb_frame.f_code.co_filename)[1] # Extract filename
e_message = str(e)
e_line_number = e_traceback.tb_lineno
print(f'exception type: {e_type}') # Output: exception type: <class 'ValueError'>
print(f'exception filename: {e_filename}') # Output: exception filename: main.py
print(f'exception line number: {e_line_number}') # Output: exception line number: 5
print(f'exception message: {e_message}') # Output: exception message: invalid value- The method returns a tuple containing exception type, exception object, and exception traceback.
Getting Formatted Exception Information with traceback
The traceback module provides functions for working with tracebacks in a more structured way.
Using traceback.format_exc()
traceback.format_exc() returns a formatted string representing the entire traceback, similar to what you see when an unhandled exception occurs:
import traceback
try:
raise ValueError('invalid value')
except ValueError as e:
print(traceback.format_exc())Output:
Traceback (most recent call last):
File "/path/to/your/file.py", line 4, in <module>
raise ValueError('invalid value')
ValueError: invalid valueUsing traceback.print_exc()
traceback.print_exc() prints the formatted traceback directly to the console (or to a file if you specify one):
import traceback
try:
raise ValueError('invalid value')
except ValueError as e:
traceback.print_exc()Output (to console):
Traceback (most recent call last):
File "/path/to/your/file.py", line 4, in <module>
raise ValueError('invalid value')
ValueError: invalid valueHandling Multiple Exceptions in a Traceback
If you have nested exceptions (an exception raised while handling another exception), you can iterate through the traceback to get information about each exception in the chain:
import sys
import os
try:
raise ValueError('invalid value')
except ValueError as e:
all_exceptions = []
tback = e.__traceback__
while tback is not None: # Iterate over the traceback frames
e_type = type(e).__name__
e_file = tback.tb_frame.f_code.co_filename
e_line = tback.tb_lineno
e_message = str(e)
all_exceptions.append({
'e_type': e_type,
'e_file': e_file,
'e_line': e_line,
'e_message': e_message,
})
tback = tback.tb_next # Move to the *next* frame in the traceback
print(all_exceptions)Output:
[
{'e_type': 'ValueError',
'e_file': '/path/to/your/file.py',
'e_line': 3, 'e_message': 'invalid value'
}
]- The
tb_nextattribute is used to access the next frame in the traceback, creating a linked structure to iterate over.