Browse Source

Merge pull request #938 from ahlen/response-with-headers-without-status

Enable tuple responses with headers without status
pull/930/merge
Armin Ronacher 11 years ago
parent
commit
c9bf907037
  1. 6
      docs/quickstart.rst
  2. 23
      flask/app.py
  3. 30
      flask/testsuite/basic.py

6
docs/quickstart.rst

@ -676,9 +676,9 @@ converting return values into response objects is as follows:
default parameters.
3. If a tuple is returned the items in the tuple can provide extra
information. Such tuples have to be in the form ``(response, status,
headers)`` where at least one item has to be in the tuple. The
`status` value will override the status code and `headers` can be a
list or dictionary of additional header values.
headers)`` or ``(response, headers)`` where at least one item has
to be in the tuple. The `status` value will override the status code
and `headers` can be a list or dictionary of additional header values.
4. If none of that works, Flask will assume the return value is a
valid WSGI application and convert that into a response object.

23
flask/app.py

@ -1544,7 +1544,8 @@ class Flask(_PackageBoundObject):
a WSGI function the function is called as WSGI application
and buffered as response object
:class:`tuple` A tuple in the form ``(response, status,
headers)`` where `response` is any of the
headers)`` or ``(response, headers)``
where `response` is any of the
types defined here, `status` is a string
or an integer and `headers` is a list or
a dictionary with header values.
@ -1556,34 +1557,38 @@ class Flask(_PackageBoundObject):
Previously a tuple was interpreted as the arguments for the
response object.
"""
status = headers = None
status_or_headers = headers = None
if isinstance(rv, tuple):
rv, status, headers = rv + (None,) * (3 - len(rv))
rv, status_or_headers, headers = rv + (None,) * (3 - len(rv))
if rv is None:
raise ValueError('View function did not return a response')
if isinstance(status_or_headers, (dict, list)):
headers, status_or_headers = status_or_headers, None
if not isinstance(rv, self.response_class):
# When we create a response object directly, we let the constructor
# set the headers and status. We do this because there can be
# some extra logic involved when creating these objects with
# specific values (like default content type selection).
if isinstance(rv, (text_type, bytes, bytearray)):
rv = self.response_class(rv, headers=headers, status=status)
headers = status = None
rv = self.response_class(rv, headers=headers, status=status_or_headers)
headers = status_or_headers = None
else:
rv = self.response_class.force_type(rv, request.environ)
if status is not None:
if isinstance(status, string_types):
rv.status = status
if status_or_headers is not None:
if isinstance(status_or_headers, string_types):
rv.status = status_or_headers
else:
rv.status_code = status
rv.status_code = status_or_headers
if headers:
rv.headers.extend(headers)
return rv
def create_url_adapter(self, request):
"""Creates a URL adapter for the given request. The URL adapter
is created at a point where the request context is not yet set up

30
flask/testsuite/basic.py

@ -735,7 +735,23 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return 'Meh', 400, {
'X-Foo': 'Testing',
'Content-Type': 'text/plain; charset=utf-8'
}
@app.route('/two_args')
def from_two_args_tuple():
return 'Hello', {
'X-Foo': 'Test',
'Content-Type': 'text/plain; charset=utf-8'
}
@app.route('/args_status')
def from_status_tuple():
return 'Hi, status!', 400
@app.route('/args_header')
def from_response_instance_status_tuple():
return flask.Response('Hello world', 404), {
"X-Foo": "Bar",
"X-Bar": "Foo"
}
c = app.test_client()
self.assert_equal(c.get('/unicode').data, u'Hällo Wörld'.encode('utf-8'))
self.assert_equal(c.get('/string').data, u'Hällo Wörld'.encode('utf-8'))
@ -744,6 +760,20 @@ class BasicFunctionalityTestCase(FlaskTestCase):
self.assert_equal(rv.headers['X-Foo'], 'Testing')
self.assert_equal(rv.status_code, 400)
self.assert_equal(rv.mimetype, 'text/plain')
rv2 = c.get('/two_args')
self.assert_equal(rv2.data, b'Hello')
self.assert_equal(rv2.headers['X-Foo'], 'Test')
self.assert_equal(rv2.status_code, 200)
self.assert_equal(rv2.mimetype, 'text/plain')
rv3 = c.get('/args_status')
self.assert_equal(rv3.data, b'Hi, status!')
self.assert_equal(rv3.status_code, 400)
self.assert_equal(rv3.mimetype, 'text/html')
rv4 = c.get('/args_header')
self.assert_equal(rv4.data, b'Hello world')
self.assert_equal(rv4.headers['X-Foo'], 'Bar')
self.assert_equal(rv4.headers['X-Bar'], 'Foo')
self.assert_equal(rv4.status_code, 404)
def test_make_response(self):
app = flask.Flask(__name__)

Loading…
Cancel
Save