In an except block I want to raise the same exception but without the stack trace and without the information that this exception has been raised as direct cause of another exception. (and without modifying sys.tracebacklimit globally)
Additionally I have a very clumsy exception class which parses and modifies the message text so I can't just reproduce it.
My current approach is
try:
deeply_nested_function_that_raises_exception()
except ClumsyExceptionBaseClass as exc:
cls, code, msg = exc.__class__, exc.code, exc.msg
raise cls("Error: %d %s" % (code, msg))
What I'm doing here is de-composing the exception information, re-assemble a new exception with a message which will be parsed and split into error code and message in the constructor and raise it from outside the except block in order to forget all trace information.
Is there a more pythonic way to do this? All I want is get rid of the noisy (and useless in my case) trace back while keeping the information contained in the exception object..
In Python 3, you can use with_traceback to remove the traceback entries accumulated so far:
try: ...
except Exception as e:
raise e.with_traceback(None)
In Python 2, it’s just
try: ...
except Exception as e:
raise e # not just "raise"
It will of course still show the trace to this line, since that’s added as the exception propagates (again).
I am bit confused about the try exception usage in Python 2.7.
try:
raise valueError("sample value error")
except Exception as e:
print str(e)
try:
raise valueError("sample value error")
except Exception,exception:
print str(exception)
try:
raise valueError("sample value error")
except exception:
print str(exception)
try:
raise valueError("sample value error")
except Exception:
print str(Exception) # it prints only the object reference
can some help me to understand the above usage?
Some concepts to help you understand the difference between the alternate variants of the except variants:
except Exception, e – This in an older variant, now deprecated, similar to except Exception as e
except Exception as e – Catch exceptions of the type Exception (or any subclass) and store them in the variable e for further processing, messaging or similar
except Exception – Catch exceptions of the type Exception (or any subclass), but ignore the value/information provided in the exception
except e – Gives me an compilation error, not sure if this related to python version, but if so, it should/would mean that you don't care about the type of exception but want to access the information in it
except – Catch any exception, and ignore the exception information
What to use, depends on many factors, but if you don't need the provided information in the exception there is no need to present the variable to catch this information.
Regarding which type of Exception to catch, take care to catch the accurate type of exceptions. If you are writing a general catch it all, it could be correct to use except Exception, but in the example case you've given I would opt for actually using except ValueError directly. This would allow for potentially other exceptions to be properly handled at another level of your code. The point is, don't catch exception you are not ready to handle.
If you want, you can read more on python 2.7 exception handling or available python 2.7 exception in the official documentation.
For Python 3 (also works in Python 2.7):
try:
raise ValueError("sample value error")
except Exception as e:
print(e)
For Python 2 (will not work in Python 3):
try:
raise ValueError("sample value error")
except Exception, e:
print e
I use:
try:
raise valueError("sample value error")
except Exception as e:
print str(e)
When I want to declare a specific error and
try:
raise valueError("sample value error")
except:
print "Something unexpected happened"
When I don't really care or except: pass , except: return etc
Use the format
try:
raise ValueError("sample value error")
except Exception, e:
print e
How can I get the full stack trace from the Exception object itself?
Consider the following code as reduced example of the problem:
last_exception = None
try:
raise Exception('foo failed')
except Exception as e:
last_exception = e
# this happens somewhere else, decoupled from the original raise
print_exception_stack_trace(last_exception)
Edit: I lied, sorry. e.__traceback__ is what you want.
try:
raise ValueError
except ValueError as e:
print( e.__traceback__ )
>c:/python31/pythonw -u "test.py"
<traceback object at 0x00C964B8>
>Exit code: 0
This is only valid in Python 3; you can't do it in earlier versions.
Given this Python code:
elif request.method == 'DELETE':
try:
os.remove(full_file)
return jsonify({'results':'purged %s' % full_file})
except OSError as e:
if e.errno != errno.ENOENT:
raise
return jsonify({'results':'file not present: %s' % full_file})
I want to test all possible paths, including the exception handling. Using Mock, it's easy enough to raise an exception, which I do with this code:
with patch('os.remove', new=Mock(side_effect=OSError(errno.ENOENT))):
self.assertRaises(OSError, self.app.delete, file_URL) # broken
Mock raises an exception, which has a printed value of 2 (ENOENT) - but e.errno is set to NONE. And so far, I have not found a way to set it. The result is, the exception always gets re-raised, and I never reach the last line of code, in my unit test.
I've also tried creating a dummy class with errno set, and returning that. But unless it has *side_effect* set to be called, it doesn't raise an exception, and when I set side_effect, I don't get the object.errno as a return value.
Is there a way to have Mock raise an Exception, where that Exception object has the errno attribute set?
Pass two arguments to OSError constructor. (First one should be errno).
For example:
>>> OSError(2).errno
>>> OSError(2, 'message').errno
2
>>> OSError(2, 'message').strerror
'message'
I'm using python to evaluate some measured data. Because of many possible results it is difficult to handle or possible combinations. Sometimes an error happens during the evaluation. It is usually an index error because I get out of range from measured data.
It is very difficult to find out on which place in code the problem happened. It would help a lot if I knew on which line the error was raised. If I use following code:
try:
result = evaluateData(data)
except Exception, err:
print ("Error: %s.\n" % str(err))
Unfortunately this only tells me that there is and index error. I would like to know more details about the exception (line in code, variable etc.) to find out what happened. Is it possible?
Thank you.
Solution, printing filename, linenumber, line itself and exception description:
import linecache
import sys
def PrintException():
exc_type, exc_obj, tb = sys.exc_info()
f = tb.tb_frame
lineno = tb.tb_lineno
filename = f.f_code.co_filename
linecache.checkcache(filename)
line = linecache.getline(filename, lineno, f.f_globals)
print 'EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj)
try:
print 1/0
except:
PrintException()
Output:
EXCEPTION IN (D:/Projects/delme3.py, LINE 15 "print 1/0"): integer division or modulo by zero
To simply get the line number you can use sys, if you would like to have more, try the traceback module.
import sys
try:
[][2]
except IndexError:
print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
prints:
Error on line 3
Example from the traceback module documentation:
import sys, traceback
def lumberjack():
bright_side_of_death()
def bright_side_of_death():
return tuple()[0]
try:
lumberjack()
except IndexError:
exc_type, exc_value, exc_traceback = sys.exc_info()
print "*** print_tb:"
traceback.print_tb(exc_traceback, limit=1, file=sys.stdout)
print "*** print_exception:"
traceback.print_exception(exc_type, exc_value, exc_traceback,
limit=2, file=sys.stdout)
print "*** print_exc:"
traceback.print_exc()
print "*** format_exc, first and last line:"
formatted_lines = traceback.format_exc().splitlines()
print formatted_lines[0]
print formatted_lines[-1]
print "*** format_exception:"
print repr(traceback.format_exception(exc_type, exc_value,
exc_traceback))
print "*** extract_tb:"
print repr(traceback.extract_tb(exc_traceback))
print "*** format_tb:"
print repr(traceback.format_tb(exc_traceback))
print "*** tb_lineno:", exc_traceback.tb_lineno
I use the traceback which is simple and robust:
import traceback
try:
raise ValueError()
except:
print(traceback.format_exc()) # or: traceback.print_exc()
Out:
Traceback (most recent call last):
File "catch.py", line 4, in <module>
raise ValueError()
ValueError
The simplest way is just to use:
import traceback
try:
<blah>
except IndexError:
traceback.print_exc()
or if using logging:
import logging
try:
<blah>
except IndexError as e:
logging.exception(e)
Gives you file, lineno, and exception for the last item in the call stack
from sys import exc_info
from traceback import format_exception
def print_exception():
etype, value, tb = exc_info()
info, error = format_exception(etype, value, tb)[-2:]
print(f'Exception in:\n{info}\n{error}')
try:
1 / 0
except:
print_exception()
prints
Exception in:
File "file.py", line 12, in <module>
1 / 0
ZeroDivisionError: division by zero
I would suggest using the python logging library, it has two useful methods that might help in this case.
logging.findCaller()
findCaller(stack_info=False) - Reports just the line number for the previous caller leading to the exception raised
findCaller(stack_info=True) - Reports the line number & stack for the previous caller leading to the exception raised
logging.logException()
Reports the line & stack within the try/except block that raised the exception
For more info checkout the api https://docs.python.org/3/library/logging.html
There are many answers already posted here that show how to get the line number, but it's worth noting that if you want variables containing the "raw data," so to speak, of the stack trace so that you can have more granular control of what you display or how you format it, using the traceback module you can step through the stack frame by frame and look at what's stored in the attributes of the frame summary objects. There are several simple and elegant ways to manipulate the frame summary objects directly. Let's say for example that you want the line number from the last frame in the stack (which tells you which line of code triggered the exception), here's how you could get it by accessing the relevant frame summary object:
Option 1:
import sys
import traceback
try:
# code that raises an exception
except Exception as exc:
exc_type, exc_value, exc_tb = sys.exc_info()
stack_summary = traceback.extract_tb(exc_tb)
end = stack_summary[-1] # or `stack_summary.pop(-1)` if you prefer
Option 2:
import sys
import traceback
try:
# code that raises an exception
except Exception as exc:
tbe = traceback.TracebackException(*sys.exc_info())
end = tbe.stack[-1] # or `tbe.stack.pop(-1)` if you prefer
In either of the above examples, end will be a frame summary object:
>>> type(end)
<class 'traceback.FrameSummary'>
which was in turn taken from a stack summary object:
>>> type(stack_summary) # from option 1
<class 'traceback.StackSummary'>
>>> type(tbe.stack) # from option 2
<class 'traceback.StackSummary'>
The stack summary object behaves like a list and you can iterate through all of the frame summary objects in it however you want in order to trace through the error. The frame summary object (end, in this example), contains the line number and everything else you need to locate where in the code the exception occurred:
>>> print(end.__doc__)
A single frame from a traceback.
- :attr:`filename` The filename for the frame.
- :attr:`lineno` The line within filename for the frame that was
active when the frame was captured.
- :attr:`name` The name of the function or method that was executing
when the frame was captured.
- :attr:`line` The text from the linecache module for the
of code that was running when the frame was captured.
- :attr:`locals` Either None if locals were not supplied, or a dict
mapping the name to the repr() of the variable.
And if you capture the exception object (either from except Exception as exc: syntax or from the second object returned by sys.exc_info()), you will then have everything you need to write your own highly customized error printing/logging function:
err_type = type(exc).__name__
err_msg = str(exc)
Putting it all together:
from datetime import datetime
import sys
import traceback
def print_custom_error_message():
exc_type, exc_value, exc_tb = sys.exc_info()
stack_summary = traceback.extract_tb(exc_tb)
end = stack_summary[-1]
err_type = type(exc_value).__name__
err_msg = str(exc_value)
date = datetime.strftime(datetime.now(), "%B %d, %Y at precisely %I:%M %p")
print(f"On {date}, a {err_type} occured in {end.filename} inside {end.name} on line {end.lineno} with the error message: {err_msg}.")
print(f"The following line of code is responsible: {end.line!r}")
print("Please make a note of it.")
def do_something_wrong():
try:
1/0
except Exception as exc:
print_custom_error_message()
if __name__ == "__main__":
do_something_wrong()
Let's run it!
user#some_machine:~$ python example.py
On August 25, 2022 at precisely 01:31 AM, a ZeroDivisionError occured in example.py inside do_something_wrong on line 21 with the error message: division by zero.
The following line of code is responsible: '1/0'
Please make a note of it.
At this point you can see how you could print this message for any place in the stack: end, beginning, anywhere in-between, or iterate through and print it for every frame in the stack.
Of course, the formatting functionality already provided by the traceback module covers most debugging use cases, but it's useful to know how to manipulate the traceback objects to extract the information you want.
I always use this snippet
import sys, os
try:
raise NotImplementedError("No error")
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno)
for different views and possible issues you can refer When I catch an exception, how do I get the type, file, and line number?
All the solutions answer the OPs problem, however, if one is holding onto a specific error instance and the last traceback stack won't do it they will not suffice —a corner scenario example given below.
In this case, the magic attribute __traceback__ of a raised exception instance may be used. This is a system traceback object (exposed as types.TracebackType, see Types) not the module. This traceback instance behaves just one like would expect (but it is always nice to check):
from collections import deque
from typing import (List, )
errors: List[Exception] = deque([], 5)
def get_raised(error_cls: type, msg: str) -> Exception:
# for debugging, an exception instance that is not raised
# ``__traceback__`` has ``None``
try:
raise error_cls(msg)
except Exception as error:
return error
error = get_raised(NameError, 'foo')
errors.append(error)
error = get_raised(ValueError, 'bar')
errors.append(error)
try:
raise get_raised(TypeError, 'bar')
except Exception as error:
errors.append(error)
Now, I can check out the first error's details:
import types
traceback = errors[0].__traceback__ # inadvisable name due to module
line_no: int = traceback.tb_lineno
frame: types.FrameType = traceback.tb_frame
previous: Union[type(None), types.TracebackType] = traceback.tb_next
filename: str = frame.f_code.co_filename
The traceback's previous is None for the second error despite a preceding error as expected, but for the third wherein an error is raised twice it is not.
This below is just a test which makes no sense contextually. A case were it is useful if when an exception is raised in a view of a webapp (a 500 status kind of incident) that gets caught and stored for the admit to inspect akin to Setry.io (but for free). Here is a minimal example where the home page / will raise an error, that gets caught and the route errors will list them. This is using Pyramid in a very concentrated way (multifile is way better) with no logging or authentication and the error logging could be better for the admin to inspect similar to Sentry.io.
from pyramid.config import Configurator
from waitress import serve
from collections import deque
# just for typehinting:
from pyramid.request import Request
from pyramid.traversal import DefaultRootFactory
from pyramid.router import Router
import types
from typing import (List, )
def home_view(context: DefaultRootFactory, request: Request) -> dict:
raise NotImplementedError('I forgot to fill this')
return {'status': 'ok'} # never reached.
def caught_view(error: Exception, request: Request) -> dict:
"""
Exception above is just type hinting.
This is controlled by the context argument in
either the ``add_exception_view`` method of config,
or the ``exception_view_config`` decorator factory (callable class)
"""
# this below is a simplification as URLDecodeError is an attack (418)
request.response.status = 500
config.registry.settings['error_buffer'].append(error)
#logging.exception(error) # were it set up.
#slack_admin(format_error(error)) # ditto
return {'status': 'error', 'message': 'The server crashed!!'}
def format_error(error: Exception) -> str:
traceback = error.__traceback__ # inadvisable name due to module
frame: types.FrameType = traceback.tb_frame
return f'{type(error).__name__}: {error}' +\
f'at line {traceback.tb_lineno} in file {frame.f_code.co_filename}'
def error_view(context: DefaultRootFactory, request: Request) -> dict:
print(request.registry.settings['error_buffer'])
return {'status': 'ok',
'errors':list(map(format_error, request.registry.settings['error_buffer']))
}
with Configurator(settings=dict()) as config:
config.add_route('home', '/')
config.add_route('errors', '/errors')
config.add_view(home_view, route_name='home', renderer='json')
config.add_view(error_view, route_name='errors', renderer='json')
config.add_exception_view(caught_view, context=Exception, renderer='json')
config.registry.settings['error_buffer']: List[Exception] = deque([], 5)
# not in config.registry.settings, not JSON serialisable
# config.add_request_method
app : Router = config.make_wsgi_app()
port = 6969
serve(app, port=port)