import decimal import json import io import pytest from werkzeug.exceptions import BadRequest from werkzeug.wrappers import Request from werkzeug.datastructures import FileStorage, MultiDict from flask_restx import Api, Model, fields, inputs from flask_restx.errors import SpecsError from flask_restx.reqparse import Argument, RequestParser, ParseResult class ReqParseTest(object): def test_api_shortcut(self, app): api = Api(app) parser = api.parser() assert isinstance(parser, RequestParser) def test_parse_model(self, app): model = Model("Todo", {"task": fields.String(required=True)}) parser = RequestParser() parser.add_argument("todo", type=model, required=True) data = {"todo": {"task": "aaa"}} with app.test_request_context( "/", method="post", data=json.dumps(data), content_type="application/json" ): args = parser.parse_args() assert args["todo"] == {"task": "aaa"} def test_help(self, app, mocker): abort = mocker.patch( "flask_restx.reqparse.abort", side_effect=BadRequest("Bad Request") ) parser = RequestParser() parser.add_argument("foo", choices=("one", "two"), help="Bad choice.") req = mocker.Mock(["values", "get_json"]) req.values = MultiDict([("foo", "three")]) req.get_json.return_value = None with pytest.raises(BadRequest): parser.parse_args(req) expected = { "foo": "Bad choice. The value 'three' is not a valid choice for 'foo'." } abort.assert_called_with( 400, "Input payload validation failed", errors=expected ) def test_no_help(self, app, mocker): abort = mocker.patch( "flask_restx.reqparse.abort", side_effect=BadRequest("Bad Request") ) parser = RequestParser() parser.add_argument("foo", choices=["one", "two"]) req = mocker.Mock(["values", "get_json"]) req.get_json.return_value = None req.values = MultiDict([("foo", "three")]) with pytest.raises(BadRequest): parser.parse_args(req) expected = {"foo": "The value 'three' is not a valid choice for 'foo'."} abort.assert_called_with( 400, "Input payload validation failed", errors=expected ) @pytest.mark.request_context() def test_viewargs(self, mocker): req = Request.from_values() req.view_args = {"foo": "bar"} parser = RequestParser() parser.add_argument("foo", location=["view_args"]) args = parser.parse_args(req) assert args["foo"] == "bar" req = mocker.Mock(["get_json"]) req.values = () req.get_json.return_value = None req.view_args = {"foo": "bar"} parser = RequestParser() parser.add_argument("foo", store_missing=True) args = parser.parse_args(req) assert args["foo"] is None def test_parse_unicode(self, app): req = Request.from_values("/bubble?foo=barß") parser = RequestParser() parser.add_argument("foo") args = parser.parse_args(req) assert args["foo"] == "barß" def test_parse_unicode_app(self, app): parser = RequestParser() parser.add_argument("foo") with app.test_request_context("/bubble?foo=barß"): args = parser.parse_args() assert args["foo"] == "barß" @pytest.mark.request_context( "/bubble", method="post", content_type="application/json" ) def test_json_location(self): parser = RequestParser() parser.add_argument("foo", location="json", store_missing=True) args = parser.parse_args() assert args["foo"] is None @pytest.mark.request_context( "/bubble", method="post", data=json.dumps({"foo": "bar"}), content_type="application/json", ) def test_get_json_location(self): parser = RequestParser() parser.add_argument("foo", location="json") args = parser.parse_args() assert args["foo"] == "bar" @pytest.mark.request_context("/bubble?foo=bar") def test_parse_append_ignore(self, app): parser = RequestParser() parser.add_argument( "foo", ignore=True, type=int, action="append", store_missing=True ), args = parser.parse_args() assert args["foo"] is None @pytest.mark.request_context("/bubble?") def test_parse_append_default(self): parser = RequestParser() parser.add_argument("foo", action="append", store_missing=True), args = parser.parse_args() assert args["foo"] is None @pytest.mark.request_context("/bubble?foo=bar&foo=bat") def test_parse_append(self): parser = RequestParser() parser.add_argument("foo", action="append"), args = parser.parse_args() assert args["foo"] == ["bar", "bat"] @pytest.mark.request_context("/bubble?foo=bar") def test_parse_append_single(self): parser = RequestParser() parser.add_argument("foo", action="append"), args = parser.parse_args() assert args["foo"] == ["bar"] @pytest.mark.request_context("/bubble?foo=bar") def test_split_single(self): parser = RequestParser() parser.add_argument("foo", action="split"), args = parser.parse_args() assert args["foo"] == ["bar"] @pytest.mark.request_context("/bubble?foo=bar,bat") def test_split_multiple(self): parser = RequestParser() parser.add_argument("foo", action="split"), args = parser.parse_args() assert args["foo"] == ["bar", "bat"] @pytest.mark.request_context("/bubble?foo=1,2,3") def test_split_multiple_cast(self): parser = RequestParser() parser.add_argument("foo", type=int, action="split") args = parser.parse_args() assert args["foo"] == [1, 2, 3] @pytest.mark.request_context("/bubble?foo=bar") def test_parse_dest(self): parser = RequestParser() parser.add_argument("foo", dest="bat") args = parser.parse_args() assert args["bat"] == "bar" @pytest.mark.request_context("/bubble?foo>=bar&foo<=bat&foo=foo") def test_parse_gte_lte_eq(self): parser = RequestParser() parser.add_argument("foo", operators=[">=", "<=", "="], action="append"), args = parser.parse_args() assert args["foo"] == ["bar", "bat", "foo"] @pytest.mark.request_context("/bubble?foo>=bar") def test_parse_gte(self): parser = RequestParser() parser.add_argument("foo", operators=[">="]) args = parser.parse_args() assert args["foo"] == "bar" @pytest.mark.request_context("/bubble?foo=bar") def test_parse_foo_operators_four_hunderd(self): parser = RequestParser() parser.add_argument("foo", type=int), with pytest.raises(BadRequest): parser.parse_args() @pytest.mark.request_context("/bubble") def test_parse_foo_operators_ignore(self): parser = RequestParser() parser.add_argument("foo", ignore=True, store_missing=True) args = parser.parse_args() assert args["foo"] is None @pytest.mark.request_context("/bubble?foo<=bar") def test_parse_lte_gte_mock(self, mocker): mock_type = mocker.Mock() parser = RequestParser() parser.add_argument("foo", type=mock_type, operators=["<="]) parser.parse_args() mock_type.assert_called_with("bar", "foo", "<=") @pytest.mark.request_context("/bubble?foo<=bar") def test_parse_lte_gte_append(self): parser = RequestParser() parser.add_argument("foo", operators=["<=", "="], action="append") args = parser.parse_args() assert args["foo"] == ["bar"] @pytest.mark.request_context("/bubble?foo<=bar") def test_parse_lte_gte_missing(self): parser = RequestParser() parser.add_argument("foo", operators=["<=", "="]) args = parser.parse_args() assert args["foo"] == "bar" @pytest.mark.request_context("/bubble?foo=bar&foo=bat") def test_parse_eq_other(self): parser = RequestParser() parser.add_argument("foo"), args = parser.parse_args() assert args["foo"] == "bar" @pytest.mark.request_context("/bubble?foo=bar") def test_parse_eq(self): parser = RequestParser() parser.add_argument("foo"), args = parser.parse_args() assert args["foo"] == "bar" @pytest.mark.request_context("/bubble?foo<=bar") def test_parse_lte(self): parser = RequestParser() parser.add_argument("foo", operators=["<="]) args = parser.parse_args() assert args["foo"] == "bar" @pytest.mark.request_context("/bubble") def test_parse_required(self, app): parser = RequestParser() parser.add_argument("foo", required=True, location="values") expected = { "foo": "Missing required parameter in the post body or the query string" } with pytest.raises(BadRequest) as cm: parser.parse_args() assert cm.value.data["message"] == "Input payload validation failed" assert cm.value.data["errors"] == expected parser = RequestParser() parser.add_argument("bar", required=True, location=["values", "cookies"]) expected = { "bar": ( "Missing required parameter in the post body or the query " "string or the request's cookies" ) } with pytest.raises(BadRequest) as cm: parser.parse_args() assert cm.value.data["message"] == "Input payload validation failed" assert cm.value.data["errors"] == expected @pytest.mark.request_context("/bubble") @pytest.mark.options(bundle_errors=True) def test_parse_error_bundling(self, app): parser = RequestParser() parser.add_argument("foo", required=True, location="values") parser.add_argument("bar", required=True, location=["values", "cookies"]) with pytest.raises(BadRequest) as cm: parser.parse_args() assert cm.value.data["message"] == "Input payload validation failed" assert cm.value.data["errors"] == { "foo": "Missing required parameter in the post body or the query string", "bar": ( "Missing required parameter in the post body or the query string " "or the request's cookies" ), } @pytest.mark.request_context("/bubble") @pytest.mark.options(bundle_errors=False) def test_parse_error_bundling_w_parser_arg(self, app): parser = RequestParser(bundle_errors=True) parser.add_argument("foo", required=True, location="values") parser.add_argument("bar", required=True, location=["values", "cookies"]) with pytest.raises(BadRequest) as cm: parser.parse_args() assert cm.value.data["message"] == "Input payload validation failed" assert cm.value.data["errors"] == { "foo": "Missing required parameter in the post body or the query string", "bar": ( "Missing required parameter in the post body or the query string " "or the request's cookies" ), } @pytest.mark.request_context("/bubble") def test_parse_default_append(self): parser = RequestParser() parser.add_argument("foo", default="bar", action="append", store_missing=True) args = parser.parse_args() assert args["foo"] == "bar" @pytest.mark.request_context("/bubble") def test_parse_default(self): parser = RequestParser() parser.add_argument("foo", default="bar", store_missing=True) args = parser.parse_args() assert args["foo"] == "bar" @pytest.mark.request_context("/bubble") def test_parse_callable_default(self): parser = RequestParser() parser.add_argument("foo", default=lambda: "bar", store_missing=True) args = parser.parse_args() assert args["foo"] == "bar" @pytest.mark.request_context("/bubble?foo=bar") def test_parse(self): parser = RequestParser() parser.add_argument("foo"), args = parser.parse_args() assert args["foo"] == "bar" @pytest.mark.request_context("/bubble") def test_parse_none(self): parser = RequestParser() parser.add_argument("foo") args = parser.parse_args() assert args["foo"] is None def test_parse_store_missing(self, app): req = Request.from_values("/bubble") parser = RequestParser() parser.add_argument("foo", store_missing=False) args = parser.parse_args(req) assert "foo" not in args def test_parse_choices_correct(self, app): req = Request.from_values("/bubble?foo=bat") parser = RequestParser() parser.add_argument("foo", choices=["bat"]), args = parser.parse_args(req) assert args["foo"] == "bat" def test_parse_choices(self, app): req = Request.from_values("/bubble?foo=bar") parser = RequestParser() parser.add_argument("foo", choices=["bat"]), with pytest.raises(BadRequest): parser.parse_args(req) def test_parse_choices_sensitive(self, app): req = Request.from_values("/bubble?foo=BAT") parser = RequestParser() parser.add_argument("foo", choices=["bat"], case_sensitive=True), with pytest.raises(BadRequest): parser.parse_args(req) def test_parse_choices_insensitive(self, app): req = Request.from_values("/bubble?foo=BAT") parser = RequestParser() parser.add_argument("foo", choices=["bat"], case_sensitive=False), args = parser.parse_args(req) assert "bat" == args.get("foo") # both choices and args are case_insensitive req = Request.from_values("/bubble?foo=bat") parser = RequestParser() parser.add_argument("foo", choices=["BAT"], case_sensitive=False), args = parser.parse_args(req) assert "bat" == args.get("foo") def test_parse_ignore(self, app): req = Request.from_values("/bubble?foo=bar") parser = RequestParser() parser.add_argument("foo", type=int, ignore=True, store_missing=True), args = parser.parse_args(req) assert args["foo"] is None def test_chaining(self): parser = RequestParser() assert parser is parser.add_argument("foo") def test_result_existence(self): result = ParseResult() result.foo = "bar" result["bar"] = "baz" assert result["foo"] == "bar" assert result.bar == "baz" def test_result_missing(self): result = ParseResult() pytest.raises(AttributeError, lambda: result.spam) pytest.raises(KeyError, lambda: result["eggs"]) def test_result_configurability(self): req = Request.from_values() assert isinstance(RequestParser().parse_args(req), ParseResult) assert type(RequestParser(result_class=dict).parse_args(req)) is dict def test_none_argument(self, app): parser = RequestParser() parser.add_argument("foo", location="json") with app.test_request_context( "/bubble", method="post", data=json.dumps({"foo": None}), content_type="application/json", ): args = parser.parse_args() assert args["foo"] is None def test_type_callable(self, app): req = Request.from_values("/bubble?foo=1") parser = RequestParser() parser.add_argument("foo", type=lambda x: x, required=False), args = parser.parse_args(req) assert args["foo"] == "1" def test_type_callable_none(self, app): parser = RequestParser() parser.add_argument("foo", type=lambda x: x, location="json", required=False), with app.test_request_context( "/bubble", method="post", data=json.dumps({"foo": None}), content_type="application/json", ): args = parser.parse_args() assert args["foo"] is None def test_type_decimal(self, app): parser = RequestParser() parser.add_argument("foo", type=decimal.Decimal, location="json") with app.test_request_context( "/bubble", method="post", data=json.dumps({"foo": "1.0025"}), content_type="application/json", ): args = parser.parse_args() assert args["foo"] == decimal.Decimal("1.0025") def test_type_filestorage(self, app): parser = RequestParser() parser.add_argument("foo", type=FileStorage, location="files") fdata = "foo bar baz qux".encode("utf-8") with app.test_request_context( "/bubble", method="POST", data={"foo": (io.BytesIO(fdata), "baz.txt")} ): args = parser.parse_args() assert args["foo"].name == "foo" assert args["foo"].filename == "baz.txt" assert args["foo"].read() == fdata def test_filestorage_custom_type(self, app): def _custom_type(f): return FileStorage( stream=f.stream, filename="{0}aaaa".format(f.filename), name="{0}aaaa".format(f.name), ) parser = RequestParser() parser.add_argument("foo", type=_custom_type, location="files") fdata = "foo bar baz qux".encode("utf-8") with app.test_request_context( "/bubble", method="POST", data={"foo": (io.BytesIO(fdata), "baz.txt")} ): args = parser.parse_args() assert args["foo"].name == "fooaaaa" assert args["foo"].filename == "baz.txtaaaa" assert args["foo"].read() == fdata def test_passing_arguments_object(self, app): req = Request.from_values("/bubble?foo=bar") parser = RequestParser() parser.add_argument(Argument("foo")) args = parser.parse_args(req) assert args["foo"] == "bar" def test_int_choice_types(self, app): parser = RequestParser() parser.add_argument("foo", type=int, choices=[1, 2, 3], location="json") with app.test_request_context( "/bubble", method="post", data=json.dumps({"foo": 5}), content_type="application/json", ): with pytest.raises(BadRequest): parser.parse_args() def test_int_range_choice_types(self, app): parser = RequestParser() parser.add_argument("foo", type=int, choices=range(100), location="json") with app.test_request_context( "/bubble", method="post", data=json.dumps({"foo": 101}), content_type="application/json", ): with pytest.raises(BadRequest): parser.parse_args() def test_request_parser_copy(self, app): req = Request.from_values("/bubble?foo=101&bar=baz") parser = RequestParser() foo_arg = Argument("foo", type=int) parser.args.append(foo_arg) parser_copy = parser.copy() # Deepcopy should create a clone of the argument object instead of # copying a reference to the new args list assert foo_arg not in parser_copy.args # Args added to new parser should not be added to the original bar_arg = Argument("bar") parser_copy.args.append(bar_arg) assert bar_arg not in parser.args args = parser_copy.parse_args(req) assert args["foo"] == 101 assert args["bar"] == "baz" def test_request_parse_copy_including_settings(self): parser = RequestParser(trim=True, bundle_errors=True) parser_copy = parser.copy() assert parser.trim == parser_copy.trim assert parser.bundle_errors == parser_copy.bundle_errors def test_request_parser_replace_argument(self, app): req = Request.from_values("/bubble?foo=baz") parser = RequestParser() parser.add_argument("foo", type=int) parser_copy = parser.copy() parser_copy.replace_argument("foo") args = parser_copy.parse_args(req) assert args["foo"] == "baz" def test_both_json_and_values_location(self, app): parser = RequestParser() parser.add_argument("foo", type=int) parser.add_argument("baz", type=int) with app.test_request_context( "/bubble?foo=1", method="post", data=json.dumps({"baz": 2}), content_type="application/json", ): args = parser.parse_args() assert args["foo"] == 1 assert args["baz"] == 2 def test_not_json_location_and_content_type_json(self, app): parser = RequestParser() parser.add_argument("foo", location="args") with app.test_request_context( "/bubble", method="get", content_type="application/json" ): parser.parse_args() # Should not raise a 400: BadRequest def test_request_parser_remove_argument(self): req = Request.from_values("/bubble?foo=baz") parser = RequestParser() parser.add_argument("foo", type=int) parser_copy = parser.copy() parser_copy.remove_argument("foo") args = parser_copy.parse_args(req) assert args == {} def test_strict_parsing_off(self): req = Request.from_values("/bubble?foo=baz") parser = RequestParser() args = parser.parse_args(req) assert args == {} def test_strict_parsing_on(self): req = Request.from_values("/bubble?foo=baz") parser = RequestParser() with pytest.raises(BadRequest): parser.parse_args(req, strict=True) def test_strict_parsing_off_partial_hit(self, app): req = Request.from_values("/bubble?foo=1&bar=bees&n=22") parser = RequestParser() parser.add_argument("foo", type=int) args = parser.parse_args(req) assert args["foo"] == 1 def test_strict_parsing_on_partial_hit(self, app): req = Request.from_values("/bubble?foo=1&bar=bees&n=22") parser = RequestParser() parser.add_argument("foo", type=int) with pytest.raises(BadRequest): parser.parse_args(req, strict=True) def test_trim_argument(self, app): req = Request.from_values("/bubble?foo= 1 &bar=bees&n=22") parser = RequestParser() parser.add_argument("foo") args = parser.parse_args(req) assert args["foo"] == " 1 " parser = RequestParser() parser.add_argument("foo", trim=True) args = parser.parse_args(req) assert args["foo"] == "1" parser = RequestParser() parser.add_argument("foo", trim=True, type=int) args = parser.parse_args(req) assert args["foo"] == 1 def test_trim_request_parser(self, app): req = Request.from_values("/bubble?foo= 1 &bar=bees&n=22") parser = RequestParser(trim=False) parser.add_argument("foo") args = parser.parse_args(req) assert args["foo"] == " 1 " parser = RequestParser(trim=True) parser.add_argument("foo") args = parser.parse_args(req) assert args["foo"] == "1" parser = RequestParser(trim=True) parser.add_argument("foo", type=int) args = parser.parse_args(req) assert args["foo"] == 1 def test_trim_request_parser_override_by_argument(self): parser = RequestParser(trim=True) parser.add_argument("foo", trim=False) assert parser.args[0].trim is False def test_trim_request_parser_json(self, app): parser = RequestParser(trim=True) parser.add_argument("foo", location="json") parser.add_argument("int1", location="json", type=int) parser.add_argument("int2", location="json", type=int) with app.test_request_context( "/bubble", method="post", data=json.dumps({"foo": " bar ", "int1": 1, "int2": " 2 "}), content_type="application/json", ): args = parser.parse_args() assert args["foo"] == "bar" assert args["int1"] == 1 assert args["int2"] == 2 class ArgumentTest(object): def test_name(self): arg = Argument("foo") assert arg.name == "foo" def test_dest(self): arg = Argument("foo", dest="foobar") assert arg.dest == "foobar" def test_location_url(self): arg = Argument("foo", location="url") assert arg.location == "url" def test_location_url_list(self): arg = Argument("foo", location=["url"]) assert arg.location == ["url"] def test_location_header(self): arg = Argument("foo", location="headers") assert arg.location == "headers" def test_location_json(self): arg = Argument("foo", location="json") assert arg.location == "json" def test_location_get_json(self): arg = Argument("foo", location="get_json") assert arg.location == "get_json" def test_location_header_list(self): arg = Argument("foo", location=["headers"]) assert arg.location == ["headers"] def test_type(self): arg = Argument("foo", type=int) assert arg.type == int def test_default(self): arg = Argument("foo", default=True) assert arg.default is True def test_default_help(self): arg = Argument("foo") assert arg.help is None def test_required(self): arg = Argument("foo", required=True) assert arg.required is True def test_ignore(self): arg = Argument("foo", ignore=True) assert arg.ignore is True def test_operator(self): arg = Argument("foo", operators=[">=", "<=", "="]) assert arg.operators == [">=", "<=", "="] def test_action_filter(self): arg = Argument("foo", action="filter") assert arg.action == "filter" def test_action(self): arg = Argument("foo", action="append") assert arg.action == "append" def test_choices(self): arg = Argument("foo", choices=[1, 2]) assert arg.choices == [1, 2] def test_default_dest(self): arg = Argument("foo") assert arg.dest is None def test_default_operators(self): arg = Argument("foo") assert arg.operators[0] == "=" assert len(arg.operators) == 1 def test_default_type(self): arg = Argument("foo") sentinel = 666 assert arg.type(sentinel) == "666" def test_default_default(self): arg = Argument("foo") assert arg.default is None def test_required_default(self): arg = Argument("foo") assert arg.required is False def test_ignore_default(self): arg = Argument("foo") assert arg.ignore is False def test_action_default(self): arg = Argument("foo") assert arg.action == "store" def test_choices_default(self): arg = Argument("foo") assert len(arg.choices) == 0 def test_source(self, mocker): req = mocker.Mock(["args", "headers", "values"]) req.args = {"foo": "bar"} req.headers = {"baz": "bat"} arg = Argument("foo", location=["args"]) assert arg.source(req) == MultiDict(req.args) arg = Argument("foo", location=["headers"]) assert arg.source(req) == MultiDict(req.headers) def test_convert_default_type_with_null_input(self): arg = Argument("foo") assert arg.convert(None, None) is None def test_convert_with_null_input_when_not_nullable(self): arg = Argument("foo", nullable=False) pytest.raises(ValueError, lambda: arg.convert(None, None)) def test_source_bad_location(self, mocker): req = mocker.Mock(["values"]) arg = Argument("foo", location=["foo"]) assert len(arg.source(req)) == 0 # yes, basically you don't find it def test_source_default_location(self, mocker): req = mocker.Mock(["values", "get_json"]) req.get_json.return_value = None req._get_child_mock = lambda **kwargs: MultiDict() arg = Argument("foo") assert arg.source(req) == req.values def test_option_case_sensitive(self): arg = Argument("foo", choices=["bar", "baz"], case_sensitive=True) assert arg.case_sensitive is True # Insensitive arg = Argument("foo", choices=["bar", "baz"], case_sensitive=False) assert arg.case_sensitive is False # Default arg = Argument("foo", choices=["bar", "baz"]) assert arg.case_sensitive is True class RequestParserSchemaTest(object): def test_empty_parser(self): parser = RequestParser() assert parser.__schema__ == [] def test_primitive_types(self): parser = RequestParser() parser.add_argument("int", type=int, help="Some integer") parser.add_argument("str", type=str, help="Some string") parser.add_argument("float", type=float, help="Some float") assert parser.__schema__ == [ { "description": "Some integer", "type": "integer", "name": "int", "in": "query", }, { "description": "Some string", "type": "string", "name": "str", "in": "query", }, { "description": "Some float", "type": "number", "name": "float", "in": "query", }, ] def test_unknown_type(self): parser = RequestParser() parser.add_argument("unknown", type=lambda v: v) assert parser.__schema__ == [ { "name": "unknown", "type": "string", "in": "query", } ] def test_required(self): parser = RequestParser() parser.add_argument("int", type=int, required=True) assert parser.__schema__ == [ { "name": "int", "type": "integer", "in": "query", "required": True, } ] def test_default(self): parser = RequestParser() parser.add_argument("int", type=int, default=5) assert parser.__schema__ == [ { "name": "int", "type": "integer", "in": "query", "default": 5, } ] def test_default_as_false(self): parser = RequestParser() parser.add_argument("bool", type=inputs.boolean, default=False) assert parser.__schema__ == [ { "name": "bool", "type": "boolean", "in": "query", "default": False, } ] def test_choices(self): parser = RequestParser() parser.add_argument("string", type=str, choices=["a", "b"]) assert parser.__schema__ == [ { "name": "string", "type": "string", "in": "query", "enum": ["a", "b"], } ] def test_location(self): parser = RequestParser() parser.add_argument("default", type=int) parser.add_argument("in_values", type=int, location="values") parser.add_argument("in_query", type=int, location="args") parser.add_argument("in_headers", type=int, location="headers") parser.add_argument("in_cookie", type=int, location="cookie") assert parser.__schema__ == [ { "name": "default", "type": "integer", "in": "query", }, { "name": "in_values", "type": "integer", "in": "query", }, { "name": "in_query", "type": "integer", "in": "query", }, { "name": "in_headers", "type": "integer", "in": "header", }, ] def test_location_json(self): parser = RequestParser() parser.add_argument("in_json", type=str, location="json") assert parser.__schema__ == [ { "name": "in_json", "type": "string", "in": "body", } ] def test_location_form(self): parser = RequestParser() parser.add_argument("in_form", type=int, location="form") assert parser.__schema__ == [ { "name": "in_form", "type": "integer", "in": "formData", } ] def test_location_files(self): parser = RequestParser() parser.add_argument("in_files", type=FileStorage, location="files") assert parser.__schema__ == [ { "name": "in_files", "type": "file", "in": "formData", } ] def test_form_and_body_location(self): parser = RequestParser() parser.add_argument("default", type=int) parser.add_argument("in_form", type=int, location="form") parser.add_argument("in_json", type=str, location="json") with pytest.raises(SpecsError) as cm: parser.__schema__ assert cm.value.msg == "Can't use formData and body at the same time" def test_files_and_body_location(self): parser = RequestParser() parser.add_argument("default", type=int) parser.add_argument("in_files", type=FileStorage, location="files") parser.add_argument("in_json", type=str, location="json") with pytest.raises(SpecsError) as cm: parser.__schema__ assert cm.value.msg == "Can't use formData and body at the same time" def test_models(self): todo_fields = Model( "Todo", {"task": fields.String(required=True, description="The task details")}, ) parser = RequestParser() parser.add_argument("todo", type=todo_fields) assert parser.__schema__ == [ { "name": "todo", "type": "Todo", "in": "body", } ] def test_lists(self): parser = RequestParser() parser.add_argument("int", type=int, action="append") assert parser.__schema__ == [ { "name": "int", "in": "query", "type": "array", "collectionFormat": "multi", "items": {"type": "integer"}, } ] def test_split_lists(self): parser = RequestParser() parser.add_argument("int", type=int, action="split") assert parser.__schema__ == [ { "name": "int", "in": "query", "type": "array", "collectionFormat": "csv", "items": {"type": "integer"}, } ] def test_schema_interface(self): def custom(value): pass custom.__schema__ = { "type": "string", "format": "custom-format", } parser = RequestParser() parser.add_argument("custom", type=custom) assert parser.__schema__ == [ { "name": "custom", "in": "query", "type": "string", "format": "custom-format", } ] def test_callable_default(self): parser = RequestParser() parser.add_argument("int", type=int, default=lambda: 5) assert parser.__schema__ == [ { "name": "int", "type": "integer", "in": "query", "default": 5, } ]