diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py
index 14aec4ccce..801d7dce2f 100644
--- a/common/lib/capa/capa/capa_problem.py
+++ b/common/lib/capa/capa/capa_problem.py
@@ -117,6 +117,9 @@ class LoncapaProblem(object):
# the dict has keys = xml subtree of Response, values = Response instance
self._preprocess_problem(self.tree)
+ if not self.student_answers: # True when student_answers is an empty dict
+ self.set_initial_display()
+
def do_reset(self):
'''
Reset internal state to unfinished, with no answers
@@ -125,6 +128,14 @@ class LoncapaProblem(object):
self.correct_map = CorrectMap()
self.done = False
+ def set_initial_display(self):
+ initial_answers = dict()
+ for responder in self.responders.values():
+ if hasattr(responder,'get_initial_display'):
+ initial_answers.update(responder.get_initial_display())
+
+ self.student_answers = initial_answers
+
def __unicode__(self):
return u"LoncapaProblem ({0})".format(self.problem_id)
@@ -189,7 +200,7 @@ class LoncapaProblem(object):
cmap = CorrectMap()
cmap.update(self.correct_map)
for responder in self.responders.values():
- if hasattr(responder,'update_score'): # TODO: Is this the best way to target 'update_score' of CodeResponse?
+ if hasattr(responder,'update_score'):
# Each LoncapaResponse will update the specific entries of 'cmap' that it's responsible for
cmap = responder.update_score(score_msg, cmap, queuekey)
self.correct_map.set_dict(cmap.get_dict())
diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py
index 617b1cdf33..27f35fafcc 100644
--- a/common/lib/capa/capa/responsetypes.py
+++ b/common/lib/capa/capa/responsetypes.py
@@ -724,6 +724,24 @@ class CodeResponse(LoncapaResponse):
self.tests = xml.get('tests')
+ # Extract 'answer' and 'initial_display' from XML. Note that the code to be exec'ed here is:
+ # (1) Internal edX code, i.e. NOT student submissions, and
+ # (2) The code should only define the strings 'initial_display', 'answer', 'preamble', 'test_program'
+ # following the 6.01 problem definition convention
+ penv = {}
+ penv['__builtins__'] = globals()['__builtins__']
+ try:
+ exec(self.code,penv,penv)
+ except Exception as err:
+ log.error('Error in CodeResponse %s: Error in problem reference code' % err)
+ raise Exception(err)
+ try:
+ self.answer = penv['answer']
+ self.initial_display = penv['initial_display']
+ except Exception as err:
+ log.error("Error in CodeResponse %s: Problem reference code does not define 'answer' and/or 'initial_display' in ..." % err)
+ raise Exception(err)
+
def get_score(self, student_answers):
idset = sorted(self.answer_ids)
@@ -778,22 +796,11 @@ class CodeResponse(LoncapaResponse):
# CodeResponse differentiates from ExternalResponse in the behavior of 'get_answers'. CodeResponse.get_answers
# does NOT require a queue submission, and the answer is computed (extracted from problem XML) locally.
def get_answers(self):
- # Extract the CodeResponse answer from XML
- penv = {}
- penv['__builtins__'] = globals()['__builtins__']
- try:
- exec(self.code,penv,penv)
- except Exception as err:
- log.error('Error in CodeResponse %s: Error in problem reference code' % err)
- raise Exception(err)
- try:
- ans = penv['answer']
- except Exception as err:
- log.error('Error in CodeResponse %s: Problem reference code does not define answer in ...' % err)
- raise Exception(err)
-
- anshtml = '
%s
' % ans
+ anshtml = '
%s
' % self.answer
return dict(zip(self.answer_ids,[anshtml]))
+
+ def get_initial_display(self):
+ return dict(zip(self.answer_ids,[self.initial_display]))
# CodeResponse._send_to_queue implements the same interface as defined for ExternalResponse's 'get_score'
def _send_to_queue(self, extra_payload):