Change default behavior of uncaught exception handling in python - python

I went through "Logging uncaught exceptions in Python". And, I have tried this:
import web
import sys
app = web.application((
'/test', 'test'), globals())
def test_func(e_type, value, traceback):
print "Handled exception here.."
class test:
def GET(self):
a = 1/0
if __name__ == "__main__":
sys.excepthook = test_func
app.run()
Here, you can easily see if GET /test request comes in, I am deliberately raising ZerDivisionError. As i have overriden sys.excepthook, I expect method test_func to execute on ZeroDivisionError.
Whereas, this piece of code is not working as per expectation. I have observed that when i try to override excepthook in standalone code (not in web-app), it works fine. New method(overriden) is called properly.
Any idea why is this different behavior ?

Using web.py, one way of catching exceptions yourself would be to add a custom processor:
...
def error_processor(handler):
try:
handler()
except:
# do something reasonable to handle the exception
return 'something happened...'
app.add_processor(error_processor)
app.run()
...
Otherwise web.py will catch the exception and show a default error message instead.

Python doc says
sys.excepthook(type, value, traceback)
This function prints out a given traceback and exception to sys.stderr.
So this sys.excepthook is called when a exception needs to printed to terminal. Now you see, web.py itself handles the exceptions. If you dont assign the sys.excepthook, webpy captures the exception and shows the exception in browser. And as web.py is itself handling the exceptions, setting sys.excepthook makes no change.
If web.py didn't handle the exception itself, then it would be uncaught and sys.excepthook would be called.
If you really want to handle exception yourself in this code, try searching web.py doc and source code to figure out how web.py handles exceptions and customize that.
python doc also says
sys.__excepthook__
These objects contain the original values of displayhook and excepthook at the start of the program. They are saved so that displayhook and excepthook can be restored in case they happen to get replaced with broken objects.
So my guess is web.py using that, so your custom handler is not called.

Related

How to display an error message in mpl_connect() callback function

My understanding is that: Normally, when an error happens, it's thrown down through all the calling functions, and then displayed in the console. Now there's some packages that do their own error handling, especially GUI related packages often don't show errors at all but just continue excecution.
How can we override such behaviour in general? When I write GUI functions, I would like to see the errors! I found this post where it's explained how to do it for the case of Tkinter. How can this be done in Matplotlib?
Example code:
import matplotlib.pyplot as plt
def onclick(event):
print(event.x, event.y)
raise ValueError('SomeError') # this error is thrown but isn't displayed
fig = plt.figure(5)
fig.clf()
try: # if figure was open before, try to disconnect the button
fig.canvas.mpl_disconnect(cid_button)
except:
pass
cid_button = fig.canvas.mpl_connect('button_press_event', onclick)
Indeed, when the python interpreter encounters an exception that is never caught, it will print a so-called traceback to stdout before exciting. However, GUI packages usually catch and swallow all exceptions, in order to prevent the python interpreter from exciting. You would like to display that traceback somewhere, but in case of GUI applications, you will have to decide where to show that traceback. The standard library has a module that helps you working with such traceback, aptly named traceback. Then, you will have to catch the exception before the GUI toolkit does it. I do not know a general way to insert a callback error handler, but you can manually add error handling to each of your callbacks. The best way to do this is to write a function decorator that you then apply to your callback.
import traceback, functools
def print_errors_to_stdout(fun):
#functools.wraps(fun)
def wrapper(*args,**kw):
try:
return fun(*args,**kw)
except Exception:
traceback.print_exc()
raise
return wrapper
#print_errors_to_stdout
def onclick(event):
print(event.x, event.y)
raise ValueError('SomeError')
The decorator print_errors_to_stdout takes a function and returns a new function that embeds the original function in a try ... except block and in case of an exception prints the traceback to stdout with the help of traceback.print_exc(). (The wrapper itself is decorated with functools.wraps such that the generated wrapper function, among other things, keeps the docstring of the original function). If you would like to show the traceback somewhere else traceback.format_exc() would give you a string that you could then show/store somwhere. The decorator also reraises the exception, such that the GUI toolkit still gets a chance to take it's own actions, typically just swallowing the exception.

exceptions raised from within a urlfetch callback

