mirror of https://github.com/pallets/flask.git
				
				
				
			Merge pull request #2314 from cerickson/errorhandler
Added support for generic HTTPException handlers on app and blueprints
This commit is contained in:
		
						commit
						e206764955
					
				
							
								
								
									
										22
									
								
								flask/app.py
								
								
								
								
							
							
						
						
									
										22
									
								
								flask/app.py
								
								
								
								
							| 
						 | 
					@ -1460,15 +1460,17 @@ class Flask(_PackageBoundObject):
 | 
				
			||||||
        return f
 | 
					        return f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _find_error_handler(self, e):
 | 
					    def _find_error_handler(self, e):
 | 
				
			||||||
        """Finds a registered error handler for the request’s blueprint.
 | 
					        """Find a registered error handler for a request in this order:
 | 
				
			||||||
        Otherwise falls back to the app, returns None if not a suitable
 | 
					        blueprint handler for a specific code, app handler for a specific code,
 | 
				
			||||||
        handler is found.
 | 
					        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))
 | 
					        exc_class, code = self._get_exc_class_and_code(type(e))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def find_handler(handler_map):
 | 
					        def find_handler(handler_map):
 | 
				
			||||||
            if not handler_map:
 | 
					            if not handler_map:
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for cls in exc_class.__mro__:
 | 
					            for cls in exc_class.__mro__:
 | 
				
			||||||
                handler = handler_map.get(cls)
 | 
					                handler = handler_map.get(cls)
 | 
				
			||||||
                if handler is not None:
 | 
					                if handler is not None:
 | 
				
			||||||
| 
						 | 
					@ -1476,15 +1478,13 @@ class Flask(_PackageBoundObject):
 | 
				
			||||||
                    handler_map[exc_class] = handler
 | 
					                    handler_map[exc_class] = handler
 | 
				
			||||||
                    return handler
 | 
					                    return handler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # try blueprint handlers
 | 
					        # check for any in blueprint or app
 | 
				
			||||||
        handler = find_handler(self.error_handler_spec
 | 
					        for name, c in ((request.blueprint, code), (None, code),
 | 
				
			||||||
                               .get(request.blueprint, {})
 | 
					                        (request.blueprint, None), (None, None)):
 | 
				
			||||||
                               .get(code))
 | 
					            handler = find_handler(self.error_handler_spec.get(name, {}).get(c))
 | 
				
			||||||
        if handler is not None:
 | 
					 | 
				
			||||||
            return handler
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # fall back to app handlers
 | 
					            if handler:
 | 
				
			||||||
        return find_handler(self.error_handler_spec[None].get(code))
 | 
					                return handler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,10 @@
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
from werkzeug.exceptions import Forbidden, InternalServerError
 | 
					from werkzeug.exceptions import (
 | 
				
			||||||
 | 
					    Forbidden,
 | 
				
			||||||
 | 
					    InternalServerError,
 | 
				
			||||||
 | 
					    HTTPException,
 | 
				
			||||||
 | 
					    NotFound
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
import flask
 | 
					import flask
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,3 +143,53 @@ def test_error_handler_blueprint():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert c.get('/error').data == b'app-error'
 | 
					    assert c.get('/error').data == b'app-error'
 | 
				
			||||||
    assert c.get('/bp/error').data == b'bp-error'
 | 
					    assert c.get('/bp/error').data == b'bp-error'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_default_error_handler():
 | 
				
			||||||
 | 
					    bp = flask.Blueprint('bp', __name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @bp.errorhandler(HTTPException)
 | 
				
			||||||
 | 
					    def bp_exception_handler(e):
 | 
				
			||||||
 | 
					        assert isinstance(e, HTTPException)
 | 
				
			||||||
 | 
					        assert isinstance(e, NotFound)
 | 
				
			||||||
 | 
					        return 'bp-default'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @bp.errorhandler(Forbidden)
 | 
				
			||||||
 | 
					    def bp_exception_handler(e):
 | 
				
			||||||
 | 
					        assert isinstance(e, Forbidden)
 | 
				
			||||||
 | 
					        return 'bp-forbidden'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @bp.route('/undefined')
 | 
				
			||||||
 | 
					    def bp_registered_test():
 | 
				
			||||||
 | 
					        raise NotFound()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @bp.route('/forbidden')
 | 
				
			||||||
 | 
					    def bp_forbidden_test():
 | 
				
			||||||
 | 
					        raise Forbidden()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    app = flask.Flask(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @app.errorhandler(HTTPException)
 | 
				
			||||||
 | 
					    def catchall_errorhandler(e):
 | 
				
			||||||
 | 
					        assert isinstance(e, HTTPException)
 | 
				
			||||||
 | 
					        assert isinstance(e, NotFound)
 | 
				
			||||||
 | 
					        return 'default'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @app.errorhandler(Forbidden)
 | 
				
			||||||
 | 
					    def catchall_errorhandler(e):
 | 
				
			||||||
 | 
					        assert isinstance(e, Forbidden)
 | 
				
			||||||
 | 
					        return 'forbidden'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @app.route('/forbidden')
 | 
				
			||||||
 | 
					    def forbidden():
 | 
				
			||||||
 | 
					        raise Forbidden()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    app.register_blueprint(bp, url_prefix='/bp')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c = app.test_client()
 | 
				
			||||||
 | 
					    assert c.get('/bp/undefined').data == b'bp-default'
 | 
				
			||||||
 | 
					    assert c.get('/bp/forbidden').data == b'bp-forbidden'
 | 
				
			||||||
 | 
					    assert c.get('/undefined').data == b'default'
 | 
				
			||||||
 | 
					    assert c.get('/forbidden').data == b'forbidden'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue