mirror of https://github.com/pallets/flask.git
Changed the implementation of returning tuples from functions
This commit is contained in:
parent
3249eeb438
commit
cf1641e5be
2
CHANGES
2
CHANGES
|
@ -63,6 +63,8 @@ Relase date to be decided, codename to be chosen.
|
||||||
the `get_send_file_options` hook is used.
|
the `get_send_file_options` hook is used.
|
||||||
- Fixed an assumption in sessions implementation which could break message
|
- Fixed an assumption in sessions implementation which could break message
|
||||||
flashing on sessions implementations which use external storage.
|
flashing on sessions implementations which use external storage.
|
||||||
|
- Changed the behavior of tuple return values from functions. They are no
|
||||||
|
longer arguments to the response object, they now have a defined meaning.
|
||||||
|
|
||||||
Version 0.8.1
|
Version 0.8.1
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -674,8 +674,11 @@ converting return values into response objects is as follows:
|
||||||
returned from the view.
|
returned from the view.
|
||||||
2. If it's a string, a response object is created with that data and the
|
2. If it's a string, a response object is created with that data and the
|
||||||
default parameters.
|
default parameters.
|
||||||
3. If a tuple is returned the response object is created by passing the
|
3. If a tuple is returned the items in the tuple can provide extra
|
||||||
tuple as arguments to the response object's constructor.
|
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.
|
||||||
4. If none of that works, Flask will assume the return value is a
|
4. If none of that works, Flask will assume the return value is a
|
||||||
valid WSGI application and convert that into a response object.
|
valid WSGI application and convert that into a response object.
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,21 @@ installation, make sure to pass it the ``-U`` parameter::
|
||||||
|
|
||||||
$ easy_install -U Flask
|
$ easy_install -U Flask
|
||||||
|
|
||||||
|
Version 0.9
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The behavior of returning tuples from a function was simplified. If you
|
||||||
|
return a tuple it no longer defines the arguments for the response object
|
||||||
|
you're creating, it's now always a tuple in the form ``(response, status,
|
||||||
|
headers)`` where at least one item has to be provided. If you depend on
|
||||||
|
the old behavior, you can add it easily by subclassing Flask::
|
||||||
|
|
||||||
|
class TraditionalFlask(Flask):
|
||||||
|
def make_response(self, rv):
|
||||||
|
if isinstance(rv, tuple):
|
||||||
|
return self.response_class(*rv)
|
||||||
|
return Flask.make_response(self, rv)
|
||||||
|
|
||||||
Version 0.8
|
Version 0.8
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|
55
flask/app.py
55
flask/app.py
|
@ -1354,37 +1354,48 @@ class Flask(_PackageBoundObject):
|
||||||
string as body
|
string as body
|
||||||
:class:`unicode` a response object is created with the
|
:class:`unicode` a response object is created with the
|
||||||
string encoded to utf-8 as body
|
string encoded to utf-8 as body
|
||||||
:class:`tuple` the response object is created with the
|
|
||||||
contents of the tuple as arguments
|
|
||||||
a WSGI function the function is called as WSGI application
|
a WSGI function the function is called as WSGI application
|
||||||
and buffered as response object
|
and buffered as response object
|
||||||
|
:class:`tuple` A tuple in the form ``(response, status,
|
||||||
|
headers)`` where `response` is any of the
|
||||||
|
types defined here, `status` is a string
|
||||||
|
or an integer and `headers` is a list of
|
||||||
|
a dictionary with header values.
|
||||||
======================= ===========================================
|
======================= ===========================================
|
||||||
|
|
||||||
:param rv: the return value from the view function
|
:param rv: the return value from the view function
|
||||||
|
|
||||||
|
.. versionchanged:: 0.9
|
||||||
|
Previously a tuple was interpreted as the arguments for the
|
||||||
|
response object.
|
||||||
"""
|
"""
|
||||||
|
status = headers = None
|
||||||
|
if isinstance(rv, tuple):
|
||||||
|
rv, status, headers = rv + (None,) * (3 - len(rv))
|
||||||
|
|
||||||
if rv is None:
|
if rv is None:
|
||||||
raise ValueError('View function did not return a response')
|
raise ValueError('View function did not return a response')
|
||||||
if isinstance(rv, self.response_class):
|
|
||||||
return rv
|
if not isinstance(rv, self.response_class):
|
||||||
if isinstance(rv, basestring):
|
# When we create a response object directly, we let the constructor
|
||||||
return self.response_class(rv)
|
# set the headers and status. We do this because there can be
|
||||||
if isinstance(rv, tuple):
|
# some extra logic involved when creating these objects with
|
||||||
if len(rv) > 0 and isinstance(rv[0], self.response_class):
|
# specific values (like defualt content type selection).
|
||||||
original = rv[0]
|
if isinstance(rv, basestring):
|
||||||
new_response = self.response_class('', *rv[1:])
|
rv = self.response_class(rv, headers=headers, status=status)
|
||||||
if len(rv) < 3:
|
headers = status = None
|
||||||
# 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:
|
else:
|
||||||
return self.response_class(*rv)
|
rv = self.response_class.force_type(rv, request.environ)
|
||||||
return self.response_class.force_type(rv, request.environ)
|
|
||||||
|
if status is not None:
|
||||||
|
if isinstance(status, basestring):
|
||||||
|
rv.status = status
|
||||||
|
else:
|
||||||
|
rv.status_code = status
|
||||||
|
if headers:
|
||||||
|
rv.headers.extend(headers)
|
||||||
|
|
||||||
|
return rv
|
||||||
|
|
||||||
def create_url_adapter(self, request):
|
def create_url_adapter(self, request):
|
||||||
"""Creates a URL adapter for the given request. The URL adapter
|
"""Creates a URL adapter for the given request. The URL adapter
|
||||||
|
|
|
@ -631,7 +631,10 @@ class BasicFunctionalityTestCase(FlaskTestCase):
|
||||||
return u'Hällo Wörld'.encode('utf-8')
|
return u'Hällo Wörld'.encode('utf-8')
|
||||||
@app.route('/args')
|
@app.route('/args')
|
||||||
def from_tuple():
|
def from_tuple():
|
||||||
return 'Meh', 400, {'X-Foo': 'Testing'}, 'text/plain'
|
return 'Meh', 400, {
|
||||||
|
'X-Foo': 'Testing',
|
||||||
|
'Content-Type': 'text/plain; charset=utf-8'
|
||||||
|
}
|
||||||
c = app.test_client()
|
c = app.test_client()
|
||||||
self.assert_equal(c.get('/unicode').data, u'Hällo Wörld'.encode('utf-8'))
|
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'))
|
self.assert_equal(c.get('/string').data, u'Hällo Wörld'.encode('utf-8'))
|
||||||
|
@ -677,16 +680,10 @@ class BasicFunctionalityTestCase(FlaskTestCase):
|
||||||
|
|
||||||
rv = flask.make_response(
|
rv = flask.make_response(
|
||||||
flask.Response('', headers={'Content-Type': 'text/html'}),
|
flask.Response('', headers={'Content-Type': 'text/html'}),
|
||||||
400, None, 'application/json')
|
400, [('X-Foo', 'bar')])
|
||||||
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.status_code, 400)
|
||||||
self.assertEqual(rv.headers['Content-Type'], 'text/html')
|
self.assertEqual(rv.headers['Content-Type'], 'text/html')
|
||||||
|
self.assertEqual(rv.headers['X-Foo'], 'bar')
|
||||||
|
|
||||||
def test_url_generation(self):
|
def test_url_generation(self):
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
|
|
Loading…
Reference in New Issue