Commit 73b25e1f by Brian Wilson

Add check for problems that (do not) support regrading.

parent 07d2de47
......@@ -230,7 +230,6 @@ class LoncapaProblem(object):
if hasattr(the_input, 'ungraded_response'):
the_input.ungraded_response(xqueue_msg, queuekey)
def is_queued(self):
'''
Returns True if any part of the problem has been submitted to an external queue
......@@ -238,7 +237,6 @@ class LoncapaProblem(object):
'''
return any(self.correct_map.is_queued(answer_id) for answer_id in self.correct_map)
def get_recentmost_queuetime(self):
'''
Returns a DateTime object that represents the timestamp of the most recent
......@@ -256,7 +254,6 @@ class LoncapaProblem(object):
return max(queuetimes)
def grade_answers(self, answers):
'''
Grade student responses. Called by capa_module.check_problem.
......@@ -272,6 +269,31 @@ class LoncapaProblem(object):
self.student_answers = convert_files_to_filenames(answers)
return self._grade_answers(answers)
def supports_regrading(self):
"""
Checks that the current problem definition permits regrading.
More precisely, it checks that there are no response types in
the current problem that are not fully supported (yet) for regrading.
This includes responsetypes for which the student's answer
is not properly stored in state, i.e. file submissions. At present,
we have no way to know if an existing response was actually a real
answer or merely the filename of a file submitted as an answer.
It turns out that because regrading is a background task, limiting
it to responsetypes that don't support file submissions also means
that the responsetypes are synchronous. This is convenient as it
permits regrading to be complete when the regrading call returns.
"""
# We check for synchronous grading and no file submissions by
# screening out all problems with a CodeResponse type.
for responder in self.responders.values():
if 'filesubmission' in responder.allowed_inputfields:
return False
return True
def regrade_existing_answers(self):
'''
Regrade student responses. Called by capa_module.regrade_problem.
......@@ -298,14 +320,21 @@ class LoncapaProblem(object):
# log.debug('Responders: %s' % self.responders)
# Call each responsetype instance to do actual grading
for responder in self.responders.values():
# File objects are passed only if responsetype explicitly allows for file
# submissions
# File objects are passed only if responsetype explicitly allows
# for file submissions. But we have no way of knowing if
# student_answers contains a proper answer or the filename of
# an earlier submission, so for now skip these entirely.
# TODO: figure out where to get file submissions when regrading.
if 'filesubmission' in responder.allowed_inputfields and answers is not None:
if 'filesubmission' in responder.allowed_inputfields and answers is None:
raise Exception("Cannot regrade problems with possible file submissions")
# use 'answers' if it is provided, otherwise use the saved student_answers.
if answers is not None:
results = responder.evaluate_answers(answers, oldcmap)
else:
results = responder.evaluate_answers(self.student_answers, oldcmap)
newcmap.update(results)
self.correct_map = newcmap
# log.debug('%s: in grade_answers, answers=%s, cmap=%s' % (self,answers,newcmap))
return newcmap
......
......@@ -822,14 +822,21 @@ class CapaModule(CapaFields, XModule):
Returns a dict with one key:
{'success' : 'correct' | 'incorrect' | AJAX alert msg string }
Raises NotFoundError if called on a problem that has not yet been answered
(since this is avoidable). Returns the error messages for exceptions
occurring while performing the regrading, rather than throwing them.
Raises NotFoundError if called on a problem that has not yet been
answered, or if it's a problem that cannot be regraded.
Returns the error messages for exceptions occurring while performing
the regrading, rather than throwing them.
"""
event_info = dict()
event_info['state'] = self.lcp.get_state()
event_info['problem_id'] = self.location.url()
if not self.lcp.supports_regrading():
event_info['failure'] = 'unsupported'
self.system.track_function('problem_regrade_fail', event_info)
raise NotFoundError('Problem does not support regrading')
if not self.done:
event_info['failure'] = 'unanswered'
self.system.track_function('problem_regrade_fail', event_info)
......
......@@ -641,6 +641,16 @@ class CapaModuleTest(unittest.TestCase):
with self.assertRaises(xmodule.exceptions.NotFoundError):
module.regrade_problem()
def test_regrade_problem_not_supported(self):
# Simulate that the problem is NOT done
module = CapaFactory.create(done=True)
# Try to regrade the problem, and get exception
with patch('capa.capa_problem.LoncapaProblem.supports_regrading') as mock_supports_regrading:
mock_supports_regrading.return_value = False
with self.assertRaises(xmodule.exceptions.NotFoundError):
module.regrade_problem()
def test_regrade_problem_error(self):
# Try each exception that capa_module should handle
......
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