Adds ENABLE_SUBSECTION_GRADES_SAVED feature flag to both lms and cms. Also installs the wiring that will allow robust grades to be used for courses that enable it. This functionality is still gated by the feature flag and should not be used until the remaining robust grades work is finished.
70 lines
2.4 KiB
Python
70 lines
2.4 KiB
Python
"""
|
|
Functionality for course-level grades.
|
|
"""
|
|
from collections import namedtuple
|
|
from logging import getLogger
|
|
|
|
import dogstats_wrapper as dog_stats_api
|
|
|
|
from opaque_keys.edx.keys import CourseKey
|
|
from courseware.courses import get_course_by_id
|
|
from .new.course_grade import CourseGradeFactory
|
|
|
|
|
|
log = getLogger(__name__)
|
|
|
|
|
|
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:
|
|
|
|
(student, gradeset, err_msg)
|
|
|
|
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:
|
|
gradeset = summary(student, course)
|
|
yield GradeResult(student, gradeset, "")
|
|
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
|
|
)
|
|
yield GradeResult(student, {}, exc.message)
|
|
|
|
|
|
def summary(student, course):
|
|
"""
|
|
Returns the grade summary of the student for the given course.
|
|
|
|
Also sends a signal to update the minimum grade requirement status.
|
|
"""
|
|
return CourseGradeFactory(student).create(course).summary
|