From 7e6aa80c6a8c553ba76824da612d409b4b5dab14 Mon Sep 17 00:00:00 2001 From: bensynapse <118375461+bensynapse@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:15:42 +0300 Subject: [PATCH] Preserve numeric zero in named URI parameters Numeric zero was treated as an empty value in query and semicolon expansions. Keep its quoted text so offset=0 stays in the expanded URI. --- tests/test_uritemplate.py | 28 ++++++++++++++++++++++++++++ uritemplate/variable.py | 11 +++++------ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/tests/test_uritemplate.py b/tests/test_uritemplate.py index dfe19f5..e796582 100644 --- a/tests/test_uritemplate.py +++ b/tests/test_uritemplate.py @@ -664,6 +664,34 @@ def test_expand(self) -> None: self.assertEqual(expand("{/zero}", self.context), "/0") self.assertEqual(expand("{/zero,a_float}", self.context), "/0/3.1415") + def test_zero_parameter_expansions(self) -> None: + cases: t.List[t.Tuple[variable.ScalarVariableValue, str]] = [ + (0, "0"), + (0.0, "0.0"), + (-0.0, "-0.0"), + (0j, "0j"), + ] + for value, expected in cases: + for operator in ("?", "&", ";"): + for modifier in ("", "*"): + template = f"{{{operator}zero{modifier}}}" + with self.subTest(template=template, value=value): + self.assertEqual( + expand(template, {"zero": value}), + f"{operator}zero={expected}", + ) + + def test_empty_parameter_expansions(self) -> None: + for operator, expected in ( + ("?", "?zero="), + ("&", "&zero="), + (";", ";zero"), + ): + template = f"{{{operator}zero}}" + with self.subTest(template=template): + self.assertEqual(expand(template, {"zero": ""}), expected) + self.assertEqual(expand(template, {"zero": None}), "") + if __name__ == "__main__": unittest.main() diff --git a/uritemplate/variable.py b/uritemplate/variable.py index 1f7993c..f0d6ddb 100644 --- a/uritemplate/variable.py +++ b/uritemplate/variable.py @@ -310,11 +310,9 @@ def _query_expansion( ) return f"{name}={value}" - if value: - value = t.cast(t.Text, value) - value = value[:prefix] if prefix else value - return f"{name}={_quote(value)}" - return name + "=" + value = t.cast(t.Text, value) + value = value[:prefix] if prefix else value + return f"{name}={_quote(value)}" def _label_path_expansion( self, @@ -415,8 +413,9 @@ def _semi_path_expansion( value = t.cast(t.Text, value) value = value[:prefix] if prefix else value + value = self.operator.quote(value) if value: - return f"{name}={self.operator.quote(value)}" + return f"{name}={value}" return name