From 498e0412dd6b6b78a144330a7a7dbb765ac61d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Lafr=C3=A9choux?= Date: Wed, 17 Apr 2019 00:10:16 +0200 Subject: [PATCH] Fix returning tuple subclass from a view function --- flask_rest_api/utils.py | 6 ++++-- tests/test_blueprint.py | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/flask_rest_api/utils.py b/flask_rest_api/utils.py index 6677c8f0..eca1f842 100644 --- a/flask_rest_api/utils.py +++ b/flask_rest_api/utils.py @@ -64,14 +64,16 @@ def load_info_from_docstring(docstring): return info -# Copied from flask +# Copied from Flask def unpack_tuple_response(rv): """Unpack a flask Response tuple""" status = headers = None # unpack tuple returns - if isinstance(rv, tuple): + # Unlike Flask, we check exact type because tuple subclasses may be + # returned by view functions and paginated/dumped + if type(rv) is tuple: # pylint: disable=unidiomatic-typecheck len_rv = len(rv) # a 3-tuple is unpacked directly diff --git a/tests/test_blueprint.py b/tests/test_blueprint.py index c36f552e..92aec059 100644 --- a/tests/test_blueprint.py +++ b/tests/test_blueprint.py @@ -566,6 +566,13 @@ def func_response_code_str_headers(): def func_response_wrong_tuple(): return {}, 201, {'X-header': 'test'}, 'extra' + @blp.route('/response_tuple_subclass') + @blp.response() + def func_response_tuple_subclass(): + class MyTuple(tuple): + pass + return MyTuple((1, 2)) + api.register_blueprint(blp) response = client.get('/test/response') @@ -595,6 +602,9 @@ def func_response_wrong_tuple(): assert response.headers['X-header'] == 'test' response = client.get('/test/response_wrong_tuple') assert response.status_code == 500 + response = client.get('/test/response_tuple_subclass') + assert response.status_code == 200 + assert response.json == [1, 2] def test_blueprint_pagination_response_tuple(self, app): api = Api(app) @@ -631,6 +641,14 @@ def func_response_code_headers(): def func_response_wrong_tuple(): return [1, 2], 201, {'X-header': 'test'}, 'extra' + @blp.route('/response_tuple_subclass') + @blp.response() + @blp.paginate(Page) + def func_response_tuple_subclass(): + class MyTuple(tuple): + pass + return MyTuple((1, 2)) + api.register_blueprint(blp) response = client.get('/test/response') @@ -649,6 +667,9 @@ def func_response_wrong_tuple(): assert response.headers['X-header'] == 'test' response = client.get('/test/response_wrong_tuple') assert response.status_code == 500 + response = client.get('/test/response_tuple_subclass') + assert response.status_code == 200 + assert response.json == [1, 2] def test_blueprint_response_response_object(self, app, schemas): api = Api(app)