mirror of https://github.com/encode/starlette.git
Ensure query params behavior matches standard mappings. (#338)
* QueryParams behavior as standard mapping
This commit is contained in:
parent
0c3a1e4a60
commit
774cb40a17
|
@ -231,7 +231,7 @@ class QueryParams(typing.Mapping[str, str]):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
params: typing.Mapping[str, str] = None,
|
params: typing.Union["QueryParams", typing.Mapping[str, str]] = None,
|
||||||
items: typing.List[typing.Tuple[str, str]] = None,
|
items: typing.List[typing.Tuple[str, str]] = None,
|
||||||
query_string: str = None,
|
query_string: str = None,
|
||||||
scope: Scope = None,
|
scope: Scope = None,
|
||||||
|
@ -241,7 +241,10 @@ class QueryParams(typing.Mapping[str, str]):
|
||||||
assert items is None, "Cannot set both 'params' and 'items'"
|
assert items is None, "Cannot set both 'params' and 'items'"
|
||||||
assert query_string is None, "Cannot set both 'params' and 'query_string'"
|
assert query_string is None, "Cannot set both 'params' and 'query_string'"
|
||||||
assert scope is None, "Cannot set both 'params' and 'scope'"
|
assert scope is None, "Cannot set both 'params' and 'scope'"
|
||||||
_items = list(params.items())
|
if isinstance(params, QueryParams):
|
||||||
|
_items = list(params.multi_items())
|
||||||
|
else:
|
||||||
|
_items = list(params.items())
|
||||||
elif items is not None:
|
elif items is not None:
|
||||||
assert query_string is None, "Cannot set both 'items' and 'query_string'"
|
assert query_string is None, "Cannot set both 'items' and 'query_string'"
|
||||||
assert scope is None, "Cannot set both 'items' and 'scope'"
|
assert scope is None, "Cannot set both 'items' and 'scope'"
|
||||||
|
@ -252,26 +255,28 @@ class QueryParams(typing.Mapping[str, str]):
|
||||||
elif scope is not None:
|
elif scope is not None:
|
||||||
_items = parse_qsl(scope["query_string"].decode("latin-1"))
|
_items = parse_qsl(scope["query_string"].decode("latin-1"))
|
||||||
|
|
||||||
self._dict = {k: v for k, v in reversed(_items)}
|
self._dict = {k: v for k, v in _items}
|
||||||
self._list = _items
|
self._list = _items
|
||||||
|
|
||||||
def getlist(self, key: typing.Any) -> typing.List[str]:
|
def getlist(self, key: typing.Any) -> typing.List[str]:
|
||||||
return [item_value for item_key, item_value in self._list if item_key == key]
|
return [item_value for item_key, item_value in self._list if item_key == key]
|
||||||
|
|
||||||
def keys(self) -> typing.List[str]: # type: ignore
|
def keys(self) -> typing.List[str]: # type: ignore
|
||||||
return [key for key, value in self._list]
|
return list(self._dict.keys())
|
||||||
|
|
||||||
def values(self) -> typing.List[str]: # type: ignore
|
def values(self) -> typing.List[str]: # type: ignore
|
||||||
return [value for key, value in self._list]
|
return list(self._dict.values())
|
||||||
|
|
||||||
def items(self) -> typing.List[typing.Tuple[str, str]]: # type: ignore
|
def items(self) -> typing.List[typing.Tuple[str, str]]: # type: ignore
|
||||||
|
return list(self._dict.items())
|
||||||
|
|
||||||
|
def multi_items(self) -> typing.List[typing.Tuple[str, str]]:
|
||||||
return list(self._list)
|
return list(self._list)
|
||||||
|
|
||||||
def get(self, key: typing.Any, default: typing.Any = None) -> typing.Any:
|
def get(self, key: typing.Any, default: typing.Any = None) -> typing.Any:
|
||||||
if key in self._dict:
|
if key in self._dict:
|
||||||
return self._dict[key]
|
return self._dict[key]
|
||||||
else:
|
return default
|
||||||
return default
|
|
||||||
|
|
||||||
def __getitem__(self, key: typing.Any) -> str:
|
def __getitem__(self, key: typing.Any) -> str:
|
||||||
return self._dict[key]
|
return self._dict[key]
|
||||||
|
@ -283,7 +288,7 @@ class QueryParams(typing.Mapping[str, str]):
|
||||||
return iter(self.keys())
|
return iter(self.keys())
|
||||||
|
|
||||||
def __len__(self) -> int:
|
def __len__(self) -> int:
|
||||||
return len(self._list)
|
return len(self._dict)
|
||||||
|
|
||||||
def __eq__(self, other: typing.Any) -> bool:
|
def __eq__(self, other: typing.Any) -> bool:
|
||||||
if not isinstance(other, QueryParams):
|
if not isinstance(other, QueryParams):
|
||||||
|
|
|
@ -172,15 +172,16 @@ def test_queryparams():
|
||||||
assert "a" in q
|
assert "a" in q
|
||||||
assert "A" not in q
|
assert "A" not in q
|
||||||
assert "c" not in q
|
assert "c" not in q
|
||||||
assert q["a"] == "123"
|
assert q["a"] == "456"
|
||||||
assert q.get("a") == "123"
|
assert q.get("a") == "456"
|
||||||
assert q.get("nope", default=None) is None
|
assert q.get("nope", default=None) is None
|
||||||
assert q.getlist("a") == ["123", "456"]
|
assert q.getlist("a") == ["123", "456"]
|
||||||
assert q.keys() == ["a", "a", "b"]
|
assert q.keys() == ["a", "b"]
|
||||||
assert q.values() == ["123", "456", "789"]
|
assert q.values() == ["456", "789"]
|
||||||
assert q.items() == [("a", "123"), ("a", "456"), ("b", "789")]
|
assert q.items() == [("a", "456"), ("b", "789")]
|
||||||
assert list(q) == ["a", "a", "b"]
|
assert len(q) == 2
|
||||||
assert dict(q) == {"a": "123", "b": "789"}
|
assert list(q) == ["a", "b"]
|
||||||
|
assert dict(q) == {"a": "456", "b": "789"}
|
||||||
assert str(q) == "a=123&a=456&b=789"
|
assert str(q) == "a=123&a=456&b=789"
|
||||||
assert repr(q) == "QueryParams(query_string='a=123&a=456&b=789')"
|
assert repr(q) == "QueryParams(query_string='a=123&a=456&b=789')"
|
||||||
assert QueryParams({"a": "123", "b": "456"}) == QueryParams(
|
assert QueryParams({"a": "123", "b": "456"}) == QueryParams(
|
||||||
|
@ -193,4 +194,10 @@ def test_queryparams():
|
||||||
{"b": "456", "a": "123"}
|
{"b": "456", "a": "123"}
|
||||||
)
|
)
|
||||||
assert QueryParams() == QueryParams({})
|
assert QueryParams() == QueryParams({})
|
||||||
|
assert QueryParams(items=[("a", "123"), ("a", "456")]) == QueryParams(
|
||||||
|
query_string="a=123&a=456"
|
||||||
|
)
|
||||||
assert QueryParams({"a": "123", "b": "456"}) != "invalid"
|
assert QueryParams({"a": "123", "b": "456"}) != "invalid"
|
||||||
|
|
||||||
|
q = QueryParams(items=[("a", "123"), ("a", "456")])
|
||||||
|
assert QueryParams(q) == q
|
||||||
|
|
Loading…
Reference in New Issue