def test_update_from_correctmap(self): # Initialize a CorrectMap with some properties self.cmap.set( answer_id='1_2_1', correctness='correct', npoints=5, msg='Test message', hint='Test hint', hintmode='always', queuestate={ 'key': 'secretstring', 'time': '20130228100026' } ) self.cmap.set_overall_message("Test message") # Create a second cmap, then update it to have the same properties # as the first cmap other_cmap = CorrectMap() other_cmap.update(self.cmap) # Assert that it has all the same properties self.assertEqual( other_cmap.get_overall_message(), self.cmap.get_overall_message() ) self.assertEqual( other_cmap.get_dict(), self.cmap.get_dict() )
def update_score(self, score_msg, queuekey): """ Deliver grading response (e.g. from async code checking) to the specific ResponseType that requested grading Returns an updated CorrectMap """ cmap = CorrectMap() cmap.update(self.correct_map) for responder in self.responders.values(): if hasattr(responder, "update_score"): # Each LoncapaResponse will update its specific entries in cmap # cmap is passed by reference responder.update_score(score_msg, cmap, queuekey) self.correct_map.set_dict(cmap.get_dict()) return cmap
def update_score(self, score_msg, queuekey): """ Deliver grading response (e.g. from async code checking) to the specific ResponseType that requested grading Returns an updated CorrectMap """ cmap = CorrectMap() cmap.update(self.correct_map) for responder in self.responders.values(): if hasattr(responder, 'update_score'): # Each LoncapaResponse will update its specific entries in cmap # cmap is passed by reference responder.update_score(score_msg, cmap, queuekey) self.correct_map.set_dict(cmap.get_dict()) return cmap
def _grade_answers(self, student_answers): """ Internal grading call used for checking new 'student_answers' and also rescoring existing student_answers. For new student_answers being graded, `student_answers` is a dict of all the entries from request.POST, but with the first part of each key removed (the string before the first "_"). Thus, for example, input_ID123 -> ID123, and input_fromjs_ID123 -> fromjs_ID123. For rescoring, `student_answers` is None. Calls the Response for each question in this problem, to do the actual grading. """ # old CorrectMap oldcmap = self.correct_map # start new with empty CorrectMap newcmap = CorrectMap() # 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. 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 rescoring. if 'filesubmission' in responder.allowed_inputfields and student_answers is None: _ = self.capa_system.i18n.ugettext raise Exception( _(u"Cannot rescore problems with possible file submissions" )) # use 'student_answers' only if it is provided, and if it might contain a file # submission that would not exist in the persisted "student_answers". if 'filesubmission' in responder.allowed_inputfields and student_answers is not None: results = responder.evaluate_answers(student_answers, oldcmap) else: results = responder.evaluate_answers(self.student_answers, oldcmap) newcmap.update(results) self.correct_map = newcmap return newcmap
def _grade_answers(self, student_answers): """ Internal grading call used for checking new 'student_answers' and also rescoring existing student_answers. For new student_answers being graded, `student_answers` is a dict of all the entries from request.POST, but with the first part of each key removed (the string before the first "_"). Thus, for example, input_ID123 -> ID123, and input_fromjs_ID123 -> fromjs_ID123. For rescoring, `student_answers` is None. Calls the Response for each question in this problem, to do the actual grading. """ # old CorrectMap oldcmap = self.correct_map # start new with empty CorrectMap newcmap = CorrectMap() # 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. 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 rescoring. if "filesubmission" in responder.allowed_inputfields and student_answers is None: _ = self.capa_system.i18n.ugettext raise Exception(_(u"Cannot rescore problems with possible file submissions")) # use 'student_answers' only if it is provided, and if it might contain a file # submission that would not exist in the persisted "student_answers". if "filesubmission" in responder.allowed_inputfields and student_answers is not None: results = responder.evaluate_answers(student_answers, oldcmap) else: results = responder.evaluate_answers(self.student_answers, oldcmap) newcmap.update(results) self.correct_map = newcmap return newcmap
def test_update_from_correctmap(self): # Initialize a CorrectMap with some properties self.cmap.set(answer_id='1_2_1', correctness='correct', npoints=5, msg='Test message', hint='Test hint', hintmode='always', queuestate={'key':'secretstring', 'time':'20130228100026'}) self.cmap.set_overall_message("Test message") # Create a second cmap, then update it to have the same properties # as the first cmap other_cmap = CorrectMap() other_cmap.update(self.cmap) # Assert that it has all the same properties self.assertEqual(other_cmap.get_overall_message(), self.cmap.get_overall_message()) self.assertEqual(other_cmap.get_dict(), self.cmap.get_dict())
def _build_correct_map(self, *args): cmap = CorrectMap() for index, correctness in enumerate(args): cmap.update(CorrectMap(answer_id=self._build_question_id(index), correctness=correctness)) return cmap.cmap
class CorrectMapTest(unittest.TestCase): """ Tests to verify that CorrectMap behaves correctly """ def setUp(self): self.cmap = CorrectMap() def test_set_input_properties(self): # Set the correctmap properties for two inputs self.cmap.set(answer_id='1_2_1', correctness='correct', npoints=5, msg='Test message', hint='Test hint', hintmode='always', queuestate={ 'key': 'secretstring', 'time': '20130228100026' }) self.cmap.set(answer_id='2_2_1', correctness='incorrect', npoints=None, msg=None, hint=None, hintmode=None, queuestate=None) # Assert that each input has the expected properties self.assertTrue(self.cmap.is_correct('1_2_1')) self.assertFalse(self.cmap.is_correct('2_2_1')) self.assertEqual(self.cmap.get_correctness('1_2_1'), 'correct') self.assertEqual(self.cmap.get_correctness('2_2_1'), 'incorrect') self.assertEqual(self.cmap.get_npoints('1_2_1'), 5) self.assertEqual(self.cmap.get_npoints('2_2_1'), 0) self.assertEqual(self.cmap.get_msg('1_2_1'), 'Test message') self.assertEqual(self.cmap.get_msg('2_2_1'), None) self.assertEqual(self.cmap.get_hint('1_2_1'), 'Test hint') self.assertEqual(self.cmap.get_hint('2_2_1'), None) self.assertEqual(self.cmap.get_hintmode('1_2_1'), 'always') self.assertEqual(self.cmap.get_hintmode('2_2_1'), None) self.assertTrue(self.cmap.is_queued('1_2_1')) self.assertFalse(self.cmap.is_queued('2_2_1')) self.assertEqual(self.cmap.get_queuetime_str('1_2_1'), '20130228100026') self.assertEqual(self.cmap.get_queuetime_str('2_2_1'), None) self.assertTrue(self.cmap.is_right_queuekey('1_2_1', 'secretstring')) self.assertFalse(self.cmap.is_right_queuekey('1_2_1', 'invalidstr')) self.assertFalse(self.cmap.is_right_queuekey('1_2_1', '')) self.assertFalse(self.cmap.is_right_queuekey('1_2_1', None)) self.assertFalse(self.cmap.is_right_queuekey('2_2_1', 'secretstring')) self.assertFalse(self.cmap.is_right_queuekey('2_2_1', 'invalidstr')) self.assertFalse(self.cmap.is_right_queuekey('2_2_1', '')) self.assertFalse(self.cmap.is_right_queuekey('2_2_1', None)) def test_get_npoints(self): # Set the correctmap properties for 4 inputs # 1) correct, 5 points # 2) correct, None points # 3) incorrect, 5 points # 4) incorrect, None points # 5) correct, 0 points self.cmap.set(answer_id='1_2_1', correctness='correct', npoints=5) self.cmap.set(answer_id='2_2_1', correctness='correct', npoints=None) self.cmap.set(answer_id='3_2_1', correctness='incorrect', npoints=5) self.cmap.set(answer_id='4_2_1', correctness='incorrect', npoints=None) self.cmap.set(answer_id='5_2_1', correctness='correct', npoints=0) # Assert that we get the expected points # If points assigned --> npoints # If no points assigned and correct --> 1 point # If no points assigned and incorrect --> 0 points self.assertEqual(self.cmap.get_npoints('1_2_1'), 5) self.assertEqual(self.cmap.get_npoints('2_2_1'), 1) self.assertEqual(self.cmap.get_npoints('3_2_1'), 5) self.assertEqual(self.cmap.get_npoints('4_2_1'), 0) self.assertEqual(self.cmap.get_npoints('5_2_1'), 0) def test_set_overall_message(self): # Default is an empty string string self.assertEqual(self.cmap.get_overall_message(), "") # Set a message that applies to the whole question self.cmap.set_overall_message("Test message") # Retrieve the message self.assertEqual(self.cmap.get_overall_message(), "Test message") # Setting the message to None --> empty string self.cmap.set_overall_message(None) self.assertEqual(self.cmap.get_overall_message(), "") def test_update_from_correctmap(self): # Initialize a CorrectMap with some properties self.cmap.set(answer_id='1_2_1', correctness='correct', npoints=5, msg='Test message', hint='Test hint', hintmode='always', queuestate={ 'key': 'secretstring', 'time': '20130228100026' }) self.cmap.set_overall_message("Test message") # Create a second cmap, then update it to have the same properties # as the first cmap other_cmap = CorrectMap() other_cmap.update(self.cmap) # Assert that it has all the same properties self.assertEqual(other_cmap.get_overall_message(), self.cmap.get_overall_message()) self.assertEqual(other_cmap.get_dict(), self.cmap.get_dict()) def test_update_from_invalid(self): # Should get an exception if we try to update() a CorrectMap # with a non-CorrectMap value invalid_list = [None, "string", 5, datetime.datetime.today()] for invalid in invalid_list: with self.assertRaises(Exception): self.cmap.update(invalid)
class CorrectMapTest(unittest.TestCase): """ Tests to verify that CorrectMap behaves correctly """ def setUp(self): super(CorrectMapTest, self).setUp() self.cmap = CorrectMap() def test_set_input_properties(self): # Set the correctmap properties for two inputs self.cmap.set( answer_id='1_2_1', correctness='correct', npoints=5, msg='Test message', hint='Test hint', hintmode='always', queuestate={ 'key': 'secretstring', 'time': '20130228100026' } ) self.cmap.set( answer_id='2_2_1', correctness='incorrect', npoints=None, msg=None, hint=None, hintmode=None, queuestate=None ) # Assert that each input has the expected properties self.assertTrue(self.cmap.is_correct('1_2_1')) self.assertFalse(self.cmap.is_correct('2_2_1')) self.assertEqual(self.cmap.get_correctness('1_2_1'), 'correct') self.assertEqual(self.cmap.get_correctness('2_2_1'), 'incorrect') self.assertEqual(self.cmap.get_npoints('1_2_1'), 5) self.assertEqual(self.cmap.get_npoints('2_2_1'), 0) self.assertEqual(self.cmap.get_msg('1_2_1'), 'Test message') self.assertEqual(self.cmap.get_msg('2_2_1'), None) self.assertEqual(self.cmap.get_hint('1_2_1'), 'Test hint') self.assertEqual(self.cmap.get_hint('2_2_1'), None) self.assertEqual(self.cmap.get_hintmode('1_2_1'), 'always') self.assertEqual(self.cmap.get_hintmode('2_2_1'), None) self.assertTrue(self.cmap.is_queued('1_2_1')) self.assertFalse(self.cmap.is_queued('2_2_1')) self.assertEqual(self.cmap.get_queuetime_str('1_2_1'), '20130228100026') self.assertEqual(self.cmap.get_queuetime_str('2_2_1'), None) self.assertTrue(self.cmap.is_right_queuekey('1_2_1', 'secretstring')) self.assertFalse(self.cmap.is_right_queuekey('1_2_1', 'invalidstr')) self.assertFalse(self.cmap.is_right_queuekey('1_2_1', '')) self.assertFalse(self.cmap.is_right_queuekey('1_2_1', None)) self.assertFalse(self.cmap.is_right_queuekey('2_2_1', 'secretstring')) self.assertFalse(self.cmap.is_right_queuekey('2_2_1', 'invalidstr')) self.assertFalse(self.cmap.is_right_queuekey('2_2_1', '')) self.assertFalse(self.cmap.is_right_queuekey('2_2_1', None)) def test_get_npoints(self): # Set the correctmap properties for 4 inputs # 1) correct, 5 points # 2) correct, None points # 3) incorrect, 5 points # 4) incorrect, None points # 5) correct, 0 points self.cmap.set( answer_id='1_2_1', correctness='correct', npoints=5.3 ) self.cmap.set( answer_id='2_2_1', correctness='correct', npoints=None ) self.cmap.set( answer_id='3_2_1', correctness='incorrect', npoints=5 ) self.cmap.set( answer_id='4_2_1', correctness='incorrect', npoints=None ) self.cmap.set( answer_id='5_2_1', correctness='correct', npoints=0 ) # Assert that we get the expected points # If points assigned --> npoints # If no points assigned and correct --> 1 point # If no points assigned and incorrect --> 0 points self.assertEqual(self.cmap.get_npoints('1_2_1'), 5.3) self.assertEqual(self.cmap.get_npoints('2_2_1'), 1) self.assertEqual(self.cmap.get_npoints('3_2_1'), 5) self.assertEqual(self.cmap.get_npoints('4_2_1'), 0) self.assertEqual(self.cmap.get_npoints('5_2_1'), 0) def test_set_overall_message(self): # Default is an empty string string self.assertEqual(self.cmap.get_overall_message(), "") # Set a message that applies to the whole question self.cmap.set_overall_message("Test message") # Retrieve the message self.assertEqual(self.cmap.get_overall_message(), "Test message") # Setting the message to None --> empty string self.cmap.set_overall_message(None) self.assertEqual(self.cmap.get_overall_message(), "") def test_update_from_correctmap(self): # Initialize a CorrectMap with some properties self.cmap.set( answer_id='1_2_1', correctness='correct', npoints=5, msg='Test message', hint='Test hint', hintmode='always', queuestate={ 'key': 'secretstring', 'time': '20130228100026' } ) self.cmap.set_overall_message("Test message") # Create a second cmap, then update it to have the same properties # as the first cmap other_cmap = CorrectMap() other_cmap.update(self.cmap) # Assert that it has all the same properties self.assertEqual( other_cmap.get_overall_message(), self.cmap.get_overall_message() ) self.assertEqual( other_cmap.get_dict(), self.cmap.get_dict() ) def test_update_from_invalid(self): # Should get an exception if we try to update() a CorrectMap # with a non-CorrectMap value invalid_list = [None, "string", 5, datetime.datetime.today()] for invalid in invalid_list: with self.assertRaises(Exception): self.cmap.update(invalid)
class CorrectMapTest(unittest.TestCase): """ Tests to verify that CorrectMap behaves correctly """ def setUp(self): super(CorrectMapTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments self.cmap = CorrectMap() def test_set_input_properties(self): # Set the correctmap properties for three inputs self.cmap.set( answer_id='1_2_1', correctness='correct', npoints=5, msg='Test message', hint='Test hint', hintmode='always', queuestate={ 'key': 'secretstring', 'time': '20130228100026' } ) self.cmap.set( answer_id='2_2_1', correctness='incorrect', npoints=None, msg=None, hint=None, hintmode=None, queuestate=None ) self.cmap.set( answer_id='3_2_1', correctness='partially-correct', npoints=3, msg=None, hint=None, hintmode=None, queuestate=None ) # Assert that each input has the expected properties assert self.cmap.is_correct('1_2_1') assert not self.cmap.is_correct('2_2_1') assert self.cmap.is_correct('3_2_1') assert self.cmap.is_partially_correct('3_2_1') assert not self.cmap.is_partially_correct('2_2_1') # Intentionally testing an item that's not in cmap. assert not self.cmap.is_partially_correct('9_2_1') assert self.cmap.get_correctness('1_2_1') == 'correct' assert self.cmap.get_correctness('2_2_1') == 'incorrect' assert self.cmap.get_correctness('3_2_1') == 'partially-correct' assert self.cmap.get_npoints('1_2_1') == 5 assert self.cmap.get_npoints('2_2_1') == 0 assert self.cmap.get_npoints('3_2_1') == 3 assert self.cmap.get_msg('1_2_1') == 'Test message' assert self.cmap.get_msg('2_2_1') is None assert self.cmap.get_hint('1_2_1') == 'Test hint' assert self.cmap.get_hint('2_2_1') is None assert self.cmap.get_hintmode('1_2_1') == 'always' assert self.cmap.get_hintmode('2_2_1') is None assert self.cmap.is_queued('1_2_1') assert not self.cmap.is_queued('2_2_1') assert self.cmap.get_queuetime_str('1_2_1') == '20130228100026' assert self.cmap.get_queuetime_str('2_2_1') is None assert self.cmap.is_right_queuekey('1_2_1', 'secretstring') assert not self.cmap.is_right_queuekey('1_2_1', 'invalidstr') assert not self.cmap.is_right_queuekey('1_2_1', '') assert not self.cmap.is_right_queuekey('1_2_1', None) assert not self.cmap.is_right_queuekey('2_2_1', 'secretstring') assert not self.cmap.is_right_queuekey('2_2_1', 'invalidstr') assert not self.cmap.is_right_queuekey('2_2_1', '') assert not self.cmap.is_right_queuekey('2_2_1', None) def test_get_npoints(self): # Set the correctmap properties for 4 inputs # 1) correct, 5 points # 2) correct, None points # 3) incorrect, 5 points # 4) incorrect, None points # 5) correct, 0 points # 4) partially correct, 2.5 points # 5) partially correct, None points self.cmap.set( answer_id='1_2_1', correctness='correct', npoints=5.3 ) self.cmap.set( answer_id='2_2_1', correctness='correct', npoints=None ) self.cmap.set( answer_id='3_2_1', correctness='incorrect', npoints=5 ) self.cmap.set( answer_id='4_2_1', correctness='incorrect', npoints=None ) self.cmap.set( answer_id='5_2_1', correctness='correct', npoints=0 ) self.cmap.set( answer_id='6_2_1', correctness='partially-correct', npoints=2.5 ) self.cmap.set( answer_id='7_2_1', correctness='partially-correct', npoints=None ) # Assert that we get the expected points # If points assigned --> npoints # If no points assigned and correct --> 1 point # If no points assigned and partially correct --> 1 point # If no points assigned and incorrect --> 0 points assert self.cmap.get_npoints('1_2_1') == 5.3 assert self.cmap.get_npoints('2_2_1') == 1 assert self.cmap.get_npoints('3_2_1') == 5 assert self.cmap.get_npoints('4_2_1') == 0 assert self.cmap.get_npoints('5_2_1') == 0 assert self.cmap.get_npoints('6_2_1') == 2.5 assert self.cmap.get_npoints('7_2_1') == 1 def test_set_overall_message(self): # Default is an empty string string assert self.cmap.get_overall_message() == '' # Set a message that applies to the whole question self.cmap.set_overall_message("Test message") # Retrieve the message assert self.cmap.get_overall_message() == 'Test message' # Setting the message to None --> empty string self.cmap.set_overall_message(None) assert self.cmap.get_overall_message() == '' def test_update_from_correctmap(self): # Initialize a CorrectMap with some properties self.cmap.set( answer_id='1_2_1', correctness='correct', npoints=5, msg='Test message', hint='Test hint', hintmode='always', queuestate={ 'key': 'secretstring', 'time': '20130228100026' } ) self.cmap.set_overall_message("Test message") # Create a second cmap, then update it to have the same properties # as the first cmap other_cmap = CorrectMap() other_cmap.update(self.cmap) # Assert that it has all the same properties assert other_cmap.get_overall_message() == self.cmap.get_overall_message() assert other_cmap.get_dict() == self.cmap.get_dict() def test_update_from_invalid(self): # Should get an exception if we try to update() a CorrectMap # with a non-CorrectMap value invalid_list = [None, "string", 5, datetime.datetime.today()] for invalid in invalid_list: with pytest.raises(Exception): self.cmap.update(invalid) def test_set_none_state(self): """ Test that if an invalid state is set to correct map, the state does not update at all. """ invalid_list = [None, "", False, 0] for invalid in invalid_list: self.cmap.set_dict(invalid) assert self.cmap.get_dict() == {}