From 4df7e4681dcdca089a269bb9bb63ce6355b19896 Mon Sep 17 00:00:00 2001 From: axolotle Date: Sun, 30 Apr 2023 17:15:40 +0200 Subject: [PATCH] form: force option type to 'select' if there's 'choices' + add test --- src/tests/test_questions.py | 15 +++++++++++++++ src/utils/form.py | 23 ++++++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/tests/test_questions.py b/src/tests/test_questions.py index 7ef678d19..7737c4546 100644 --- a/src/tests/test_questions.py +++ b/src/tests/test_questions.py @@ -1950,6 +1950,21 @@ def test_question_string_default_type(): assert out.value == "some_value" +def test_option_default_type_with_choices_is_select(): + questions = { + "some_choices": {"choices": ["a", "b"]}, + # LEGACY (`choices` in option `string` used to be valid) + # make sure this result as a `select` option + "some_legacy": {"type": "string", "choices": ["a", "b"]} + } + answers = {"some_choices": "a", "some_legacy": "a"} + + options = ask_questions_and_parse_answers(questions, answers) + for option in options: + assert option.type == "select" + assert option.value == "a" + + @pytest.mark.skip # we should do something with this example def test_question_string_input_test_ask_with_example(): ask_text = "some question" diff --git a/src/utils/form.py b/src/utils/form.py index 57cb1cd5b..1ca03373e 100644 --- a/src/utils/form.py +++ b/src/utils/form.py @@ -1014,6 +1014,22 @@ OPTIONS = { } +def hydrate_option_type(raw_option: dict[str, Any]) -> dict[str, Any]: + type_ = raw_option.get( + "type", OptionType.select if "choices" in raw_option else OptionType.string + ) + # LEGACY (`choices` in option `string` used to be valid) + if "choices" in raw_option and type_ == OptionType.string: + logger.warning( + f"Packagers: option {raw_option['id']} has 'choices' but has type 'string', use 'select' instead to remove this warning." + ) + type_ = OptionType.select + + raw_option["type"] = type_ + + return raw_option + + # ╭───────────────────────────────────────────────────────╮ # │ ╷ ╷╶┬╴╶┬╴╷ ╭─╴ │ # │ │ │ │ │ │ ╰─╮ │ @@ -1036,8 +1052,8 @@ def prompt_or_validate_form( for id_, raw_option in raw_options.items(): raw_option["id"] = id_ raw_option["value"] = answers.get(id_) - question_class = OPTIONS[raw_option.get("type", "string")] - option = question_class(raw_option) + raw_option = hydrate_option_type(raw_option) + option = OPTIONS[raw_option["type"]](raw_option) interactive = Moulinette.interface.type == "cli" and os.isatty(1) @@ -1178,7 +1194,8 @@ def hydrate_questions_with_choices(raw_questions: List) -> List: out = [] for raw_question in raw_questions: - question = OPTIONS[raw_question.get("type", OptionType.string)](raw_question) + raw_question = hydrate_option_type(raw_question) + question = OPTIONS[raw_question["type"]](raw_question) if isinstance(question, BaseChoicesOption) and question.choices: raw_question["choices"] = question.choices raw_question["default"] = question.default