From 3ca0ee7a80d56d0b6c8432a9163478c536b90897 Mon Sep 17 00:00:00 2001 From: Friday Date: Wed, 18 Feb 2026 05:10:47 +0000 Subject: [PATCH] Fix query_param_matcher not matching empty query parameter values _parse_request_params calls parse_qsl without keep_blank_values=True, so query parameters with empty string values (e.g. ?bar=) are silently dropped. This causes query_param_matcher({"bar": ""}) to never match. Fixes #778 Co-Authored-By: Claude Opus 4.6 --- responses/__init__.py | 5 ++++- responses/tests/test_matchers.py | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/responses/__init__.py b/responses/__init__.py index 3f6e4743..f5a2193b 100644 --- a/responses/__init__.py +++ b/responses/__init__.py @@ -1051,7 +1051,10 @@ def _parse_request_params( self, url: str ) -> Dict[str, Union[str, int, float, List[Optional[Union[str, int, float]]]]]: params: Dict[str, Union[str, int, float, List[Any]]] = {} - for key, val in groupby(parse_qsl(urlsplit(url).query), lambda kv: kv[0]): + for key, val in groupby( + parse_qsl(urlsplit(url).query, keep_blank_values=True), + lambda kv: kv[0], + ): values = list(map(lambda x: x[1], val)) if len(values) == 1: values = values[0] # type: ignore[assignment] diff --git a/responses/tests/test_matchers.py b/responses/tests/test_matchers.py index 1888ac3b..44544f34 100644 --- a/responses/tests/test_matchers.py +++ b/responses/tests/test_matchers.py @@ -260,6 +260,24 @@ def run(): assert_reset() +def test_query_param_matcher_empty_value(): + @responses.activate + def run(): + responses.add( + responses.GET, + "https://example.com/foo", + match=[ + matchers.query_param_matcher({"bar": ""}), + ], + json={}, + ) + resp = requests.get("https://example.com/foo?bar=") + assert resp.status_code == 200 + + run() + assert_reset() + + def test_query_param_matcher_loose(): @responses.activate def run():