Python global exception handling
You could change sys.excepthook
if you really don't want to use a try/except
.
import sys
def my_except_hook(exctype, value, traceback):
if exctype == KeyboardInterrupt:
print "Handler code goes here"
else:
sys.__excepthook__(exctype, value, traceback)
sys.excepthook = my_except_hook
Global error handler for any exception
You can use @app.errorhandler(Exception)
:
Demo (the HTTPException check ensures that the status code is preserved):
from flask import Flask, abort, jsonify
from werkzeug.exceptions import HTTPException
app = Flask('test')
@app.errorhandler(Exception)
def handle_error(e):
code = 500
if isinstance(e, HTTPException):
code = e.code
return jsonify(error=str(e)), code
@app.route('/')
def index():
abort(409)
app.run(port=1234)
Output:
$ http get http://127.0.0.1:1234/
HTTP/1.0 409 CONFLICT
Content-Length: 31
Content-Type: application/json
Date: Sun, 29 Mar 2015 17:06:54 GMT
Server: Werkzeug/0.10.1 Python/3.4.3
{
"error": "409: Conflict"
}
$ http get http://127.0.0.1:1234/notfound
HTTP/1.0 404 NOT FOUND
Content-Length: 32
Content-Type: application/json
Date: Sun, 29 Mar 2015 17:06:58 GMT
Server: Werkzeug/0.10.1 Python/3.4.3
{
"error": "404: Not Found"
}
If you also want to override the default HTML exceptions from Flask (so that they also return JSON), add the following before app.run
:
from werkzeug.exceptions import default_exceptions
for ex in default_exceptions:
app.register_error_handler(ex, handle_error)
For older Flask versions (<=0.10.1, i.e. any non-git/master version at the moment), add the following code to your application to register the HTTP errors explicitly:
from werkzeug import HTTP_STATUS_CODES
for code in HTTP_STATUS_CODES:
app.register_error_handler(code, handle_error)
Flask global exception handling
I tend to set up an error handler on the app that formats the exception into a json response. Then you can create custom exceptions like UnauthorizedException...
class Unauthorized(Exception):
status_code = 401
@app.errorhandler(Exception)
def _(error):
trace = traceback.format_exc()
status_code = getattr(error, 'status_code', 400)
response_dict = dict(getattr(error, 'payload', None) or ())
response_dict['message'] = getattr(error, 'message', None)
response_dict['traceback'] = trace
response = jsonify(response_dict)
response.status_code = status_code
traceback.print_exc(file=sys.stdout)
return response
You can also handle specific exceptions using this pattern...
@app.errorhandler(ValidationError)
def handle_validation_error(error):
# Do something...
Error handlers get attached to the app, not the apimanager. You probably have something like
app = Flask()
apimanager = ApiManager(app)
...
Put this somewhere using that app object.
Global error handling for a better KeyError treatment
Here is the solution I used right now, since we can't override the builtins.
class LXKeyError(KeyError):
def __init__(self, item, d):
self.item = item
self.d = d
def __str__(self):
keys = str(list(self.d.keys()))
if len(keys) > 1000: # (13 (max field length in uf) + 4 ("', '")) * 50 (max number of fields we want to print) = 850
keys = f'{keys[:995]} ...'
return f'Unknown key in dict: {self.item!r} (keys: {keys})'
class LXDict(dict):
def __missing__(self, key):
raise LXKeyError(key, self)
Test:
orig_d = {'a': 'a', 'b': 'b', '1': '', '2': '', '3': '', '4': '', '5': '', '6': '', '7': '', '8': '', '9': '', '10': '', '11': '', '12': '',
'13': '', '14': '', '15': '', '16': '', '17': '', '18': '', '19': '', '20': '',
}
d = LXDict(orig_d)
try:
d['x']
assert False, f'Should not arrive here'
except KeyError as ex:
print(ex)
Catch `Exception` globally in FastAPI
In case you want to capture all unhandled exceptions (internal server error), there's a very simple way of doing it. Documentation
from fastapi import FastAPI
from starlette.requests import Request
from starlette.responses import Response
app = FastAPI()
async def catch_exceptions_middleware(request: Request, call_next):
try:
return await call_next(request)
except Exception:
# you probably want some kind of logging here
return Response("Internal server error", status_code=500)
app.middleware('http')(catch_exceptions_middleware)
Make sure you place this middleware before everything else.
Global Exception Handling in Google App Engine
If you're using the webapp framework, you should already be defining a subclass of RequestHandler that serves as a base class, with all your app's handlers extending that. You can simply override handle_exception, which serves as a global exception handler for any uncaught exceptions.
The default implementation calls self.error(500), logs the exception, and if debug is on, outputs a stacktrace.
If you're using another framework, you could write a piece of WSGI middleware that calls the wrapped WSGI app, and catches any thrown exceptions, dealing with them as you wish.
Exceptions for the whole class
Write one or more exception handler functions that, given a function and the exception raised in it, does what you want to do (e.g. displays an alert). If you need more than one, write them.
def message(func, e):
print "Exception", type(e).__name__, "in", func.__name__
print str(e)
Now write a decorator that applies a given handler to a called function:
import functools
def handle_with(handler, *exceptions):
try:
handler, cleanup = handler
except TypeError:
cleanup = lambda f, e: None
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except exceptions or Exception as e:
return handler(func, e)
else:
e = None
finally:
cleanup(func, e)
return wrapper
return decorator
This only captures the exceptions you specify. If you don't specify any, Exception
is caught. Additionally, the first argument can be a tuple (or other sequence) of two handler functions; the second handler, if given, is called in a finally
clause. The value returned from the primary handler is returned as the value of the function call.
Now, given the above, you can write:
@handle_with(message, TypeError, ValueError)
def add(x, y):
return x + y
You could also do this with a context manager:
from contextlib import contextmanager
@contextmanager
def handler(handler, *exceptions):
try:
handler, cleanup = handler
except TypeError:
cleanup = lambda e: None
try:
yield
except exceptions or Exception as e:
handler(e)
else:
e = None
finally:
cleanup(e)
Now you can write:
def message(e):
print "Exception", type(e).__name__
print str(e)
def add(x, y):
with handler(message, TypeError, ValueError):
return x + y
Note that the context manager doesn't know what function it's in (you can find this out, sorta, using inspect
, though this is "magic" so I didn't do it) so it gives you a little less useful information. Also, the context manager doesn't give you the opportunity to return anything in your handler.
Related Topics
Sqlalchemy Create_All() Does Not Create Tables
Cast Base Class to Derived Class Python (Or More Pythonic Way of Extending Classes)
Python String 'Join' Is Faster () Than '+', But What's Wrong Here
Syntaxerror: Multiple Statements Found While Compiling a Single Statement
Full Examples of Using Pyserial Package
Matplotlib: Overlay Plots with Different Scales
How to Capture Output of Python's Interpreter and Show in a Text Widget
Time Complexity of String Slice
Scrollbar on Matplotlib Showing Page
How to Increment a Shared Counter from Multiple Processes
Download Image with Selenium Python
Python and Beautifulsoup Encoding Issues
Change the Colors Within Certain Range to Another Color Using Opencv
How to Change Plot Background Color
Assignment Inside Lambda Expression in Python
In Django - Model Inheritance - Does It Allow You to Override a Parent Model's Attribute