Added max score to output of get_student_grade_summary_data.
This will put the actual score and actual max score in scope for the the return_csv function, so actual scores can be dumped. The ultimate goal is to provide this data in the CSV dump that is passed to Stellar via pylmod. This is PR #10395 on edX, and issue 95 on mitocw's edx fork. https://github.com/edx/edx-platform/pull/10395 https://github.com/mitocw/edx-platform/issues/95
This commit is contained in:
3
AUTHORS
3
AUTHORS
@@ -253,4 +253,5 @@ Justin Abrahms <abrahms@mit.edu>
|
||||
Arbab Nazar <arbab@edx.org>
|
||||
Douglas Hall <dhall@edx.org>
|
||||
Awais Jibran <awaisdar001@gmail.com>
|
||||
Muhammad Rehan <muhammadrehan69@gmail.com>
|
||||
Muhammad Rehan <muhammadrehan69@gmail.com>
|
||||
Shawn Milochik <shawn@milochik.com>
|
||||
|
||||
@@ -69,7 +69,7 @@ class TestRawGradeCSV(TestSubmittingProblems):
|
||||
|
||||
def get_expected_grade_data(
|
||||
self, get_grades=True, get_raw_scores=False,
|
||||
use_offline=False):
|
||||
use_offline=False, get_score_max=False):
|
||||
"""
|
||||
Return expected results from the get_student_grade_summary_data call
|
||||
with any options selected.
|
||||
@@ -79,6 +79,11 @@ class TestRawGradeCSV(TestSubmittingProblems):
|
||||
get_student_grade_summary_data for this function to be accurate.
|
||||
If kwargs are added or removed, or the functionality triggered by
|
||||
them changes, this function must be updated to match.
|
||||
|
||||
If get_score_max is True, instead of a single score between 0 and 1,
|
||||
the actual score and total possible are returned. For example, if the
|
||||
student got one out of two possible points, the values (1, 2) will be
|
||||
returned instead of 0.5.
|
||||
"""
|
||||
expected_data = {
|
||||
'students': [self.student_user, self.student_user2],
|
||||
@@ -155,6 +160,10 @@ class TestRawGradeCSV(TestSubmittingProblems):
|
||||
u'ID', u'Username', u'Full Name', u'edX email',
|
||||
u'External email', u'p3', u'p2', u'p1'
|
||||
]
|
||||
# Strip out the single-value float scores and replace them
|
||||
# with two-tuples of actual and possible scores (see docstring).
|
||||
if get_score_max:
|
||||
expected_data["data"][-1][-3:] = (0.0, 1), (1.0, 1.0), (0.0, 1)
|
||||
|
||||
return expected_data
|
||||
|
||||
@@ -197,7 +206,7 @@ class TestRawGradeCSV(TestSubmittingProblems):
|
||||
request, self.course, get_grades=False
|
||||
)
|
||||
expected_data = self.get_expected_grade_data(get_grades=False)
|
||||
# if get_grades == False, get_expected_grade_data does not
|
||||
# if get_grades is False, get_expected_grade_data does not
|
||||
# add an "assignments" key.
|
||||
self.assertNotIn("assignments", expected_data)
|
||||
self.compare_data(data, expected_data)
|
||||
@@ -228,6 +237,22 @@ class TestRawGradeCSV(TestSubmittingProblems):
|
||||
)
|
||||
self.compare_data(data, expected_data)
|
||||
|
||||
def test_grade_summary_data_get_score_max(self):
|
||||
"""
|
||||
Test grade summary data report generation with get_score_max set
|
||||
to True (also requires get_raw_scores to be True).
|
||||
"""
|
||||
request = DummyRequest()
|
||||
self.answer_question()
|
||||
data = get_student_grade_summary_data(
|
||||
request, self.course, use_offline=True, get_raw_scores=True,
|
||||
get_score_max=True,
|
||||
)
|
||||
expected_data = self.get_expected_grade_data(
|
||||
use_offline=True, get_raw_scores=True, get_score_max=True,
|
||||
)
|
||||
self.compare_data(data, expected_data)
|
||||
|
||||
def compare_data(self, data, expected_data):
|
||||
"""
|
||||
Compare the output of the get_student_grade_summary_data
|
||||
|
||||
@@ -631,17 +631,21 @@ class GradeTable(object):
|
||||
self.grades = {}
|
||||
self._current_row = {}
|
||||
|
||||
def _add_grade_to_row(self, component, score):
|
||||
def _add_grade_to_row(self, component, score, possible=None):
|
||||
"""Creates component if needed, and assigns score
|
||||
|
||||
Args:
|
||||
component (str): Course component being graded
|
||||
score (float): Score of student on component
|
||||
possible (float): Max possible score for the component
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
component_index = self.components.setdefault(component, len(self.components))
|
||||
if possible is not None:
|
||||
# send a tuple instead of a single value
|
||||
score = (score, possible)
|
||||
self._current_row[component_index] = score
|
||||
|
||||
@contextmanager
|
||||
@@ -681,7 +685,10 @@ class GradeTable(object):
|
||||
return self.components.keys()
|
||||
|
||||
|
||||
def get_student_grade_summary_data(request, course, get_grades=True, get_raw_scores=False, use_offline=False):
|
||||
def get_student_grade_summary_data(
|
||||
request, course, get_grades=True, get_raw_scores=False,
|
||||
use_offline=False, get_score_max=False
|
||||
):
|
||||
"""
|
||||
Return data arrays with student identity and grades for specified course.
|
||||
|
||||
@@ -697,6 +704,11 @@ def get_student_grade_summary_data(request, course, get_grades=True, get_raw_sco
|
||||
data = list (one per student) of lists of data corresponding to the fields
|
||||
|
||||
If get_raw_scores=True, then instead of grade summaries, the raw grades for all graded modules are returned.
|
||||
|
||||
If get_score_max is True, two values will be returned for each grade -- the
|
||||
total number of points earned and the total number of points possible. For
|
||||
example, if two points are possible and one is earned, (1, 2) will be
|
||||
returned instead of 0.5 (the default).
|
||||
"""
|
||||
course_key = course.id
|
||||
enrolled_students = User.objects.filter(
|
||||
@@ -723,9 +735,18 @@ def get_student_grade_summary_data(request, course, get_grades=True, get_raw_sco
|
||||
log.debug(u'student=%s, gradeset=%s', student, gradeset)
|
||||
with gtab.add_row(student.id) as add_grade:
|
||||
if get_raw_scores:
|
||||
# TODO (ichuang) encode Score as dict instead of as list, so score[0] -> score['earned']
|
||||
# The following code calls add_grade, which is an alias
|
||||
# for the add_row method on the GradeTable class. This adds
|
||||
# a grade for each assignment. Depending on whether
|
||||
# get_score_max is True, it will return either a single
|
||||
# value as a float between 0 and 1, or a two-tuple
|
||||
# containing the earned score and possible score for
|
||||
# the assignment (see docstring).
|
||||
for score in gradeset['raw_scores']:
|
||||
add_grade(score.section, getattr(score, 'earned', score[0]))
|
||||
if get_score_max is True:
|
||||
add_grade(score.section, score.earned, score.possible)
|
||||
else:
|
||||
add_grade(score.section, score.earned)
|
||||
else:
|
||||
for grade_item in gradeset['section_breakdown']:
|
||||
add_grade(grade_item['label'], grade_item['percent'])
|
||||
|
||||
Reference in New Issue
Block a user