Browse Source

Changed the implementation of returning tuples from functions

pull/483/head
Armin Ronacher 13 years ago
parent
commit
cf1641e5be
  1. 2
      CHANGES
  2. 7
      docs/quickstart.rst
  3. 15
      docs/upgrading.rst
  4. 55
      flask/app.py
  5. 15
      flask/testsuite/basic.py

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
------------- -------------

7
docs/quickstart.rst

@ -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.

15
docs/upgrading.rst

@ -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

@ -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 else:
# response=None, status=None, headers=None, rv = self.response_class.force_type(rv, request.environ)
# mimetype=None, content_type=None, ...
# so if there's at least 3 elements the rv if status is not None:
# tuple contains header information so the if isinstance(status, basestring):
# headers from rv[0] "win." rv.status = status
new_response.headers = original.headers
new_response.response = original.response
return new_response
else: else:
return self.response_class(*rv) rv.status_code = status
return self.response_class.force_type(rv, request.environ) 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

15
flask/testsuite/basic.py

@ -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…
Cancel
Save