When performing async urlfetch calls with a callback and inside a tasklet, it seems that exceptions raised from within the callback don't propagate to the wrapping tasklet.
Example code:
def cb() :
raise Exception, 'just a test'
rpc = urlfetch.create_rpc(callback = cb)
#ndb.tasklet
def t() :
try :
response = yield urlfetch.make_fetch_call(rpc, 'http://...')
except :
print 'an error occured'
raise ndb.Return
t().get_result()
In the code above, executed by the dev server, the "just a test" exception doesn't get caught inside the tasklet; ie. instead of the error message being output to the console i'm getting the "just a test" exception reported.
If there's a generic urlfetch exception related to the make_fetch_call (such as DownloadError in case of a bad URL), it's being handled properly.
Is there a way to catch callback-generated exceptions inside the tasklet in such a situation? Or maybe should this behavior be considered a bug?
Thanks.
I've created a sample project to illustrate the correct way to do this.
While reading the code, you'll find a lot of benefit from reading the comments and also cross-referencing with the docs on tasklets and rpc.make_fetch_call().
Some of the confusing aspects of this were the fact that ndb tasklets actually use Exceptions to indicate return values (even if successful, you should raise ndb.Return (True), making exception handling difficult to tiptoe around), and the fact that exceptions in the callback needs to be caught when we call wait() on the rpc future object returned by t(), while exceptions in the url fetch need to be caught inside t() itself when we do yield rpc.make_fetch_call(). There may be a way to do the latter using rpc.check_success(), but that'll be up to your hacking to figure out.
I hope you find the source helpful, and I hope you learned a lesson about avoiding using exceptions to indicate that a generator is done...

How to get mail report about all unhandled exceptions inside of twisted server?

I'm initialize 2 servers in one twisted script. So I want to get all unhadled exception inside of it on my mail. Is it posible?
Thank you!
You can use sys.excepthook. sys.excepthook catches all exceptions that are uncaught in your code. How you handle them from there is your choice.
For sending emails, you may be interested in the Python email module. Here are some examples.
You can reconstruct a traceback from an exception using the Python traceback module; specifically format_exception().
import sys
import traceback
def excepthook(type_, value, tb):
# do whatever with the exception information
# you want to do here
exception = traceback.format_exception(type_, value, tb)
print ''.join(exception)
sys.excepthook = excepthook
Note: I don't know anything about twisted, so there may be a twisted way (pun not intended) to do this, however, this is how I would do it if there was no other official way of course.

python logging in django

I am using the basic python logger in django and it seems to be workng well. I have the logging setup in my setting.py as;
logging.baseConfig(level = logging.NOTSET,
format='a format',
datemt=' a datefmt',
filename='path to log',
filemode = 'a')
logging.getLogger('').setLevel(logging.NOTSET)
My question is with regard to propagating exceptions. In my code if I have a try/except clause and catch the exception so I can log it, what is the best way to then propagate that error so that I can redirect to my 500 page. I have been using
try:
do stuff
except Exception, e:
logging.error(e)
raise
but I find that this causes the exeption to be logged twice. Is there another way to do this or am I doing something wrong?
Regards
Andrew
There's no need to catch the exception just so you can log it. You can log it and handle it, or else let it bubble up to some higher level which will log it and handle it. If you want to log exceptions which occur in some view, which you don't want to handle, then you can install some exception middleware which logs the exception and either returns a custom response which you determine, or None (to return whatever response Django would normally return).
There's an example of extensible exception middleware here, which doesn't actually use logging but whose log_exception() method you could subclass to log the exception, or just use that snippet as a guide to provide your own exception middleware - it's basically just a class with a method called process_exception:
class MyExceptionMiddleware:
def process_exception(self, request, exception):
#Do your logging here
Also, note that loggers have an exception() method which works like error() but includes traceback information in the log.
There's a recipe: http://code.activestate.com/recipes/466332/
In any somewhat complex application, you likely want to log and handle most exceptions. The recipe shows a way to separate logging from handling, so that it is not necessary to explicitly invoke the logging mechanism in each try-except clause.

How to display errors to the user while still logging it?

I'm using a PyQt4 user interface. I've redirected stderr to a log file for easy debugging and trouble-shooting, but now I need to display error messages to the user when an error occurs.
My issue is that I need to catch an exception when it happens and let the user know that it happened, but still let the traceback propagate to stderr (i.e. the log file).
If I do something like this:
def updateResults(self):
try:
#code that updates the results
except:
#display error message box
This will catch the exception and not propogate to the error log.
Is there some way to show the user the message and then continue to propogate the error?
Would this work?
except, e:
#display error message box
raise e
Is there a better way to accomplish my goal?
I think you are thinking about this in the wrong way. You shouldn't be re-raising the error simply to log it further down the line. The cannonical way of doing this in Python is to use the logging module. Adapted from the docs:
import logging
LOG_FILENAME = '/tmp/logging_example.out'
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,)
...
try:
# code
except:
logging.debug('Something bad happened', exc_info=True)
# display message box
# raise (if necessary)
This gives a far more flexible logging system than relying on errors produced on sys.stdout. You may not need to re-raise the exception if you can recover from the exception in some way.
Exactly, but you can just
raise
which will re-raise the currently handled exception.
Some additional information:
(With PyQt4) you will also need to rebind sys.excepthook to your own function to catch all uncaught exceptions. Otherwise PyQt will just print them to the console, which may not be what you need...
import sys
def excepthook(exc_type, exc_val, tracebackobj):
# do something useful with the uncaught exception
...
def main():
# rebind excepthook
sys.excepthook = excepthook
...

Categories