Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions respx/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

@lundberg lundberg Apr 8, 2026 •

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE:

we're using is here rather than ==

else value
)

def __hash__(self):
return hash(
(
Expand Down Expand Up @@ -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())
Expand Down
4 changes: 4 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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": "<non-matching>"})

response = await client.get(call_url, params=call_params)
assert response.text == "spam spam"

Expand Down
Loading