From 47bf68ef0af2ba63489c1be7d20995d7217de66a Mon Sep 17 00:00:00 2001 From: Jonas Lundberg Date: Wed, 8 Apr 2026 12:21:45 +0200 Subject: [PATCH] Strictly detect `ANY` in multi items patterns --- respx/patterns.py | 28 +++++++++++++++++++++------- tests/test_api.py | 4 ++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/respx/patterns.py b/respx/patterns.py index 37859f7..0bd6199 100644 --- a/respx/patterns.py +++ b/respx/patterns.py @@ -294,19 +294,24 @@ def _multi_items( ( key, tuple( - ( - ANY - if parse_any and v == str(ANY) - else str(ANY) - if encode_any and v == ANY - else v - ) + self._item_value(v, parse_any=parse_any, encode_any=encode_any) for v in value.get_list(key) ), ) for key in sorted(value.keys()) ) + def _item_value( + self, value: Any, parse_any: bool = False, encode_any: bool = False + ) -> Any: + return ( + ANY + if parse_any and value == str(ANY) + else str(ANY) + if encode_any and value is ANY + else value + ) + def __hash__(self): return hash( ( @@ -605,6 +610,15 @@ def _normalize_file_value(self, value: FileTypes) -> Tuple[Tuple[Any, Any]]: return ((filename, fileobj),) + def _item_value( + self, value: Tuple[Any, Any], parse_any: bool = False, encode_any: bool = False + ) -> Tuple[Any, Any]: + filename, data = value + return ( + super()._item_value(filename, parse_any=parse_any, encode_any=encode_any), + super()._item_value(data, parse_any=parse_any, encode_any=encode_any), + ) + def clean(self, value: RequestFiles) -> MultiItems: if isinstance(value, Mapping): value = list(value.items()) diff --git a/tests/test_api.py b/tests/test_api.py index e9ed702..8aa9903 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -501,6 +501,10 @@ def test_pop(): ) async def test_params_match(client, url, params, call_url, call_params): respx.get(url, params=params) % dict(content="spam spam") + + # Add an extra competing param but with non-matching value, reproduces #311 issue + respx.get(url, params={"foo": ""}) + response = await client.get(call_url, params=call_params) assert response.text == "spam spam"