diff --git a/CHANGES b/CHANGES index 8311e2e7..dbf447db 100644 --- a/CHANGES +++ b/CHANGES @@ -45,6 +45,9 @@ Relase date to be decided, codename to be chosen. - The :meth:`flask.render_template` method now accepts a either an iterable of template names or a single template name. Previously, it only accepted a single template name. On an iterable, the first template found is rendered. +- View functions can now return a tuple with the first instance being an + instance of :class:`flask.Response`. This allows for returning + ``jsonify(error="error msg"), 400`` from a view function. Version 0.8.1 diff --git a/flask/app.py b/flask/app.py index 15e432de..f3d7efcb 100644 --- a/flask/app.py +++ b/flask/app.py @@ -1361,7 +1361,21 @@ class Flask(_PackageBoundObject): if isinstance(rv, basestring): return self.response_class(rv) if isinstance(rv, tuple): - return self.response_class(*rv) + if len(rv) > 0 and isinstance(rv[0], self.response_class): + original = rv[0] + new_response = self.response_class('', *rv[1:]) + if len(rv) < 3: + # The args for the response class are + # response=None, status=None, headers=None, + # mimetype=None, content_type=None, ... + # so if there's at least 3 elements the rv + # tuple contains header information so the + # headers from rv[0] "win." + new_response.headers = original.headers + new_response.response = original.response + return new_response + else: + return self.response_class(*rv) return self.response_class.force_type(rv, request.environ) def create_url_adapter(self, request): diff --git a/flask/testsuite/basic.py b/flask/testsuite/basic.py index e6a278e5..41efb196 100644 --- a/flask/testsuite/basic.py +++ b/flask/testsuite/basic.py @@ -659,6 +659,35 @@ class BasicFunctionalityTestCase(FlaskTestCase): self.assert_equal(rv.data, 'W00t') self.assert_equal(rv.mimetype, 'text/html') + def test_make_response_with_response_instance(self): + app = flask.Flask(__name__) + with app.test_request_context(): + rv = flask.make_response( + flask.jsonify({'msg': 'W00t'}), 400) + self.assertEqual(rv.status_code, 400) + self.assertEqual(rv.data, + '{\n "msg": "W00t"\n}') + self.assertEqual(rv.mimetype, 'application/json') + + rv = flask.make_response( + flask.Response(''), 400) + self.assertEqual(rv.status_code, 400) + self.assertEqual(rv.data, '') + self.assertEqual(rv.mimetype, 'text/html') + + rv = flask.make_response( + flask.Response('', headers={'Content-Type': 'text/html'}), + 400, None, 'application/json') + self.assertEqual(rv.status_code, 400) + self.assertEqual(rv.headers['Content-Type'], 'application/json') + + rv = flask.make_response( + flask.Response('', mimetype='application/json'), + 400, {'Content-Type': 'text/html'}) + self.assertEqual(rv.status_code, 400) + self.assertEqual(rv.headers['Content-Type'], 'text/html') + + def test_url_generation(self): app = flask.Flask(__name__) @app.route('/hello/', methods=['POST'])