From dc86227d694671e24d1e70d4c20de38cae92805a Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Wed, 26 Aug 2026 14:36:19 +0100 Subject: [PATCH] Reject an empty top-level value in _string_from_json Closes #1487 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01YJDy3qA1LyNTh11zS98ukM --- newsfragments/1487.change.rst | 3 +++ src/vws_web_tools/__init__.py | 11 +++++++++-- tests/test_model_target_web_api_details.py | 19 ++++++++++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 newsfragments/1487.change.rst diff --git a/newsfragments/1487.change.rst b/newsfragments/1487.change.rst new file mode 100644 index 00000000..94102e57 --- /dev/null +++ b/newsfragments/1487.change.rst @@ -0,0 +1,3 @@ +Raise an error, rather than searching nested objects, when a Vuforia +credentials API response has the wanted key at the top level but with +an empty value. diff --git a/src/vws_web_tools/__init__.py b/src/vws_web_tools/__init__.py index 6c9e88c7..455f6929 100644 --- a/src/vws_web_tools/__init__.py +++ b/src/vws_web_tools/__init__.py @@ -1285,8 +1285,15 @@ def _string_from_json( if _is_json_object(value): for key in keys: child = value.get(key) - if isinstance(child, str) and child: - return child + if isinstance(child, str): + if child: + return child + # An object which has the key but with an empty value is + # the object we were looking for, and it is malformed. + # Do not fall through to a nested object which happens + # to have the same key. + message = f"Response included an empty '{key}'." + raise ValueError(message) for child in value.values(): with contextlib.suppress(ValueError): return _string_from_json(value=child, keys=keys) diff --git a/tests/test_model_target_web_api_details.py b/tests/test_model_target_web_api_details.py index 87c68e2e..fd12a685 100644 --- a/tests/test_model_target_web_api_details.py +++ b/tests/test_model_target_web_api_details.py @@ -91,7 +91,7 @@ def test_string_from_json_finds_nested_values() -> None: """A non-empty matching string is found recursively.""" result = vws_web_tools._string_from_json( value={ - "client_id": "", + "unrelated": "", "nested": [ {"clientId": "client-id"}, ], @@ -102,6 +102,23 @@ def test_string_from_json_finds_nested_values() -> None: assert result == "client-id" +def test_string_from_json_rejects_an_empty_top_level_value() -> None: + """An object which has the key with an empty value is not skipped.""" + with pytest.raises( + expected_exception=ValueError, + match="Response included an empty 'client_id'", + ): + vws_web_tools._string_from_json( + value={ + "client_id": "", + "nested": [ + {"clientId": "client-id"}, + ], + }, + keys=("client_id", "clientId"), + ) + + def test_string_from_json_raises_for_missing_values() -> None: """A missing matching string raises a useful error.""" with pytest.raises(