diff --git a/doctor/flask.py b/doctor/flask.py index a9b9e02..4c0e5a0 100644 --- a/doctor/flask.py +++ b/doctor/flask.py @@ -3,8 +3,8 @@ import logging try: - from flask import request - from flask.ext import restful + import flask_restful + from flask import current_app, request from werkzeug.exceptions import (BadRequest, Conflict, Forbidden, HTTPException, NotFound, Unauthorized, InternalServerError) @@ -80,7 +80,7 @@ def handle_http(schema, handler, args, kwargs, logic, request_schema, :param doctor.resource.ResourceSchema schema: Instance of a :class:`~doctor.resource.ResourceSchema` class. - :param handler: flask.ext.restful.Resource: An instance of a Flask Restful + :param handler: flask_restful.Resource: An instance of a Flask Restful resource class. :param tuple args: Any positional arguments passed to the wrapper method. :param dict kwargs: Any keyword arguments passed to the wrapper method. @@ -142,11 +142,14 @@ def handle_http(schema, handler, args, kwargs, logic, request_schema, except ImmutableError as e: raise HTTP409Exception(unicode(e)) except Exception as e: + # Always re-raise exceptions when DEBUG is enabled for development. + if current_app.config.get('DEBUG', False): + raise if allowed_exceptions and any(isinstance(e, cls) for cls in allowed_exceptions): raise logging.exception(unicode(e)) - raise HTTP500Exception('Uncaught doctor error') + raise HTTP500Exception('Uncaught error in logic function') class FlaskResourceSchema(ResourceSchema): @@ -174,7 +177,7 @@ def __init__(self, schema_dir, resource_schema_class=None, if resource_schema_class is None: resource_schema_class = FlaskResourceSchema if default_base_handler is None: - default_base_handler = restful.Resource + default_base_handler = flask_restful.Resource super(FlaskRouter, self).__init__( schema_dir, resource_schema_class, default_base_handler, raise_response_validation_errors) diff --git a/examples/flask/app.py b/examples/flask/app.py index dfee0d2..efd298d 100644 --- a/examples/flask/app.py +++ b/examples/flask/app.py @@ -5,7 +5,7 @@ import os from flask import Flask -from flask.ext.restful import Api +from flask_restful import Api from doctor.errors import NotFoundError from doctor.flask import FlaskRouter diff --git a/setup.py b/setup.py index 487b2fe..0817024 100644 --- a/setup.py +++ b/setup.py @@ -46,7 +46,7 @@ 'coverage >= 3.5.2, < 4.0.0', 'flake8 >= 2.4.0, < 3.0.0', 'flask >= 0.10.1, < 1.0.0', - 'flask-restful==0.2.12', + 'flask-restful==0.3.5', 'mock >= 1.0.1, < 2.0.0', 'nose >= 1.3.4, < 2.0.0', 'nose-exclude >= 0.1.9, < 1.0.0', diff --git a/test/test_flask.py b/test/test_flask.py index a3056cd..7e072a5 100644 --- a/test/test_flask.py +++ b/test/test_flask.py @@ -224,13 +224,23 @@ def test_handle_not_found_error(self): with self.assertRaisesRegexp(HTTP404Exception, r'404'): self.call_handle_http() - def test_handle_unexpected_error(self): + @mock.patch('doctor.flask.current_app') + def test_handle_unexpected_error(self, mock_current_app): + mock_current_app.config = {'DEBUG': False} self.mock_logic_exception(TypeError('bad type')) with self.assertRaisesRegexp( - HTTP500Exception, r'Uncaught doctor error'): + HTTP500Exception, r'Uncaught error in logic function'): self.call_handle_http() - def test_handle_unexpected_error_allowed_exceptions(self): + # When DEBUG is True, it should reraise the original exception + mock_current_app.config = {'DEBUG': True} + with self.assertRaisesRegexp(TypeError, 'bad type'): + self.call_handle_http() + + @mock.patch('doctor.flask.current_app') + def test_handle_unexpected_error_allowed_exceptions(self, mock_current_app): + mock_current_app.config = {'DEBUG': False} + class ExceptionalException(Exception): pass self.allowed_exceptions = [ExceptionalException] @@ -244,5 +254,5 @@ class ExceptionalException(Exception): # but other exceptions should still be caught self.mock_logic_exception(TypeError('bad type')) with self.assertRaisesRegexp( - HTTP500Exception, r'Uncaught doctor error'): + HTTP500Exception, r'Uncaught error in logic function'): self.call_handle_http()