Merge pull request #1431 from untitaker/flask-errorhandling-amend

Some cleanup for errorhandling refactor
This commit is contained in:
Markus Unterwaditzer 2015-04-12 00:06:57 +02:00
commit aaebe9fe25
2 changed files with 105 additions and 97 deletions

View file

@ -14,7 +14,7 @@ from threading import Lock
from datetime import timedelta from datetime import timedelta
from itertools import chain from itertools import chain
from functools import update_wrapper from functools import update_wrapper
from collections import Mapping from collections import Mapping, deque
from werkzeug.datastructures import ImmutableDict from werkzeug.datastructures import ImmutableDict
from werkzeug.routing import Map, Rule, RequestRedirect, BuildError from werkzeug.routing import Map, Rule, RequestRedirect, BuildError
@ -1412,26 +1412,36 @@ class Flask(_PackageBoundObject):
""" """
exc_class, code = self._get_exc_class_and_code(type(e)) exc_class, code = self._get_exc_class_and_code(type(e))
def find_superclass(handler_map): def find_handler(handler_map):
if not handler_map: if not handler_map:
return None return
for superclass in exc_class.__mro__: queue = deque(exc_class.__mro__)
if superclass is BaseException: # Protect from geniuses who might create circular references in
return None # __mro__
handler = handler_map.get(superclass) done = set()
while True:
cls = queue.popleft()
if cls in done:
continue
done.add(cls)
handler = handler_map.get(cls)
if handler is not None: if handler is not None:
handler_map[exc_class] = handler # cache for next time exc_class is raised # cache for next time exc_class is raised
handler_map[exc_class] = handler
return handler return handler
return None
queue.extend(cls.__mro__)
# try blueprint handlers # try blueprint handlers
handler = find_superclass(self.error_handler_spec.get(request.blueprint, {}).get(code)) handler = find_handler(self.error_handler_spec
.get(request.blueprint, {})
.get(code))
if handler is not None: if handler is not None:
return handler return handler
# fall back to app handlers # fall back to app handlers
return find_superclass(self.error_handler_spec[None].get(code)) return find_handler(self.error_handler_spec[None].get(code))
def handle_http_exception(self, e): def handle_http_exception(self, e):
"""Handles an HTTP exception. By default this will invoke the """Handles an HTTP exception. By default this will invoke the

View file

@ -37,7 +37,6 @@ def test_error_handler_subclass():
def registered_test(): def registered_test():
raise ChildExceptionRegistered() raise ChildExceptionRegistered()
c = app.test_client() c = app.test_client()
assert c.get('/parent').data == b'parent' assert c.get('/parent').data == b'parent'
@ -76,7 +75,6 @@ def test_error_handler_http_subclass():
def unregistered_test(): def unregistered_test():
raise ForbiddenSubclassUnregistered() raise ForbiddenSubclassUnregistered()
c = app.test_client() c = app.test_client()
assert c.get('/forbidden').data == b'forbidden' assert c.get('/forbidden').data == b'forbidden'