Commit e61a6fe7 by Ned Batchelder

Make it possible for customresponse check functions to get extra arguments,…

Make it possible for customresponse check functions to get extra arguments, though they need to be declared in the XML.
parent c49b0c50
......@@ -927,15 +927,17 @@ class CustomResponse(LoncapaResponse):
# actual function that will re-execute the original script,
# and invoke the function with the data needed.
def make_check_function(script_code, cfn):
def check_function(expect, ans):
def check_function(expect, ans, **kwargs):
extra_args = "".join(", {0}={0}".format(k) for k in kwargs)
code = (
script_code + "\n" +
"cfn_return = %s(expect, ans)\n" % cfn
"cfn_return = %s(expect, ans%s)\n" % (cfn, extra_args)
)
globals_dict = {
'expect': expect,
'ans': ans,
}
globals_dict.update(kwargs)
safe_exec.safe_exec(code, globals_dict)
return globals_dict['cfn_return']
return check_function
......@@ -1063,10 +1065,12 @@ class CustomResponse(LoncapaResponse):
# this is an interface to the Tutor2 check functions
fn = self.code
answer_given = submission[0] if (len(idset) == 1) else submission
kwnames = self.xml.get("cfn_extra_args", "").split()
kwargs = {n:self.context.get(n) for n in kwnames}
log.debug(" submission = %s" % submission)
try:
answer_given = submission[0] if (len(idset) == 1) else submission
ret = fn(self.expect, answer_given)
ret = fn(self.expect, answer_given, **kwargs)
except Exception as err:
log.error("oops in customresponse (cfn) error %s" % err)
# print "context = ",self.context
......
......@@ -221,6 +221,8 @@ class CustomResponseXMLFactory(ResponseXMLFactory):
cfn = kwargs.get('cfn', None)
expect = kwargs.get('expect', None)
answer = kwargs.get('answer', None)
options = kwargs.get('options', None)
cfn_extra_args = kwargs.get('cfn_extra_args', None)
# Create the response element
response_element = etree.Element("customresponse")
......@@ -235,6 +237,12 @@ class CustomResponseXMLFactory(ResponseXMLFactory):
answer_element = etree.SubElement(response_element, "answer")
answer_element.text = str(answer)
if options:
response_element.set('options', str(options))
if cfn_extra_args:
response_element.set('cfn_extra_args', str(cfn_extra_args))
return response_element
def create_input_element(self, **kwargs):
......
......@@ -2,7 +2,6 @@
Tests of responsetypes
"""
from datetime import datetime
import json
from nose.plugins.skip import SkipTest
......@@ -807,7 +806,6 @@ class CustomResponseTest(ResponseTest):
# 'answer_given' is the answer the student gave (if there is just one input)
# or an ordered list of answers (if there are multiple inputs)
#
#
# The function should return a dict of the form
# { 'ok': BOOL, 'msg': STRING }
#
......@@ -917,6 +915,35 @@ class CustomResponseTest(ResponseTest):
self.assertEqual(correct_map.get_msg('1_2_2'), 'Feedback 2')
self.assertEqual(correct_map.get_msg('1_2_3'), 'Feedback 3')
def test_function_code_with_extra_args(self):
script = textwrap.dedent("""\
def check_func(expect, answer_given, options, dynamath):
assert options == "xyzzy", "Options was %r" % options
return {'ok': answer_given == expect, 'msg': 'Message text'}
""")
problem = self.build_problem(script=script, cfn="check_func", expect="42", options="xyzzy", cfn_extra_args="options dynamath")
# Correct answer
input_dict = {'1_2_1': '42'}
correct_map = problem.grade_answers(input_dict)
correctness = correct_map.get_correctness('1_2_1')
msg = correct_map.get_msg('1_2_1')
self.assertEqual(correctness, 'correct')
self.assertEqual(msg, "Message text\n")
# Incorrect answer
input_dict = {'1_2_1': '0'}
correct_map = problem.grade_answers(input_dict)
correctness = correct_map.get_correctness('1_2_1')
msg = correct_map.get_msg('1_2_1')
self.assertEqual(correctness, 'incorrect')
self.assertEqual(msg, "Message text\n")
def test_multiple_inputs_return_one_status(self):
# When given multiple inputs, the 'answer_given' argument
# to the check_func() is a list of inputs
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment