From fd67e1ce97956213e8af0357b31397c26620a8b4 Mon Sep 17 00:00:00 2001 From: Prajakta Kamble Date: Tue, 23 Jun 2026 11:45:04 +0530 Subject: [PATCH 1/2] fix: handle non-numeric input for multiple-choice parameters in set_new_value The is_multiple_choice branch in set_new_value called float(s) with no try/except block. Both the is_bitmask and numeric branches properly catch ValueError and raise user-friendly translated error messages. If a user types a non-numeric string for a multiple-choice parameter (e.g. the choice label 'Disabled' instead of its numeric key '0'), the raw Python error 'could not convert string to float' was raised instead of a friendly translated message. Fixed by wrapping float(s) in a try/except ValueError matching the pattern already used in the bitmask and numeric branches. Add two regression tests covering the non-numeric error case and the valid numeric input case. --- .../data_model_ardupilot_parameter.py | 7 ++++- tests/test_data_model_ardupilot_parameter.py | 31 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/ardupilot_methodic_configurator/data_model_ardupilot_parameter.py b/ardupilot_methodic_configurator/data_model_ardupilot_parameter.py index a0b31c59b..d6c2c20c3 100644 --- a/ardupilot_methodic_configurator/data_model_ardupilot_parameter.py +++ b/ardupilot_methodic_configurator/data_model_ardupilot_parameter.py @@ -369,7 +369,12 @@ def set_new_value(self, value: str, ignore_out_of_range: bool = False) -> float: # Multiple-choice parameters: accept either the choice label or the numeric key if self.is_multiple_choice: - new_value = float(s) + try: + new_value = float(s) + except ValueError as exc: + raise ValueError( + _("The value for {param_name} must be a number.").format(param_name=self._name) + ) from exc # No change if new_value == self._new_value: raise ParameterUnchangedError( diff --git a/tests/test_data_model_ardupilot_parameter.py b/tests/test_data_model_ardupilot_parameter.py index 538a47dfe..e361f5e8e 100755 --- a/tests/test_data_model_ardupilot_parameter.py +++ b/tests/test_data_model_ardupilot_parameter.py @@ -1155,3 +1155,34 @@ def test_set_fc_value_maintains_comparison_state() -> None: # Assert: No longer different assert param.is_different_from_fc is False +def test_set_new_value_multiple_choice_non_numeric_raises_friendly_error(param_fixture) -> None: + """ + Bug fix: non-numeric input for a multiple-choice parameter raises a friendly ValueError. + + GIVEN: A multiple-choice parameter (has a values dict) + WHEN: set_new_value is called with a non-numeric string like a choice label + THEN: A ValueError is raised with a user-friendly translated message, + not a raw Python 'could not convert string to float' error + + Previously the is_multiple_choice branch called float(s) with no try/except, + while both the bitmask and numeric branches had proper error handling. + """ + full_param = param_fixture["full_param"] + + with pytest.raises(ValueError, match="must be a number"): + full_param.set_new_value("Zero") + + +def test_set_new_value_multiple_choice_valid_numeric_string_succeeds(param_fixture) -> None: + """ + A valid numeric string for a multiple-choice parameter is accepted correctly. + + GIVEN: A multiple-choice parameter with choices {"0": "Zero", "10": "Ten", "20": "Twenty"} + WHEN: set_new_value is called with "0" (a valid numeric choice key) + THEN: The new value is set to 0.0 and returned + """ + full_param = param_fixture["full_param"] + + result = full_param.set_new_value("0") + + assert result == 0.0 From 5b1344fd1ffc41f851036cee163d31e83c941336 Mon Sep 17 00:00:00 2001 From: Prajakta Kamble Date: Thu, 25 Jun 2026 16:49:49 +0530 Subject: [PATCH 2/2] fix: handle non-numeric input for multiple-choice parameters in set_new_value The is_multiple_choice branch in set_new_value called float(s) with no try/except block. Both the is_bitmask and numeric branches properly catch ValueError and raise user-friendly translated error messages. If a user types a non-numeric string for a multiple-choice parameter (e.g. the choice label 'Disabled' instead of its numeric key '0'), the raw Python error 'could not convert string to float' was raised instead of a friendly translated message. Fixed by wrapping float(s) in a try/except ValueError matching the pattern already used in the bitmask and numeric branches. Add two regression tests covering the non-numeric error case and the valid numeric input case. --- .../data_model_ardupilot_parameter.py | 4 +--- tests/test_data_model_ardupilot_parameter.py | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ardupilot_methodic_configurator/data_model_ardupilot_parameter.py b/ardupilot_methodic_configurator/data_model_ardupilot_parameter.py index d6c2c20c3..faa550c8c 100644 --- a/ardupilot_methodic_configurator/data_model_ardupilot_parameter.py +++ b/ardupilot_methodic_configurator/data_model_ardupilot_parameter.py @@ -372,9 +372,7 @@ def set_new_value(self, value: str, ignore_out_of_range: bool = False) -> float: try: new_value = float(s) except ValueError as exc: - raise ValueError( - _("The value for {param_name} must be a number.").format(param_name=self._name) - ) from exc + raise ValueError(_("The value for {param_name} must be a number.").format(param_name=self._name)) from exc # No change if new_value == self._new_value: raise ParameterUnchangedError( diff --git a/tests/test_data_model_ardupilot_parameter.py b/tests/test_data_model_ardupilot_parameter.py index e361f5e8e..d9f6de04a 100755 --- a/tests/test_data_model_ardupilot_parameter.py +++ b/tests/test_data_model_ardupilot_parameter.py @@ -1155,6 +1155,8 @@ def test_set_fc_value_maintains_comparison_state() -> None: # Assert: No longer different assert param.is_different_from_fc is False + + def test_set_new_value_multiple_choice_non_numeric_raises_friendly_error(param_fixture) -> None: """ Bug fix: non-numeric input for a multiple-choice parameter raises a friendly ValueError.