diff --git a/news/27.bugfix b/news/27.bugfix new file mode 100644 index 0000000..ea28ffc --- /dev/null +++ b/news/27.bugfix @@ -0,0 +1 @@ +Update QuestionComputed and QuestionConstant to respect existing answers if provided in the context, preventing unnecessary recomputations when overrides are intended. @erral diff --git a/src/tui_forms/form/question.py b/src/tui_forms/form/question.py index 467cc7e..7f9f437 100644 --- a/src/tui_forms/form/question.py +++ b/src/tui_forms/form/question.py @@ -60,11 +60,12 @@ def _render_variable( self, env: Environment, answers: dict[str, Any], value: Any, root_key: str = "" ) -> Any: key = self.key - current_value = (answers.get(root_key, {}) if root_key else answers).get( - key, _NOVALUE - ) + current_answers = answers.get(root_key, {}) if root_key else answers + current_value = current_answers.get(key, _NOVALUE) if current_value is _NOVALUE: - value = template.render_variable(env, value, answers) + value = template.render_variable( + env, value, current_answers, root_key=root_key + ) else: value = current_value return value @@ -90,6 +91,10 @@ class QuestionComputed(QuestionHidden): def default_value( self, env: Environment, answers: dict[str, Any], root_key: str = "" ) -> Any: + current_answers = answers.get(root_key, {}) if root_key else answers + if (current_value := current_answers.get(self.key, _NOVALUE)) is not _NOVALUE: + return current_value + val = ( self.default["default"] if isinstance(self.default, dict) else self.default ) @@ -115,6 +120,9 @@ def default_value( self, env: Environment, answers: dict[str, Any], root_key: str = "" ) -> Any: """Return the raw constant value without rendering.""" + current_answers = answers.get(root_key, {}) if root_key else answers + if (current_value := current_answers.get(self.key, _NOVALUE)) is not _NOVALUE: + return current_value return self.default diff --git a/tests/form/test_question_overrides.py b/tests/form/test_question_overrides.py new file mode 100644 index 0000000..6e79ca0 --- /dev/null +++ b/tests/form/test_question_overrides.py @@ -0,0 +1,74 @@ +from jinja2 import Environment +from tui_forms.form.question import QuestionComputed +from tui_forms.form.question import QuestionConstant + + +def test_question_computed_respects_existing_answer(): + """Verify that QuestionComputed uses an existing answer if provided.""" + env = Environment(autoescape=True) + q = QuestionComputed( + key="test_key", + type="string", + title="Test", + description="", + default="computed-{{ base }}", + ) + answers = {"base": "value", "test_key": "user-override"} + # Should use 'user-override' instead of computing 'computed-value' + assert q.default_value(env, answers) == "user-override" + + +def test_question_computed_computes_when_missing(): + """Verify that QuestionComputed computes the value when answer is missing.""" + env = Environment(autoescape=True) + q = QuestionComputed( + key="test_key", + type="string", + title="Test", + description="", + default="computed-{{ base }}", + ) + answers = {"base": "value"} + assert q.default_value(env, answers) == "computed-value" + + +def test_question_constant_respects_existing_answer(): + """Verify that QuestionConstant uses an existing answer if provided.""" + env = Environment(autoescape=True) + q = QuestionConstant( + key="test_key", + type="string", + title="Test", + description="", + default="constant-value", + ) + answers = {"test_key": "user-override"} + assert q.default_value(env, answers) == "user-override" + + +def test_question_constant_uses_default_when_missing(): + """Verify that QuestionConstant uses the default when answer is missing.""" + env = Environment(autoescape=True) + q = QuestionConstant( + key="test_key", + type="string", + title="Test", + description="", + default="constant-value", + ) + answers = {} + assert q.default_value(env, answers) == "constant-value" + + +def test_question_computed_with_root_key(): + """Verify QuestionComputed works with root_key nesting.""" + env = Environment(autoescape=True) + q = QuestionComputed( + key="test_key", + type="string", + title="Test", + description="", + default="computed-{{ base }}", + ) + answers = {"myroot": {"base": "value", "test_key": "user-override"}} + assert q.default_value(env, answers, root_key="myroot") == "user-override"