Skip to content

Commit

Permalink
Merge pull request #594 from sirosen/make-tuple-multiple
Browse files Browse the repository at this point in the history
Add Tuple to KNOWN_MULTI_FIELDS
  • Loading branch information
sirosen authored Mar 15, 2021
2 parents 8e6e68a + 992d584 commit f953dff
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 10 deletions.
10 changes: 5 additions & 5 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ Features:
`json_or_form`) (:issue:`580`).

* Detection of fields as "multi-value" for unpacking lists from multi-dict
types is now extensible with the `is_multiple` attribute. If a field sets
`is_multiple = True` it will be detected as a multi-value field.
types is now extensible with the ``is_multiple`` attribute. If a field sets
``is_multiple = True`` it will be detected as a multi-value field.
(:issue:`563`)

* If `is_multiple` is not set or is set to `None`, webargs will check if the
field is an instance of `List`.
* If ``is_multiple`` is not set or is set to ``None``, webargs will check if the
field is an instance of ``List`` or ``Tuple``.

* A new attribute on `Parser` objects, ``Parser.KNOWN_MULTI_FIELDS`` can be
* A new attribute on ``Parser`` objects, ``Parser.KNOWN_MULTI_FIELDS`` can be
used to set fields which should be detected as ``is_multiple=True`` even when
the attribute is not set.

Expand Down
3 changes: 1 addition & 2 deletions src/webargs/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,8 @@ class Parser:
DEFAULT_VALIDATION_STATUS: int = DEFAULT_VALIDATION_STATUS
#: Default error message for validation errors
DEFAULT_VALIDATION_MESSAGE: str = "Invalid value."
# TODO: add ma.fields.Tuple in v8.0
#: field types which should always be treated as if they set `is_multiple=True`
KNOWN_MULTI_FIELDS: typing.List[typing.Type] = [ma.fields.List]
KNOWN_MULTI_FIELDS: typing.List[typing.Type] = [ma.fields.List, ma.fields.Tuple]

#: Maps location => method name
__location_map__: typing.Dict[str, typing.Union[str, typing.Callable]] = {
Expand Down
5 changes: 4 additions & 1 deletion src/webargs/multidictproxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ def __init__(
self,
multidict,
schema: ma.Schema,
known_multi_fields: typing.Tuple[typing.Type, ...] = (ma.fields.List,),
known_multi_fields: typing.Tuple[typing.Type, ...] = (
ma.fields.List,
ma.fields.Tuple,
),
):
self.data = multidict
self.known_multi_fields = known_multi_fields
Expand Down
12 changes: 10 additions & 2 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class MockRequestParser(Parser):
"""A minimal parser implementation that parses mock requests."""

def load_querystring(self, req, schema):
return MultiDictProxy(req.query, schema)
return self._makeproxy(req.query, schema)

def load_json(self, req, schema):
return req.json
Expand Down Expand Up @@ -1040,6 +1040,7 @@ def test_type_conversion_with_multiple_required(web_request, parser):
"is_multiple_false",
"is_multiple_notset",
"list_field",
"tuple_field",
"added_to_known",
],
)
Expand Down Expand Up @@ -1103,13 +1104,20 @@ class CustomNonMultipleField(CustomMultiplexingField):
args = {"foos": fields.List(fields.Str())}
result = parser.parse(args, web_request, location="query")
assert result["foos"] in (["a", "b"], ["b", "a"])
# case 5: the field is a Tuple (special case)
elif setting == "tuple_field":
# this should behave like the is_multiple=True case and produce a tuple
args = {"foos": fields.Tuple((fields.Str, fields.Str))}
result = parser.parse(args, web_request, location="query")
assert result["foos"] in (("a", "b"), ("b", "a"))
# case 6: the field is custom, but added to the known fields of the parser
elif setting == "added_to_known":
# if it's included in the known multifields and is_multiple is not set, behave
# like is_multiple=True
parser.KNOWN_MULTI_FIELDS.append(CustomMultiplexingField)
args = {"foos": CustomMultiplexingField()}
result = parser.parse(args, web_request, location="query")
assert result["foos"] in ("a", "b")
assert result["foos"] in (["a", "b"], ["b", "a"])
else:
raise NotImplementedError

Expand Down

0 comments on commit f953dff

Please sign in to comment.