Пример #1
0
 def _compute_block_score(
         self,
         block_key,
         course_structure,
         submissions_scores,
         csm_scores,
         persisted_block=None,
 ):
     """
     Compute score for the given block. If persisted_values
     is provided, it is used for possible and weight.
     """
     try:
         block = course_structure[block_key]
     except KeyError:
         # It's possible that the user's access to that
         # block has changed since the subsection grade
         # was last persisted.
         pass
     else:
         if getattr(block, 'has_score', False):
             problem_score = get_score(
                 submissions_scores,
                 csm_scores,
                 persisted_block,
                 block,
             )
             if problem_score:
                 self.locations_to_scores[block_key] = problem_score
Пример #2
0
 def problem_scores(self):
     """
     Overrides the problem_scores member variable in order
     to return empty scores for all scorable problems in the
     course.
     NOTE: The use of `course_data.structure` here is very intentional.
     It means we look through the user-specific subtree of this subsection,
     taking into account which problems are visible to the user.
     """
     locations = OrderedDict()  # dict of problem locations to ProblemScore
     for block_key in self.course_data.structure.post_order_traversal(
             filter_func=possibly_scored,
             start_node=self.location,
     ):
         block = self.course_data.structure[block_key]
         if getattr(block, 'has_score', False):
             problem_score = get_score(
                 submissions_scores={},
                 csm_scores={},
                 persisted_block=None,
                 block=block,
             )
             if problem_score is not None:
                 locations[block_key] = problem_score
     return locations
Пример #3
0
 def test_get_score(self, submission_value, csm_value, persisted_block_value, block_value, expected_result):
     score = scores.get_score(
         self._create_submissions_scores(submission_value),
         self._create_csm_scores(csm_value),
         self._create_persisted_block(persisted_block_value),
         self._create_block(block_value),
     )
     expected_score = ProblemScore(**expected_result._asdict())
     self.assertEquals(score, expected_score)
Пример #4
0
 def test_get_score(self, submission_value, csm_value, persisted_block_value, block_value, expected_result):
     score = scores.get_score(
         self._create_submissions_scores(submission_value),
         self._create_csm_scores(csm_value),
         self._create_persisted_block(persisted_block_value),
         self._create_block(block_value),
     )
     expected_score = ProblemScore(**expected_result._asdict())
     self.assertEquals(score, expected_score)
Пример #5
0
def get_vertical_score(block_key,
                       course_structure,
                       submissions_scores,
                       csm_scores,
                       persisted_block=None):
    from lms.djangoapps.grades.scores import get_score, ProblemScore  # placed here to avoid circular import

    if block_key.category != VERTICAL_CATEGORY:
        return
    vertical_weight = getattr(course_structure[block_key], "weight", None)
    if not vertical_weight:
        return
    children_keys = course_structure.get_children(block_key)
    children_scores = []
    for child_key in children_keys:
        try:
            block = course_structure[child_key]
        except KeyError:
            # It's possible that the user's access to that
            # block has changed since the subsection grade
            # was last persisted.
            pass
        else:
            if getattr(block, 'has_score', False):
                problem_score = get_score(
                    submissions_scores,
                    csm_scores,
                    persisted_block,
                    block,
                )
                if problem_score:
                    children_scores.append(problem_score)
    if not children_scores:
        return
    vertical_possible = sum(score.possible for score in children_scores)
    vertical_earned = sum(score.earned for score in children_scores)
    weighted_earned = vertical_weight * float(
        vertical_earned) / vertical_possible
    weighted_possible = vertical_weight
    inner_first_attempted = list(score.first_attempted
                                 for score in children_scores)
    vertical_attempted = max(
        inner_first_attempted) if inner_first_attempted else None
    vertical_graded = any(score.graded for score in children_scores)
    vertical_pseudo_problem = ProblemScore(raw_earned=vertical_earned,
                                           raw_possible=vertical_possible,
                                           weighted_earned=weighted_earned,
                                           weighted_possible=weighted_possible,
                                           weight=vertical_weight,
                                           graded=vertical_graded,
                                           first_attempted=vertical_attempted)
    return vertical_pseudo_problem
Пример #6
0
    def _compute_block_score(
        self,
        student,
        block_key,
        course_structure,
        scores_client,
        submissions_scores,
        persisted_values,
    ):
        """
        Compute score for the given block. If persisted_values
        is provided, it is used for possible and weight.
        """
        block = course_structure[block_key]

        if getattr(block, 'has_score', False):

            possible = persisted_values.get('possible', None)
            weight = persisted_values.get('weight',
                                          getattr(block, 'weight', None))

            (earned, possible) = get_score(
                student,
                block,
                scores_client,
                submissions_scores,
                weight,
                possible,
            )

            if earned is not None or possible is not None:
                # There's a chance that the value of graded is not the same
                # value when the problem was scored. Since we get the value
                # from the block_structure.
                #
                # Cannot grade a problem with a denominator of 0.
                # TODO: None > 0 is not python 3 compatible.
                block_graded = self._get_explicit_graded(
                    block, course_structure) if possible > 0 else False

                self.locations_to_weighted_scores[block.location] = (
                    Score(
                        earned,
                        possible,
                        block_graded,
                        block_metadata_utils.display_name_with_default_escaped(
                            block),
                        block.location,
                    ),
                    weight,
                )
