예제 #1
0
 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
예제 #2
0
 def do_reset(self):
     """
     Reset internal state to unfinished, with no answers
     """
     self.student_answers = dict()
     self.correct_map = CorrectMap()
     self.done = False
예제 #3
0
    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())
예제 #4
0
    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
예제 #5
0
    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
예제 #6
0
 def get_score(self, student_answers):
     graded_answer = json.loads(
         student_answers[self.answer_id].strip())['answer']
     return CorrectMap(self.answer_id, graded_answer)
예제 #7
0
 def setUp(self):
     self.cmap = CorrectMap()
예제 #8
0
 def setUp(self):
     super(CorrectMapTest, self).setUp()
     self.cmap = CorrectMap()
예제 #9
0
    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
예제 #10
0
    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
예제 #11
0
 def setUp(self):
     super(CorrectMapTest, self).setUp()  # lint-amnesty, pylint: disable=super-with-arguments
     self.cmap = CorrectMap()