This document explains how to write a CustomResponse problem. CustomResponse problems execute Python script to check student answers and provide hints.
There are two general ways to create a CustomResponse problem:
One format puts the Python code in an <answer> tag:
<problem>
<p>What is the sum of 2 and 3?</p>
<customresponse expect="5">
<textline math="1" />
</customresponse>
<answer>
# Python script goes here
</answer>
</problem>
Example of a checking script:
if answers[0] == expect:
correct[0] = 'correct'
overall_message = 'Good job!'
else:
correct[0] = 'incorrect'
messages[0] = 'This answer is incorrect'
overall_message = 'Please try again'
Important: Python is picky about indentation. Within the <answer> tag, you must begin your script with no indentation.
The other way to create a CustomResponse is to put a “checking function” in a <script> tag, then use the cfn attribute of the <customresponse> tag:
<problem>
<p>What is the sum of 2 and 3?</p>
<customresponse cfn="check_func" expect="5">
<textline math="1" />
</customresponse>
<script type="loncapa/python">
def check_func(expect, ans):
# Python script goes here
</script>
</problem>
Important: Python is picky about indentation. Within the <script> tag, the def check_func(expect, ans): line must have no indentation.
expect is the value of the expect attribute of <customresponse> (if provided)
answer is either:
- The value of the answer the student provided, if there is only one input.
- An ordered list of answers the student provided, if there are multiple inputs.
There are several ways that the check function can indicate whether the student succeeded. The check function can return any of the following:
- True: Indicates that the student answered correctly for all inputs.
- False: Indicates that the student answered incorrectly. All inputs will be marked incorrect.
- A dictionary of the form: { 'ok': True, 'msg': 'Message' } If the dictionary’s value for ok is set to True, all inputs are marked correct; if it is set to False, all inputs are marked incorrect. The msg is displayed beneath all inputs, and it may contain XHTML markup.
- A dictionary of the form
{ 'overall_message': 'Overall message',
'input_list': [
{ 'ok': True, 'msg': 'Feedback for input 1'},
{ 'ok': False, 'msg': 'Feedback for input 2'},
... ] }
The last form is useful for responses that contain multiple inputs. It allows you to provide feedback for each input individually, as well as a message that applies to the entire response.
Example of a checking function:
def check_func(expect, answer_given):
check1 = (int(answer_given[0]) == 1)
check2 = (int(answer_given[1]) == 2)
check3 = (int(answer_given[2]) == 3)
return {'overall_message': 'Overall message',
'input_list': [
{ 'ok': check1, 'msg': 'Feedback 1'},
{ 'ok': check2, 'msg': 'Feedback 2'},
{ 'ok': check3, 'msg': 'Feedback 3'} ] }
The function checks that the user entered 1 for the first input, 2 for the second input, and 3 for the third input. It provides feedback messages for each individual input, as well as a message displayed beneath the entire problem.