Пример #7
0
    def _compute_block_score(
            self,
            student,
            block_key,
            course_structure,
            scores_client,
            submissions_scores,
            persisted_values,
    ):
        """
        Compute score for the given block. If persisted_values
        is provided, it is used for possible and weight.
        """
        block = course_structure[block_key]

        if getattr(block, 'has_score', False):

            possible = persisted_values.get('possible', None)
            weight = persisted_values.get('weight', getattr(block, 'weight', None))

            (earned, possible) = get_score(
                student,
                block,
                scores_client,
                submissions_scores,
                weight,
                possible,
            )

            if earned is not None or possible is not None:
                # There's a chance that the value of graded is not the same
                # value when the problem was scored. Since we get the value
                # from the block_structure.
                #
                # Cannot grade a problem with a denominator of 0.
                # TODO: None > 0 is not python 3 compatible.
                block_graded = self._get_explicit_graded(block, course_structure) if possible > 0 else False

                self.locations_to_weighted_scores[block.location] = (
                    Score(
                        earned,
                        possible,
                        block_graded,
                        block_metadata_utils.display_name_with_default_escaped(block),
                        block.location,
                    ),
                    weight,
                )
Пример #8
0
 def _compute_block_score(  # lint-amnesty, pylint: disable=missing-function-docstring
     block_key,
     course_structure,
     submissions_scores,
     csm_scores,
     persisted_block=None,
 ):
     # TODO: Remove as part of EDUCATOR-4602.
     if str(block_key.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
         log.info(
             'Computing block score for block: ***{}*** in course: ***{}***.'
             .format(
                 str(block_key),
                 str(block_key.course_key),
             ))
     try:
         block = course_structure[block_key]
     except KeyError:
         # TODO: Remove as part of EDUCATOR-4602.
         if str(block_key.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
             log.info(
                 'User\'s access to block: ***{}*** in course: ***{}*** has changed. '
                 'No block score calculated.'.format(
                     str(block_key), str(block_key.course_key)))
         # It's possible that the user's access to that
         # block has changed since the subsection grade
         # was last persisted.
     else:
         if getattr(block, 'has_score', False):
             # TODO: Remove as part of EDUCATOR-4602.
             if str(block_key.course_key
                    ) == 'course-v1:UQx+BUSLEAD5x+2T2019':
                 log.info(
                     'Block: ***{}*** in course: ***{}*** HAS has_score attribute. Continuing.'
                     .format(str(block_key), str(block_key.course_key)))
             return get_score(
                 submissions_scores,
                 csm_scores,
                 persisted_block,
                 block,
             )
         # TODO: Remove as part of EDUCATOR-4602.
         if str(block_key.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
             log.info(
                 'Block: ***{}*** in course: ***{}*** DOES NOT HAVE has_score attribute. '
                 'No block score calculated.'.format(
                     str(block_key), str(block_key.course_key)))
Пример #9
0
 def problem_scores(self):
     """
     Overrides the problem_scores member variable in order
     to return empty scores for all scorable problems in the
     course.
     """
     locations = OrderedDict()  # dict of problem locations to ProblemScore
     for block_key in self.course_data.structure.post_order_traversal(
             filter_func=possibly_scored,
             start_node=self.location,
     ):
         block = self.course_data.structure[block_key]
         if getattr(block, 'has_score', False):
             locations[block_key] = get_score(
                 submissions_scores={}, csm_scores={}, persisted_block=None, block=block,
             )
     return locations
    def _compute_block_score(
        self,
        student,
        block_key,
        course_structure,
        scores_client,
        submissions_scores,
        persisted_values=None,
    ):
        """
        Compute score for the given block. If persisted_values is provided, it will be used for possible and weight.
        """
        block = course_structure[block_key]

        if getattr(block, 'has_score', False):
            (earned, possible) = get_score(
                student,
                block,
                scores_client,
                submissions_scores,
            )

            # There's a chance that the value of weight is not the same value used when the problem was scored,
            # since we can get the value from either block_structure or CSM/submissions.
            weight = getattr(block, 'weight', None)
            if persisted_values:
                possible = persisted_values.get('possible', possible)
                weight = persisted_values.get('weight', weight)

            if earned is not None or possible is not None:
                # cannot grade a problem with a denominator of 0
                block_graded = block.graded if possible > 0 else False

                self.locations_to_weighted_scores[block.location] = (
                    Score(
                        earned,
                        possible,
                        block_graded,
                        block_metadata_utils.display_name_with_default_escaped(
                            block),
                        block.location,
                    ),
                    weight,
                )
Пример #11
0
 def problem_scores(self):
     """
     Overrides the problem_scores member variable in order
     to return empty scores for all scorable problems in the
     course.
     """
     locations = OrderedDict()  # dict of problem locations to ProblemScore
     for block_key in self.course_data.structure.post_order_traversal(
             filter_func=possibly_scored,
             start_node=self.location,
     ):
         block = self.course_data.structure[block_key]
         if getattr(block, 'has_score', False):
             problem_score = get_score(
                 submissions_scores={}, csm_scores={}, persisted_block=None, block=block,
             )
             if problem_score is not None:
                 locations[block_key] = problem_score
     return locations
Пример #12
0
    def _compute_block_score(
            self,
            student,
            block_key,
            course_structure,
            scores_client,
            submissions_scores,
            persisted_values=None,
    ):
        """
        Compute score for the given block. If persisted_values is provided, it will be used for possible and weight.
        """
        block = course_structure[block_key]

        if getattr(block, 'has_score', False):
            (earned, possible) = get_score(
                student,
                block,
                scores_client,
                submissions_scores,
            )

            # There's a chance that the value of weight is not the same value used when the problem was scored,
            # since we can get the value from either block_structure or CSM/submissions.
            weight = block.weight
            if persisted_values:
                possible = persisted_values.get('possible', possible)
                weight = persisted_values.get('weight', weight)

            if earned is not None or possible is not None:
                # cannot grade a problem with a denominator of 0
                block_graded = block.graded if possible > 0 else False

                self.locations_to_weighted_scores[block.location] = (
                    Score(
                        earned,
                        possible,
                        block_graded,
                        block_metadata_utils.display_name_with_default_escaped(block),
                        block.location,
                    ),
                    weight,
                )
Пример #13
0
 def _compute_block_score(
         block_key,
         course_structure,
         submissions_scores,
         csm_scores,
         persisted_block=None,
 ):
     try:
         block = course_structure[block_key]
     except KeyError:
         # It's possible that the user's access to that
         # block has changed since the subsection grade
         # was last persisted.
         pass
     else:
         if getattr(block, 'has_score', False):
             return get_score(
                 submissions_scores,
                 csm_scores,
                 persisted_block,
                 block,
             )
Пример #14
0
 def problem_scores(self):
     """
     Overrides the problem_scores member variable in order
     to return empty scores for all scorable problems in the
     course.
     NOTE: The use of `course_data.structure` here is very intentional.
     It means we look through the user-specific subtree of this subsection,
     taking into account which problems are visible to the user.
     """
     locations = OrderedDict()  # dict of problem locations to ProblemScore
     for block_key in self.course_data.structure.post_order_traversal(
             filter_func=possibly_scored,
             start_node=self.location,
     ):
         block = self.course_data.structure[block_key]
         if getattr(block, 'has_score', False):
             problem_score = get_score(
                 submissions_scores={}, csm_scores={}, persisted_block=None, block=block,
             )
             if problem_score is not None:
                 locations[block_key] = problem_score
     return locations
Пример #15
0
 def _compute_block_score(
     block_key,
     course_structure,
     submissions_scores,
     csm_scores,
     persisted_block=None,
 ):
     try:
         block = course_structure[block_key]
     except KeyError:
         # It's possible that the user's access to that
         # block has changed since the subsection grade
         # was last persisted.
         pass
     else:
         if getattr(block, 'has_score', False):
             return get_score(
                 submissions_scores,
                 csm_scores,
                 persisted_block,
                 block,
             )
Пример #16
0
    def _compute_block_score(
            self,
            block_key,
            course_structure,
            submissions_scores,
            csm_scores,
            persisted_block=None,
    ):
        """
        Compute score for the given block. If persisted_values
        is provided, it is used for possible and weight.
        """
        block = course_structure[block_key]

        if getattr(block, 'has_score', False):
            problem_score = get_score(
                submissions_scores,
                csm_scores,
                persisted_block,
                block,
            )
            if problem_score:
                self.locations_to_scores[block_key] = problem_score
Пример #17
0
    def _compute_block_score(
            self,
            block_key,
            course_structure,
            submissions_scores,
            csm_scores,
            persisted_block=None,
    ):
        """
        Compute score for the given block. If persisted_values
        is provided, it is used for possible and weight.
        """
        block = course_structure[block_key]

        if getattr(block, 'has_score', False):
            problem_score = get_score(
                submissions_scores,
                csm_scores,
                persisted_block,
                block,
            )
            if problem_score:
                self.locations_to_scores[block_key] = problem_score
Пример #18
0
    def compute(self, student, course_structure, scores_client, submissions_scores):
        """
        Compute the grade of this subsection for the given student and course.
        """
        for descendant_key in course_structure.post_order_traversal(
                filter_func=possibly_scored,
                start_node=self.location,
        ):
            descendant = course_structure[descendant_key]

            if not getattr(descendant, 'has_score', False):
                continue

            (earned, possible) = get_score(
                student,
                descendant,
                scores_client,
                submissions_scores,
            )
            if earned is None and possible is None:
                continue

            # cannot grade a problem with a denominator of 0
            descendant_graded = descendant.graded if possible > 0 else False

            self.locations_to_scores[descendant.location] = Score(
                earned,
                possible,
                descendant_graded,
                block_metadata_utils.display_name_with_default_escaped(descendant),
                descendant.location,
            )

        self.all_total, self.graded_total = graders.aggregate_scores(
            self.scores, self.display_name,
        )