def _build_correct_map(self, *args): cmap = CorrectMap() for index, correctness in enumerate(args): cmap.update( CorrectMap(answer_id=self._build_question_id(index), correctness=correctness)) return cmap.cmap
def do_reset(self): """ Reset internal state to unfinished, with no answers """ self.student_answers = dict() self.correct_map = CorrectMap() self.done = False
def test_update_from_correctmap(self): # Initialize a CorrectMap with some properties self.cmap.set(answer_id='1_2_1', correctness='correct', npoints=5, msg='Test message', hint='Test hint', hintmode='always', queuestate={ 'key': 'secretstring', 'time': '20130228100026' }) self.cmap.set_overall_message("Test message") # Create a second cmap, then update it to have the same properties # as the first cmap other_cmap = CorrectMap() other_cmap.update(self.cmap) # Assert that it has all the same properties self.assertEqual(other_cmap.get_overall_message(), self.cmap.get_overall_message()) self.assertEqual(other_cmap.get_dict(), self.cmap.get_dict())
def update_score(self, score_msg, queuekey): """ Deliver grading response (e.g. from async code checking) to the specific ResponseType that requested grading Returns an updated CorrectMap """ cmap = CorrectMap() cmap.update(self.correct_map) for responder in self.responders.values(): if hasattr(responder, 'update_score'): # Each LoncapaResponse will update its specific entries in cmap # cmap is passed by reference responder.update_score(score_msg, cmap, queuekey) self.correct_map.set_dict(cmap.get_dict()) return cmap
def _grade_answers(self, student_answers): """ Internal grading call used for checking new 'student_answers' and also rescoring existing student_answers. For new student_answers being graded, `student_answers` is a dict of all the entries from request.POST, but with the first part of each key removed (the string before the first "_"). Thus, for example, input_ID123 -> ID123, and input_fromjs_ID123 -> fromjs_ID123. For rescoring, `student_answers` is None. Calls the Response for each question in this problem, to do the actual grading. """ # old CorrectMap oldcmap = self.correct_map # start new with empty CorrectMap newcmap = CorrectMap() # Call each responsetype instance to do actual grading for responder in self.responders.values(): # File objects are passed only if responsetype explicitly allows # for file submissions. But we have no way of knowing if # student_answers contains a proper answer or the filename of # an earlier submission, so for now skip these entirely. # TODO: figure out where to get file submissions when rescoring. if 'filesubmission' in responder.allowed_inputfields and student_answers is None: _ = self.capa_system.i18n.ugettext raise Exception( _(u"Cannot rescore problems with possible file submissions" )) # use 'student_answers' only if it is provided, and if it might contain a file # submission that would not exist in the persisted "student_answers". if 'filesubmission' in responder.allowed_inputfields and student_answers is not None: results = responder.evaluate_answers(student_answers, oldcmap) else: results = responder.evaluate_answers(self.student_answers, oldcmap) newcmap.update(results) self.correct_map = newcmap return newcmap
def get_score(self, student_answers): graded_answer = json.loads( student_answers[self.answer_id].strip())['answer'] return CorrectMap(self.answer_id, graded_answer)
def setUp(self): self.cmap = CorrectMap()
def setUp(self): super(CorrectMapTest, self).setUp() self.cmap = CorrectMap()
def fix_studentmodule_grade(self, module, save_changes): ''' Fix the grade assigned to a StudentModule''' module_state = module.state if module_state is None: # not likely, since we filter on it. But in general... LOG.info("No state found for {type} module {id} for student {student} in course {course_id}" .format( type=module.module_type, id=module.module_state_key, student=module.student.username, course_id=module.course_id)) return state_dict = json.loads(module_state) self.num_visited += 1 # LoncapaProblem.get_score() checks student_answers -- if there are none, we will return a grade of 0 # Check that this is the case, but do so sooner, before we do any of # the other grading work. student_answers = state_dict['student_answers'] if (not student_answers) or len(student_answers) == 0: # we should not have a grade here: if module.grade != 0: LOG.error("No answer found but grade {grade} exists for {type} module {id} for student {student} " "in course {course_id}".format(grade=module.grade, type=module.module_type, id=module.module_state_key, student=module.student.username, course_id=module.course_id)) else: LOG.debug("No answer and no grade found for {type} module {id} for student {student} " "in course {course_id}".format(grade=module.grade, type=module.module_type, id=module.module_state_key, student=module.student.username, course_id=module.course_id)) return # load into a CorrectMap, as done in LoncapaProblem.__init__(): correct_map = CorrectMap() if 'correct_map' in state_dict: correct_map.set_dict(state_dict['correct_map']) # calculate score the way LoncapaProblem.get_score() works, by deferring to # CorrectMap's get_npoints implementation. correct = 0 for key in correct_map: correct += correct_map.get_npoints(key) if module.grade == correct: # nothing to change LOG.debug("Grade matches for {type} module {id} for student {student} in course {course_id}" .format( type=module.module_type, id=module.module_state_key, student=module.student.username, course_id=module.course_id)) elif save_changes: # make the change LOG.info("Grade changing from {0} to {1} for {type} module {id} for student {student} " "in course {course_id}".format(module.grade, correct, type=module.module_type, id=module.module_state_key, student=module.student.username, course_id=module.course_id)) module.grade = correct module.save() self.num_changed += 1 else: # don't make the change, but log that the change would be made LOG.info("Grade would change from {0} to {1} for {type} module {id} for student {student} " "in course {course_id}".format(module.grade, correct, type=module.module_type, id=module.module_state_key, student=module.student.username, course_id=module.course_id)) self.num_changed += 1
def fix_studentmodule_grade(self, module, save_changes): ''' Fix the grade assigned to a StudentModule''' module_state = module.state if module_state is None: # not likely, since we filter on it. But in general... LOG.info( u"No state found for %s module %s for student %s in course %s", module.module_type, module.module_state_key, module.student.username, module.course_id, ) return state_dict = json.loads(module_state) self.num_visited += 1 # LoncapaProblem.get_score() checks student_answers -- if there are none, we will return a grade of 0 # Check that this is the case, but do so sooner, before we do any of the other grading work. student_answers = state_dict['student_answers'] if (not student_answers) or len(student_answers) == 0: # we should not have a grade here: if module.grade != 0: log_msg = ( u"No answer found but grade %(grade)s exists for %(type)s module %(id)s for student %(student)s " + u"in course %(course_id)s" ) LOG.error(log_msg, { "grade": module.grade, "type": module.module_type, "id": module.module_state_key, "student": module.student.username, "course_id": module.course_id, }) else: log_msg = ( u"No answer and no grade found for %(type)s module %(id)s for student %(student)s " + u"in course %(course_id)s" ) LOG.debug(log_msg, { "grade": module.grade, "type": module.module_type, "id": module.module_state_key, "student": module.student.username, "course_id": module.course_id, }) return # load into a CorrectMap, as done in LoncapaProblem.__init__(): correct_map = CorrectMap() if 'correct_map' in state_dict: correct_map.set_dict(state_dict['correct_map']) # calculate score the way LoncapaProblem.get_score() works, by deferring to # CorrectMap's get_npoints implementation. correct = 0 for key in correct_map: correct += correct_map.get_npoints(key) if module.grade == correct: # nothing to change log_msg = u"Grade matches for %(type)s module %(id)s for student %(student)s in course %(course_id)s" LOG.debug(log_msg, { "type": module.module_type, "id": module.module_state_key, "student": module.student.username, "course_id": module.course_id, }) elif save_changes: # make the change log_msg = ( u"Grade changing from %(grade)s to %(correct)s for %(type)s module " + u"%(id)s for student %(student)s in course %(course_id)s" ) LOG.debug(log_msg, { "grade": module.grade, "correct": correct, "type": module.module_type, "id": module.module_state_key, "student": module.student.username, "course_id": module.course_id, }) module.grade = correct module.save() self.num_changed += 1 else: # don't make the change, but log that the change would be made log_msg = ( u"Grade would change from %(grade)s to %(correct)s for %(type)s module %(id)s for student " + u"%(student)s in course %(course_id)s" ) LOG.debug(log_msg, { "grade": module.grade, "correct": correct, "type": module.module_type, "id": module.module_state_key, "student": module.student.username, "course_id": module.course_id, }) self.num_changed += 1
def setUp(self): super(CorrectMapTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments self.cmap = CorrectMap()