From a15388b20cb42e04cc0e0a4b748fba5376484c01 Mon Sep 17 00:00:00 2001 From: Martin Segado Date: Sun, 13 Dec 2015 15:30:43 -0500 Subject: [PATCH] Allow python variable interpolation in CustomResponse 'expect' and 'answer' attributes --- common/lib/capa/capa/responsetypes.py | 2 +- .../capa/capa/tests/response_xml_factory.py | 7 +++++ .../lib/capa/capa/tests/test_responsetypes.py | 27 +++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 14f5069a0b..aae672795f 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -2208,7 +2208,7 @@ class CustomResponse(LoncapaResponse): # if has an "expect" (or "answer") attribute then save # that - self.expect = xml.get('expect') or xml.get('answer') + self.expect = contextualize_text(xml.get('expect') or xml.get('answer'), self.context) log.debug('answer_ids=%s', self.answer_ids) diff --git a/common/lib/capa/capa/tests/response_xml_factory.py b/common/lib/capa/capa/tests/response_xml_factory.py index f780cdaa72..fc2b84159f 100644 --- a/common/lib/capa/capa/tests/response_xml_factory.py +++ b/common/lib/capa/capa/tests/response_xml_factory.py @@ -264,11 +264,15 @@ class CustomResponseXMLFactory(ResponseXMLFactory): *expect*: The value passed to the function cfn *answer*: Inline script that calculates the answer + + *answer_attr*: The "answer" attribute on the tag itself (treated as an + alias to "expect", though "expect" takes priority if both are given) """ # Retrieve **kwargs cfn = kwargs.get('cfn', None) expect = kwargs.get('expect', None) + answer_attr = kwargs.get('answer_attr', None) answer = kwargs.get('answer', None) options = kwargs.get('options', None) cfn_extra_args = kwargs.get('cfn_extra_args', None) @@ -282,6 +286,9 @@ class CustomResponseXMLFactory(ResponseXMLFactory): if expect: response_element.set('expect', str(expect)) + if answer_attr: + response_element.set('answer', str(answer_attr)) + if answer: answer_element = etree.SubElement(response_element, "answer") answer_element.text = str(answer) diff --git a/common/lib/capa/capa/tests/test_responsetypes.py b/common/lib/capa/capa/tests/test_responsetypes.py index a3a91e440f..e7ca5b5b72 100644 --- a/common/lib/capa/capa/tests/test_responsetypes.py +++ b/common/lib/capa/capa/tests/test_responsetypes.py @@ -1799,6 +1799,33 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-docstring self.assertEqual(correct_map.get_npoints('1_2_1'), 0.5) self.assertEqual(correct_map.get_correctness('1_2_1'), 'partially-correct') + def test_script_context(self): + # Ensure that python script variables can be used in the "expect" and "answer" fields, + + script = script = textwrap.dedent(""" + expected_ans = 42 + + def check_func(expect, answer_given): + return answer_given == expect + """) + + problems = ( + self.build_problem(script=script, cfn="check_func", expect="$expected_ans"), + self.build_problem(script=script, cfn="check_func", answer_attr="$expected_ans") + ) + + input_dict = {'1_2_1': '42'} + + for problem in problems: + correctmap = problem.grade_answers(input_dict) + + # CustomResponse also adds 'expect' to the problem context; check that directly first: + self.assertEqual(problem.context['expect'], '42') + + # Also make sure the problem was graded correctly: + correctness = correctmap.get_correctness('1_2_1') + self.assertEqual(correctness, 'correct') + def test_function_code_multiple_input_no_msg(self): # Check functions also have the option of returning