course_grades.py 2.39 KB
Newer Older
1 2 3
"""
Functionality for course-level grades.
"""
4
from collections import namedtuple
5
from logging import getLogger
6

7 8 9 10
import dogstats_wrapper as dog_stats_api

from opaque_keys.edx.keys import CourseKey
from courseware.courses import get_course_by_id
11
from .new.course_grade import CourseGradeFactory
12 13 14 15 16


log = getLogger(__name__)


17 18 19 20 21 22 23
GradeResult = namedtuple('StudentGrade', ['student', 'gradeset', 'err_msg'])


def iterate_grades_for(course_or_id, students):
    """
    Given a course_id and an iterable of students (User), yield a GradeResult
    for every student enrolled in the course.  GradeResult is a named tuple of:
24

25
    (student, gradeset, err_msg)
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

    If an error occurred, gradeset will be an empty dict and err_msg will be an
    exception message. If there was no error, err_msg is an empty string.

    The gradeset is a dictionary with the following fields:

    - grade : A final letter grade.
    - percent : The final percent for the class (rounded up).
        - section_breakdown : A breakdown of each section that makes
        up the grade. (For display)
    - grade_breakdown : A breakdown of the major components that
        make up the final grade. (For display)
    - raw_scores: contains scores for every graded module
    """
    if isinstance(course_or_id, (basestring, CourseKey)):
        course = get_course_by_id(course_or_id)
    else:
        course = course_or_id

    for student in students:
        with dog_stats_api.timer('lms.grades.iterate_grades_for', tags=[u'action:{}'.format(course.id)]):
            try:
48 49
                gradeset = summary(student, course)
                yield GradeResult(student, gradeset, "")
50 51 52 53 54 55 56 57 58 59
            except Exception as exc:  # pylint: disable=broad-except
                # Keep marching on even if this student couldn't be graded for
                # some reason, but log it for future reference.
                log.exception(
                    'Cannot grade student %s (%s) in course %s because of exception: %s',
                    student.username,
                    student.id,
                    course.id,
                    exc.message
                )
60
                yield GradeResult(student, {}, exc.message)
61 62


63
def summary(student, course):
64 65 66 67 68
    """
    Returns the grade summary of the student for the given course.

    Also sends a signal to update the minimum grade requirement status.
    """
69
    return CourseGradeFactory(student).create(course).summary