context.py 2.96 KB
Newer Older
1 2 3
"""
Grading Context
"""
4
from collections import OrderedDict
5

6 7
from openedx.core.djangoapps.content.block_structure.api import get_course_in_cache

8
from .course_grade import CourseGrade
9 10 11
from .scores import possibly_scored


12
def grading_context_for_course(course):
13
    """
14
    Same as grading_context, but takes in a course key.
15
    """
16 17
    course_structure = get_course_in_cache(course.id)
    return grading_context(course, course_structure)
18 19


20
def grading_context(course, course_structure):
21 22
    """
    This returns a dictionary with keys necessary for quickly grading
23
    a student.
24 25

    The grading context has two keys:
26 27
    all_graded_subsections_by_type - This contains all subsections that are
        graded, keyed by subsection format (assignment type).
28

29 30 31
        The values are arrays of dictionaries containing
            "subsection_block" : The subsection block
            "scored_descendants" : An array of usage keys for blocks
32
                that could possibly be in the subsection, for any student
33 34 35 36 37 38 39

    all_graded_blocks - This contains a list of all blocks that can
        affect grading a student. This is used to efficiently fetch
        all the xmodule state for a FieldDataCache without walking
        the descriptor tree again.

    """
40
    count_all_graded_blocks = 0
41
    all_graded_subsections_by_type = OrderedDict()
42 43

    for chapter_key in course_structure.get_children(course_structure.root_block_usage_key):
44 45 46 47
        for subsection_key in course_structure.get_children(chapter_key):
            subsection = course_structure[subsection_key]
            scored_descendants_of_subsection = []
            if subsection.graded:
48 49
                for descendant_key in course_structure.post_order_traversal(
                        filter_func=possibly_scored,
50
                        start_node=subsection_key,
51
                ):
52
                    scored_descendants_of_subsection.append(
53 54 55 56
                        course_structure[descendant_key],
                    )

                # include only those blocks that have scores, not if they are just a parent
57 58
                subsection_info = {
                    'subsection_block': subsection,
59
                    'scored_descendants': [
60
                        child for child in scored_descendants_of_subsection
61 62 63
                        if getattr(child, 'has_score', None)
                    ]
                }
64 65 66 67
                subsection_format = getattr(subsection, 'format', '')
                if subsection_format not in all_graded_subsections_by_type:
                    all_graded_subsections_by_type[subsection_format] = []
                all_graded_subsections_by_type[subsection_format].append(subsection_info)
68
                count_all_graded_blocks += len(scored_descendants_of_subsection)
69 70

    return {
71
        'all_graded_subsections_by_type': all_graded_subsections_by_type,
72 73
        'count_all_graded_blocks': count_all_graded_blocks,
        'subsection_type_graders': CourseGrade.get_subsection_type_graders(course)
74
    }