From 84eb3efa8a2520dfdaa724b811db21345937e4f5 Mon Sep 17 00:00:00 2001 From: kimth Date: Wed, 18 Jul 2012 11:08:17 -0400 Subject: [PATCH] Implemented 'initial_display' for CodeResponse --- common/lib/capa/capa/capa_problem.py | 13 +++++++++- common/lib/capa/capa/responsetypes.py | 37 ++++++++++++++++----------- 2 files changed, 34 insertions(+), 16 deletions(-) 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):