So now here we are, having tried to
handle errors in Google App Engine...and failed
all because silly
Exception in the inheritance chain and goes right for
How can we catch these in our handlers while staying
First and foremost, in the case of a timeout, we need to explicitly
DeadlineExceededError. To do so, we can use a
(hey, that's Pythonic) in each and every handler for each and every HTTP
a bunch of code is about to happen. See the necessary imports
at the bottom of the post.)
def deadline_decorator(method): def wrapped_method(self, *args, **kwargs): try: method(self, *args, **kwargs) except DeadlineExceededError: traceback_info = ''.join(format_exception(*sys.exc_info())) email_admins(traceback_info, defer_now=True) serve_500(self) return wrapped_method
Unfortunately, having to manually decorate all the functions is not so Pythonic. At this point I was stuck and wanted to give up, but asked for some advice on G+ and actually got what I needed from the all knowing Ali Afshar. What did I need?
Before showing the super simple metaclass I wrote, you need to know one thing from StackOverflow user Kevin Samuel:
The main purpose of a metaclass is to change the class automatically, when it's created.
object in Python actually constructs a class (which is also an object)
by taking into account the name of the class, the parents (or bases) and
the class attritubutes. So, we can make a metaclass by subclassing
type and overriding
class DecorateHttpVerbsMetaclass(type): def __new__(cls, name, bases, cls_attr): verbs = ['get', 'post', 'put', 'delete'] for verb in verbs: if verb in cls_attr and isinstance(cls_attr[verb], function): cls_attr[verb] = deadline_decorator(cls_attr[verb]) return super(DecorateHttpVerbsMetaclass, cls).__new__(cls, name, bases, cls_attr)
we look for four (of the nine) HTTP
because heck, only seven are supported in
and we're not that crazy. If the class has one of the verbs as an
attribute and if the attribute is a function, we
decorate it with
Now, we can rewrite our subclass of
with one extra line:
class ExtendedHandler(RequestHandler): __metaclass__ = DecorateHttpVerbsMetaclass def handle_exception(self, exception, debug_mode): traceback_info = ''.join(format_exception(*sys.exc_info())) email_admins(traceback_info, defer_now=True) serve_500(self)
By doing this, when the class
is built (as an object), all of its attributes and all of its
parent classes (or bases) attributes are checked and possibly updated by
And now you and James Nekbehrd can feel like a boss when your app handles errors.
from google.appengine.api import mail from google.appengine.ext.deferred import defer from google.appengine.ext.webapp import RequestHandler from google.appengine.runtime import DeadlineExceededError import sys from traceback import format_exception from SOME_APP_SPECIFIC_LIBRARY import serve_500 from LAST_POST import email_admins
An idea or piece of code which closely follows the most common idioms of the Python language, rather than implementing code using concepts common to other languages.
grep -r "Exception)" . | grep "class "I have convinced myself (for now) that the only errors App Engine will throw that do not inherit from
KeyboardInterruptso that is why I only catch the timeout.
You can also use
webapp2to catch 500 errors, even when
handle_exceptionfails to catch them.
Disclaimer: Just because you know what a metaclass is doesn't mean you should use one.
- "Don't do stuff like this though, what is your use case?" - Ali Afshar
- "Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why)." - Python Guru Tim Peters
- "The main use case for a metaclass is creating an API." -Kevin Samuel