Added support for generic HTTPException handlers on app and blueprints

Error handlers are now returned in order of blueprint:code, app:code,
blueprint:HTTPException, app:HTTPException, None

Corresponding tests also added.

Ref issue #941, pr #1383, #2082, #2144
This commit is contained in:
cerickson 2017-05-22 15:57:31 -07:00
parent 668061a5fc
commit 4f815015b8
2 changed files with 69 additions and 44 deletions

View file

@ -133,6 +133,8 @@ class Flask(_PackageBoundObject):
:param static_folder: the folder with static files that should be served
at `static_url_path`. Defaults to the ``'static'``
folder in the root path of the application.
folder in the root path of the application. Defaults
to None.
:param host_matching: sets the app's ``url_map.host_matching`` to the given
given value. Defaults to False.
:param static_host: the host to use when adding the static route. Defaults
@ -1460,15 +1462,17 @@ class Flask(_PackageBoundObject):
return f
def _find_error_handler(self, e):
"""Finds a registered error handler for the requests blueprint.
Otherwise falls back to the app, returns None if not a suitable
handler is found.
"""Find a registered error handler for a request in this order:
blueprint handler for a specific code, app handler for a specific code,
blueprint generic HTTPException handler, app generic HTTPException handler,
and returns None if a suitable handler is not found.
"""
exc_class, code = self._get_exc_class_and_code(type(e))
def find_handler(handler_map):
if not handler_map:
return
for cls in exc_class.__mro__:
handler = handler_map.get(cls)
if handler is not None:
@ -1476,24 +1480,13 @@ class Flask(_PackageBoundObject):
handler_map[exc_class] = handler
return handler
# try blueprint handlers
handler = find_handler(self.error_handler_spec
.get(request.blueprint, {})
.get(code))
if handler is not None:
return handler
# check for any in blueprint or app
for name, c in ((request.blueprint, code), (None, code),
(request.blueprint, None), (None, None)):
handler = find_handler(self.error_handler_spec.get(name, {}).get(c))
# fall back to app handlers
handler = find_handler(self.error_handler_spec[None].get(code))
if handler is not None:
return handler
try:
handler = find_handler(self.error_handler_spec[None][None])
except KeyError:
handler = None
return handler
if handler:
return handler
def handle_http_exception(self, e):
"""Handles an HTTP exception. By default this will invoke the