Commit 1abfff22 by Brian Wilson

when grading, check for always-regrade at the section level too

parent 9c4a88b5
...@@ -13,7 +13,6 @@ from xblock.core import Scope ...@@ -13,7 +13,6 @@ from xblock.core import Scope
from .module_render import get_module, get_module_for_descriptor from .module_render import get_module, get_module_for_descriptor
from xmodule import graders from xmodule import graders
from xmodule.capa_module import CapaModule from xmodule.capa_module import CapaModule
from xmodule.course_module import CourseDescriptor
from xmodule.graders import Score from xmodule.graders import Score
from .models import StudentModule from .models import StudentModule
...@@ -43,7 +42,6 @@ def yield_dynamic_descriptor_descendents(descriptor, module_creator): ...@@ -43,7 +42,6 @@ def yield_dynamic_descriptor_descendents(descriptor, module_creator):
else: else:
return descriptor.get_children() return descriptor.get_children()
stack = [descriptor] stack = [descriptor]
while len(stack) > 0: while len(stack) > 0:
...@@ -66,7 +64,7 @@ def yield_problems(request, course, student): ...@@ -66,7 +64,7 @@ def yield_problems(request, course, student):
).values_list('module_state_key', flat=True)) ).values_list('module_state_key', flat=True))
sections_to_list = [] sections_to_list = []
for section_format, sections in grading_context['graded_sections'].iteritems(): for _, sections in grading_context['graded_sections'].iteritems():
for section in sections: for section in sections:
section_descriptor = section['section_descriptor'] section_descriptor = section['section_descriptor']
...@@ -123,7 +121,7 @@ def answer_distributions(request, course): ...@@ -123,7 +121,7 @@ def answer_distributions(request, course):
def grade(student, request, course, model_data_cache=None, keep_raw_scores=False): def grade(student, request, course, model_data_cache=None, keep_raw_scores=False):
""" """
This grades a student as quickly as possible. It retuns the This grades a student as quickly as possible. It returns the
output from the course grader, augmented with the final letter output from the course grader, augmented with the final letter
grade. The keys in the output are: grade. The keys in the output are:
...@@ -158,6 +156,12 @@ def grade(student, request, course, model_data_cache=None, keep_raw_scores=False ...@@ -158,6 +156,12 @@ def grade(student, request, course, model_data_cache=None, keep_raw_scores=False
should_grade_section = False should_grade_section = False
# If we haven't seen a single problem in the section, we don't have to grade it at all! We can assume 0% # If we haven't seen a single problem in the section, we don't have to grade it at all! We can assume 0%
for moduledescriptor in section['xmoduledescriptors']: for moduledescriptor in section['xmoduledescriptors']:
# some problems have state that is updated independently of interaction
# with the LMS, so they need to always be scored. (E.g. foldit.)
if moduledescriptor.always_recalculate_grades:
should_grade_section = True
break
# Create a fake key to pull out a StudentModule object from the ModelDataCache # Create a fake key to pull out a StudentModule object from the ModelDataCache
key = LmsKeyValueStore.Key( key = LmsKeyValueStore.Key(
...@@ -174,7 +178,8 @@ def grade(student, request, course, model_data_cache=None, keep_raw_scores=False ...@@ -174,7 +178,8 @@ def grade(student, request, course, model_data_cache=None, keep_raw_scores=False
scores = [] scores = []
def create_module(descriptor): def create_module(descriptor):
# TODO: We need the request to pass into here. If we could forgo that, our arguments '''creates an XModule instance given a descriptor'''
# TODO: We need the request to pass into here. If we could forego that, our arguments
# would be simpler # would be simpler
return get_module_for_descriptor(student, request, descriptor, model_data_cache, course.id) return get_module_for_descriptor(student, request, descriptor, model_data_cache, course.id)
...@@ -197,18 +202,18 @@ def grade(student, request, course, model_data_cache=None, keep_raw_scores=False ...@@ -197,18 +202,18 @@ def grade(student, request, course, model_data_cache=None, keep_raw_scores=False
scores.append(Score(correct, total, graded, module_descriptor.display_name_with_default)) scores.append(Score(correct, total, graded, module_descriptor.display_name_with_default))
section_total, graded_total = graders.aggregate_scores(scores, section_name) _, graded_total = graders.aggregate_scores(scores, section_name)
if keep_raw_scores: if keep_raw_scores:
raw_scores += scores raw_scores += scores
else: else:
section_total = Score(0.0, 1.0, False, section_name)
graded_total = Score(0.0, 1.0, True, section_name) graded_total = Score(0.0, 1.0, True, section_name)
#Add the graded total to totaled_scores #Add the graded total to totaled_scores
if graded_total.possible > 0: if graded_total.possible > 0:
format_scores.append(graded_total) format_scores.append(graded_total)
else: else:
log.exception("Unable to grade a section with a total possible score of zero. " + str(section_descriptor.location)) log.exception("Unable to grade a section with a total possible score of zero. " +
str(section_descriptor.location))
totaled_scores[section_format] = format_scores totaled_scores[section_format] = format_scores
...@@ -274,12 +279,9 @@ def progress_summary(student, request, course, model_data_cache): ...@@ -274,12 +279,9 @@ def progress_summary(student, request, course, model_data_cache):
""" """
# TODO: We need the request to pass into here. If we could forego that, our arguments
# TODO: We need the request to pass into here. If we could forgo that, our arguments
# would be simpler # would be simpler
course_module = get_module(student, request, course_module = get_module(student, request, course.location, model_data_cache, course.id, depth=None)
course.location, model_data_cache,
course.id, depth=None)
if not course_module: if not course_module:
# This student must not have access to the course. # This student must not have access to the course.
return None return None
...@@ -310,20 +312,19 @@ def progress_summary(student, request, course, model_data_cache): ...@@ -310,20 +312,19 @@ def progress_summary(student, request, course, model_data_cache):
if correct is None and total is None: if correct is None and total is None:
continue continue
scores.append(Score(correct, total, graded, scores.append(Score(correct, total, graded, module_descriptor.display_name_with_default))
module_descriptor.display_name_with_default))
scores.reverse() scores.reverse()
section_total, graded_total = graders.aggregate_scores( section_total, _ = graders.aggregate_scores(
scores, section_module.display_name_with_default) scores, section_module.display_name_with_default)
format = section_module.lms.format if section_module.lms.format is not None else '' module_format = section_module.lms.format if section_module.lms.format is not None else ''
sections.append({ sections.append({
'display_name': section_module.display_name_with_default, 'display_name': section_module.display_name_with_default,
'url_name': section_module.url_name, 'url_name': section_module.url_name,
'scores': scores, 'scores': scores,
'section_total': section_total, 'section_total': section_total,
'format': format, 'format': module_format,
'due': section_module.lms.due, 'due': section_module.lms.due,
'graded': graded, 'graded': graded,
}) })
...@@ -353,11 +354,13 @@ def get_score(course_id, user, problem_descriptor, module_creator, model_data_ca ...@@ -353,11 +354,13 @@ def get_score(course_id, user, problem_descriptor, module_creator, model_data_ca
if not user.is_authenticated(): if not user.is_authenticated():
return (None, None) return (None, None)
# some problems have state that is updated independently of interaction
# with the LMS, so they need to always be scored. (E.g. foldit.)
if problem_descriptor.always_recalculate_grades: if problem_descriptor.always_recalculate_grades:
problem = module_creator(problem_descriptor) problem = module_creator(problem_descriptor)
d = problem.get_score() score = problem.get_score()
if d is not None: if score is not None:
return (d['score'], d['total']) return (score['score'], score['total'])
else: else:
return (None, None) return (None, None)
...@@ -394,7 +397,7 @@ def get_score(course_id, user, problem_descriptor, module_creator, model_data_ca ...@@ -394,7 +397,7 @@ def get_score(course_id, user, problem_descriptor, module_creator, model_data_ca
if total is None: if total is None:
return (None, None) return (None, None)
#Now we re-weight the problem, if specified # Now we re-weight the problem, if specified
weight = problem_descriptor.weight weight = problem_descriptor.weight
if weight is not None: if weight is not None:
if total == 0: if total == 0:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment