Commit 00abaffe by Mark L. Chang

Merge remote-tracking branch 'origin/master' into feature/markchang/studio-analytics

parents db1c0bf0 1b7e552d
...@@ -655,9 +655,9 @@ class MatlabInput(CodeInput): ...@@ -655,9 +655,9 @@ class MatlabInput(CodeInput):
# Check if problem has been queued # Check if problem has been queued
self.queuename = 'matlab' self.queuename = 'matlab'
self.queue_msg = '' self.queue_msg = ''
if 'queue_msg' in self.input_state and self.status in ['queued','incomplete', 'unsubmitted']: if 'queue_msg' in self.input_state and self.status in ['queued', 'incomplete', 'unsubmitted']:
self.queue_msg = self.input_state['queue_msg'] self.queue_msg = self.input_state['queue_msg']
if 'queued' in self.input_state and self.input_state['queuestate'] is not None: if 'queuestate' in self.input_state and self.input_state['queuestate'] == 'queued':
self.status = 'queued' self.status = 'queued'
self.queue_len = 1 self.queue_len = 1
self.msg = self.plot_submitted_msg self.msg = self.plot_submitted_msg
...@@ -702,7 +702,7 @@ class MatlabInput(CodeInput): ...@@ -702,7 +702,7 @@ class MatlabInput(CodeInput):
def _extra_context(self): def _extra_context(self):
''' Set up additional context variables''' ''' Set up additional context variables'''
extra_context = { extra_context = {
'queue_len': self.queue_len, 'queue_len': str(self.queue_len),
'queue_msg': self.queue_msg 'queue_msg': self.queue_msg
} }
return extra_context return extra_context
......
...@@ -361,7 +361,6 @@ class MatlabTest(unittest.TestCase): ...@@ -361,7 +361,6 @@ class MatlabTest(unittest.TestCase):
'feedback': {'message': '3'}, } 'feedback': {'message': '3'}, }
elt = etree.fromstring(self.xml) elt = etree.fromstring(self.xml)
input_class = lookup_tag('matlabinput')
the_input = self.input_class(test_system, elt, state) the_input = self.input_class(test_system, elt, state)
context = the_input._get_render_context() context = the_input._get_render_context()
...@@ -381,6 +380,31 @@ class MatlabTest(unittest.TestCase): ...@@ -381,6 +380,31 @@ class MatlabTest(unittest.TestCase):
self.assertEqual(context, expected) self.assertEqual(context, expected)
def test_rendering_while_queued(self):
state = {'value': 'print "good evening"',
'status': 'incomplete',
'input_state': {'queuestate': 'queued'},
}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_system, elt, state)
context = the_input._get_render_context()
expected = {'id': 'prob_1_2',
'value': 'print "good evening"',
'status': 'queued',
'msg': self.input_class.plot_submitted_msg,
'mode': self.mode,
'rows': self.rows,
'cols': self.cols,
'queue_msg': '',
'linenumbers': 'true',
'hidden': '',
'tabsize': int(self.tabsize),
'queue_len': '1',
}
self.assertEqual(context, expected)
def test_plot_data(self): def test_plot_data(self):
get = {'submission': 'x = 1234;'} get = {'submission': 'x = 1234;'}
response = self.the_input.handle_ajax("plot", get) response = self.the_input.handle_ajax("plot", get)
...@@ -391,6 +415,43 @@ class MatlabTest(unittest.TestCase): ...@@ -391,6 +415,43 @@ class MatlabTest(unittest.TestCase):
self.assertTrue(self.the_input.input_state['queuekey'] is not None) self.assertTrue(self.the_input.input_state['queuekey'] is not None)
self.assertEqual(self.the_input.input_state['queuestate'], 'queued') self.assertEqual(self.the_input.input_state['queuestate'], 'queued')
def test_ungraded_response_success(self):
queuekey = 'abcd'
input_state = {'queuekey': queuekey, 'queuestate': 'queued'}
state = {'value': 'print "good evening"',
'status': 'incomplete',
'input_state': input_state,
'feedback': {'message': '3'}, }
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_system, elt, state)
inner_msg = 'hello!'
queue_msg = json.dumps({'msg': inner_msg})
the_input.ungraded_response(queue_msg, queuekey)
self.assertTrue(input_state['queuekey'] is None)
self.assertTrue(input_state['queuestate'] is None)
self.assertEqual(input_state['queue_msg'], inner_msg)
def test_ungraded_response_key_mismatch(self):
queuekey = 'abcd'
input_state = {'queuekey': queuekey, 'queuestate': 'queued'}
state = {'value': 'print "good evening"',
'status': 'incomplete',
'input_state': input_state,
'feedback': {'message': '3'}, }
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_system, elt, state)
inner_msg = 'hello!'
queue_msg = json.dumps({'msg': inner_msg})
the_input.ungraded_response(queue_msg, 'abc')
self.assertEqual(input_state['queuekey'], queuekey)
self.assertEqual(input_state['queuestate'], 'queued')
self.assertFalse('queue_msg' in input_state)
......
...@@ -108,7 +108,6 @@ class CapaModule(CapaFields, XModule): ...@@ -108,7 +108,6 @@ class CapaModule(CapaFields, XModule):
''' '''
icon_class = 'problem' icon_class = 'problem'
js = {'coffee': [resource_string(__name__, 'js/src/capa/display.coffee'), js = {'coffee': [resource_string(__name__, 'js/src/capa/display.coffee'),
resource_string(__name__, 'js/src/collapsible.coffee'), resource_string(__name__, 'js/src/collapsible.coffee'),
resource_string(__name__, 'js/src/javascript_loader.coffee'), resource_string(__name__, 'js/src/javascript_loader.coffee'),
...@@ -388,7 +387,6 @@ class CapaModule(CapaFields, XModule): ...@@ -388,7 +387,6 @@ class CapaModule(CapaFields, XModule):
return html return html
def get_problem_html(self, encapsulate=True): def get_problem_html(self, encapsulate=True):
'''Return html for the problem. Adds check, reset, save buttons '''Return html for the problem. Adds check, reset, save buttons
as necessary based on the problem config and state.''' as necessary based on the problem config and state.'''
...@@ -401,7 +399,6 @@ class CapaModule(CapaFields, XModule): ...@@ -401,7 +399,6 @@ class CapaModule(CapaFields, XModule):
except Exception, err: except Exception, err:
html = self.handle_problem_html_error(err) html = self.handle_problem_html_error(err)
# The convention is to pass the name of the check button # The convention is to pass the name of the check button
# if we want to show a check button, and False otherwise # if we want to show a check button, and False otherwise
# This works because non-empty strings evaluate to True # This works because non-empty strings evaluate to True
...@@ -535,7 +532,6 @@ class CapaModule(CapaFields, XModule): ...@@ -535,7 +532,6 @@ class CapaModule(CapaFields, XModule):
return False return False
def update_score(self, get): def update_score(self, get):
""" """
Delivers grading response (e.g. from asynchronous code checking) to Delivers grading response (e.g. from asynchronous code checking) to
...@@ -590,7 +586,6 @@ class CapaModule(CapaFields, XModule): ...@@ -590,7 +586,6 @@ class CapaModule(CapaFields, XModule):
self.set_state_from_lcp() self.set_state_from_lcp()
return response return response
def get_answer(self, get): def get_answer(self, get):
''' '''
For the "show answer" button. For the "show answer" button.
...@@ -700,7 +695,6 @@ class CapaModule(CapaFields, XModule): ...@@ -700,7 +695,6 @@ class CapaModule(CapaFields, XModule):
'max_value': score['total'], 'max_value': score['total'],
}) })
def check_problem(self, get): def check_problem(self, get):
''' Checks whether answers to a problem are correct, and ''' Checks whether answers to a problem are correct, and
returns a map of correct/incorrect answers: returns a map of correct/incorrect answers:
...@@ -783,7 +777,7 @@ class CapaModule(CapaFields, XModule): ...@@ -783,7 +777,7 @@ class CapaModule(CapaFields, XModule):
self.system.track_function('save_problem_check', event_info) self.system.track_function('save_problem_check', event_info)
if hasattr(self.system, 'psychometrics_handler'): # update PsychometricsData using callback if hasattr(self.system, 'psychometrics_handler'): # update PsychometricsData using callback
self.system.psychometrics_handler(self.get_instance_state()) self.system.psychometrics_handler(self.get_state_for_lcp())
# render problem into HTML # render problem into HTML
html = self.get_problem_html(encapsulate=False) html = self.get_problem_html(encapsulate=False)
......
...@@ -35,6 +35,7 @@ class CapaFactory(object): ...@@ -35,6 +35,7 @@ class CapaFactory(object):
""" """
num = 0 num = 0
@staticmethod @staticmethod
def next_num(): def next_num():
CapaFactory.num += 1 CapaFactory.num += 1
...@@ -120,7 +121,6 @@ class CapaFactory(object): ...@@ -120,7 +121,6 @@ class CapaFactory(object):
return module return module
class CapaModuleTest(unittest.TestCase): class CapaModuleTest(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -142,9 +142,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -142,9 +142,6 @@ class CapaModuleTest(unittest.TestCase):
self.assertNotEqual(module.url_name, other_module.url_name, self.assertNotEqual(module.url_name, other_module.url_name,
"Factory should be creating unique names for each problem") "Factory should be creating unique names for each problem")
def test_correct(self): def test_correct(self):
""" """
Check that the factory creates correct and incorrect problems properly. Check that the factory creates correct and incorrect problems properly.
...@@ -155,7 +152,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -155,7 +152,6 @@ class CapaModuleTest(unittest.TestCase):
other_module = CapaFactory.create(correct=True) other_module = CapaFactory.create(correct=True)
self.assertEqual(other_module.get_score()['score'], 1) self.assertEqual(other_module.get_score()['score'], 1)
def test_showanswer_default(self): def test_showanswer_default(self):
""" """
Make sure the show answer logic does the right thing. Make sure the show answer logic does the right thing.
...@@ -165,14 +161,12 @@ class CapaModuleTest(unittest.TestCase): ...@@ -165,14 +161,12 @@ class CapaModuleTest(unittest.TestCase):
problem = CapaFactory.create() problem = CapaFactory.create()
self.assertFalse(problem.answer_available()) self.assertFalse(problem.answer_available())
def test_showanswer_attempted(self): def test_showanswer_attempted(self):
problem = CapaFactory.create(showanswer='attempted') problem = CapaFactory.create(showanswer='attempted')
self.assertFalse(problem.answer_available()) self.assertFalse(problem.answer_available())
problem.attempts = 1 problem.attempts = 1
self.assertTrue(problem.answer_available()) self.assertTrue(problem.answer_available())
def test_showanswer_closed(self): def test_showanswer_closed(self):
# can see after attempts used up, even with due date in the future # can see after attempts used up, even with due date in the future
...@@ -182,7 +176,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -182,7 +176,6 @@ class CapaModuleTest(unittest.TestCase):
due=self.tomorrow_str) due=self.tomorrow_str)
self.assertTrue(used_all_attempts.answer_available()) self.assertTrue(used_all_attempts.answer_available())
# can see after due date # can see after due date
after_due_date = CapaFactory.create(showanswer='closed', after_due_date = CapaFactory.create(showanswer='closed',
max_attempts="1", max_attempts="1",
...@@ -191,7 +184,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -191,7 +184,6 @@ class CapaModuleTest(unittest.TestCase):
self.assertTrue(after_due_date.answer_available()) self.assertTrue(after_due_date.answer_available())
# can't see because attempts left # can't see because attempts left
attempts_left_open = CapaFactory.create(showanswer='closed', attempts_left_open = CapaFactory.create(showanswer='closed',
max_attempts="1", max_attempts="1",
...@@ -207,8 +199,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -207,8 +199,6 @@ class CapaModuleTest(unittest.TestCase):
graceperiod=self.two_day_delta_str) graceperiod=self.two_day_delta_str)
self.assertFalse(still_in_grace.answer_available()) self.assertFalse(still_in_grace.answer_available())
def test_showanswer_past_due(self): def test_showanswer_past_due(self):
""" """
With showanswer="past_due" should only show answer after the problem is closed With showanswer="past_due" should only show answer after the problem is closed
...@@ -222,7 +212,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -222,7 +212,6 @@ class CapaModuleTest(unittest.TestCase):
due=self.tomorrow_str) due=self.tomorrow_str)
self.assertFalse(used_all_attempts.answer_available()) self.assertFalse(used_all_attempts.answer_available())
# can see after due date # can see after due date
past_due_date = CapaFactory.create(showanswer='past_due', past_due_date = CapaFactory.create(showanswer='past_due',
max_attempts="1", max_attempts="1",
...@@ -230,7 +219,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -230,7 +219,6 @@ class CapaModuleTest(unittest.TestCase):
due=self.yesterday_str) due=self.yesterday_str)
self.assertTrue(past_due_date.answer_available()) self.assertTrue(past_due_date.answer_available())
# can't see because attempts left # can't see because attempts left
attempts_left_open = CapaFactory.create(showanswer='past_due', attempts_left_open = CapaFactory.create(showanswer='past_due',
max_attempts="1", max_attempts="1",
...@@ -260,7 +248,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -260,7 +248,6 @@ class CapaModuleTest(unittest.TestCase):
due=self.tomorrow_str) due=self.tomorrow_str)
self.assertTrue(used_all_attempts.answer_available()) self.assertTrue(used_all_attempts.answer_available())
# can see after due date # can see after due date
past_due_date = CapaFactory.create(showanswer='finished', past_due_date = CapaFactory.create(showanswer='finished',
max_attempts="1", max_attempts="1",
...@@ -268,7 +255,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -268,7 +255,6 @@ class CapaModuleTest(unittest.TestCase):
due=self.yesterday_str) due=self.yesterday_str)
self.assertTrue(past_due_date.answer_available()) self.assertTrue(past_due_date.answer_available())
# can't see because attempts left and wrong # can't see because attempts left and wrong
attempts_left_open = CapaFactory.create(showanswer='finished', attempts_left_open = CapaFactory.create(showanswer='finished',
max_attempts="1", max_attempts="1",
...@@ -284,7 +270,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -284,7 +270,6 @@ class CapaModuleTest(unittest.TestCase):
correct=True) correct=True)
self.assertTrue(correct_ans.answer_available()) self.assertTrue(correct_ans.answer_available())
# Can see even though grace period hasn't expired, because have no more # Can see even though grace period hasn't expired, because have no more
# attempts. # attempts.
still_in_grace = CapaFactory.create(showanswer='finished', still_in_grace = CapaFactory.create(showanswer='finished',
...@@ -294,7 +279,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -294,7 +279,6 @@ class CapaModuleTest(unittest.TestCase):
graceperiod=self.two_day_delta_str) graceperiod=self.two_day_delta_str)
self.assertTrue(still_in_grace.answer_available()) self.assertTrue(still_in_grace.answer_available())
def test_closed(self): def test_closed(self):
# Attempts < Max attempts --> NOT closed # Attempts < Max attempts --> NOT closed
...@@ -322,7 +306,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -322,7 +306,6 @@ class CapaModuleTest(unittest.TestCase):
due=self.yesterday_str) due=self.yesterday_str)
self.assertTrue(module.closed()) self.assertTrue(module.closed())
def test_parse_get_params(self): def test_parse_get_params(self):
# We have to set up Django settings in order to use QueryDict # We have to set up Django settings in order to use QueryDict
...@@ -348,7 +331,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -348,7 +331,6 @@ class CapaModuleTest(unittest.TestCase):
"Output dict should have key %s" % original_key) "Output dict should have key %s" % original_key)
self.assertEqual(valid_get_dict[original_key], result[key]) self.assertEqual(valid_get_dict[original_key], result[key])
# Valid GET param dict with list keys # Valid GET param dict with list keys
valid_get_dict = self._querydict_from_dict({'input_2[]': ['test1', 'test2']}) valid_get_dict = self._querydict_from_dict({'input_2[]': ['test1', 'test2']})
result = CapaModule.make_dict_of_responses(valid_get_dict) result = CapaModule.make_dict_of_responses(valid_get_dict)
...@@ -366,7 +348,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -366,7 +348,6 @@ class CapaModuleTest(unittest.TestCase):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
result = CapaModule.make_dict_of_responses(invalid_get_dict) result = CapaModule.make_dict_of_responses(invalid_get_dict)
# Two equivalent names (one list, one non-list) # Two equivalent names (one list, one non-list)
# One of the values would overwrite the other, so detect this # One of the values would overwrite the other, so detect this
# and raise an exception # and raise an exception
...@@ -395,7 +376,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -395,7 +376,6 @@ class CapaModuleTest(unittest.TestCase):
return copyDict return copyDict
def test_check_problem_correct(self): def test_check_problem_correct(self):
module = CapaFactory.create(attempts=1) module = CapaFactory.create(attempts=1)
...@@ -403,6 +383,7 @@ class CapaModuleTest(unittest.TestCase): ...@@ -403,6 +383,7 @@ class CapaModuleTest(unittest.TestCase):
# Simulate that all answers are marked correct, no matter # Simulate that all answers are marked correct, no matter
# what the input is, by patching CorrectMap.is_correct() # what the input is, by patching CorrectMap.is_correct()
# Also simulate rendering the HTML # Also simulate rendering the HTML
# TODO: pep8 thinks the following line has invalid syntax
with patch('capa.correctmap.CorrectMap.is_correct') as mock_is_correct,\ with patch('capa.correctmap.CorrectMap.is_correct') as mock_is_correct,\
patch('xmodule.capa_module.CapaModule.get_problem_html') as mock_html: patch('xmodule.capa_module.CapaModule.get_problem_html') as mock_html:
mock_is_correct.return_value = True mock_is_correct.return_value = True
...@@ -439,7 +420,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -439,7 +420,6 @@ class CapaModuleTest(unittest.TestCase):
# Expect that the number of attempts is incremented by 1 # Expect that the number of attempts is incremented by 1
self.assertEqual(module.attempts, 1) self.assertEqual(module.attempts, 1)
def test_check_problem_closed(self): def test_check_problem_closed(self):
module = CapaFactory.create(attempts=3) module = CapaFactory.create(attempts=3)
...@@ -503,7 +483,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -503,7 +483,6 @@ class CapaModuleTest(unittest.TestCase):
# Expect that the number of attempts is NOT incremented # Expect that the number of attempts is NOT incremented
self.assertEqual(module.attempts, 1) self.assertEqual(module.attempts, 1)
def test_check_problem_error(self): def test_check_problem_error(self):
# Try each exception that capa_module should handle # Try each exception that capa_module should handle
...@@ -560,7 +539,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -560,7 +539,6 @@ class CapaModuleTest(unittest.TestCase):
# Expect that the number of attempts is NOT incremented # Expect that the number of attempts is NOT incremented
self.assertEqual(module.attempts, 1) self.assertEqual(module.attempts, 1)
def test_reset_problem(self): def test_reset_problem(self):
module = CapaFactory.create(done=True) module = CapaFactory.create(done=True)
module.new_lcp = Mock(wraps=module.new_lcp) module.new_lcp = Mock(wraps=module.new_lcp)
...@@ -583,7 +561,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -583,7 +561,6 @@ class CapaModuleTest(unittest.TestCase):
# Expect that the problem was reset # Expect that the problem was reset
module.new_lcp.assert_called_once_with({'seed': None}) module.new_lcp.assert_called_once_with({'seed': None})
def test_reset_problem_closed(self): def test_reset_problem_closed(self):
module = CapaFactory.create() module = CapaFactory.create()
...@@ -598,7 +575,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -598,7 +575,6 @@ class CapaModuleTest(unittest.TestCase):
# Expect that the problem was NOT reset # Expect that the problem was NOT reset
self.assertTrue('success' in result and not result['success']) self.assertTrue('success' in result and not result['success'])
def test_reset_problem_not_done(self): def test_reset_problem_not_done(self):
# Simulate that the problem is NOT done # Simulate that the problem is NOT done
module = CapaFactory.create(done=False) module = CapaFactory.create(done=False)
...@@ -610,7 +586,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -610,7 +586,6 @@ class CapaModuleTest(unittest.TestCase):
# Expect that the problem was NOT reset # Expect that the problem was NOT reset
self.assertTrue('success' in result and not result['success']) self.assertTrue('success' in result and not result['success'])
def test_save_problem(self): def test_save_problem(self):
module = CapaFactory.create(done=False) module = CapaFactory.create(done=False)
...@@ -625,7 +600,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -625,7 +600,6 @@ class CapaModuleTest(unittest.TestCase):
# Expect that the result is success # Expect that the result is success
self.assertTrue('success' in result and result['success']) self.assertTrue('success' in result and result['success'])
def test_save_problem_closed(self): def test_save_problem_closed(self):
module = CapaFactory.create(done=False) module = CapaFactory.create(done=False)
...@@ -640,7 +614,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -640,7 +614,6 @@ class CapaModuleTest(unittest.TestCase):
# Expect that the result is failure # Expect that the result is failure
self.assertTrue('success' in result and not result['success']) self.assertTrue('success' in result and not result['success'])
def test_save_problem_submitted_with_randomize(self): def test_save_problem_submitted_with_randomize(self):
module = CapaFactory.create(rerandomize='always', done=True) module = CapaFactory.create(rerandomize='always', done=True)
...@@ -651,7 +624,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -651,7 +624,6 @@ class CapaModuleTest(unittest.TestCase):
# Expect that we cannot save # Expect that we cannot save
self.assertTrue('success' in result and not result['success']) self.assertTrue('success' in result and not result['success'])
def test_save_problem_submitted_no_randomize(self): def test_save_problem_submitted_no_randomize(self):
module = CapaFactory.create(rerandomize='never', done=True) module = CapaFactory.create(rerandomize='never', done=True)
...@@ -724,7 +696,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -724,7 +696,6 @@ class CapaModuleTest(unittest.TestCase):
module = CapaFactory.create(rerandomize="never", done=True) module = CapaFactory.create(rerandomize="never", done=True)
self.assertTrue(module.should_show_check_button()) self.assertTrue(module.should_show_check_button())
def test_should_show_reset_button(self): def test_should_show_reset_button(self):
attempts = random.randint(1, 10) attempts = random.randint(1, 10)
...@@ -755,7 +726,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -755,7 +726,6 @@ class CapaModuleTest(unittest.TestCase):
module = CapaFactory.create(max_attempts=0, done=True) module = CapaFactory.create(max_attempts=0, done=True)
self.assertTrue(module.should_show_reset_button()) self.assertTrue(module.should_show_reset_button())
def test_should_show_save_button(self): def test_should_show_save_button(self):
attempts = random.randint(1, 10) attempts = random.randint(1, 10)
...@@ -823,7 +793,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -823,7 +793,6 @@ class CapaModuleTest(unittest.TestCase):
html = module.get_problem_html() html = module.get_problem_html()
# assert that we got here without exploding # assert that we got here without exploding
def test_get_problem_html(self): def test_get_problem_html(self):
module = CapaFactory.create() module = CapaFactory.create()
...@@ -869,7 +838,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -869,7 +838,6 @@ class CapaModuleTest(unittest.TestCase):
# Assert that the encapsulated html contains the original html # Assert that the encapsulated html contains the original html
self.assertTrue(html in html_encapsulated) self.assertTrue(html in html_encapsulated)
def test_get_problem_html_error(self): def test_get_problem_html_error(self):
""" """
In production, when an error occurs with the problem HTML In production, when an error occurs with the problem HTML
...@@ -902,7 +870,6 @@ class CapaModuleTest(unittest.TestCase): ...@@ -902,7 +870,6 @@ class CapaModuleTest(unittest.TestCase):
# Expect that the module has created a new dummy problem with the error # Expect that the module has created a new dummy problem with the error
self.assertNotEqual(original_problem, module.lcp) self.assertNotEqual(original_problem, module.lcp)
def test_random_seed_no_change(self): def test_random_seed_no_change(self):
# Run the test for each possible rerandomize value # Run the test for each possible rerandomize value
...@@ -920,7 +887,7 @@ class CapaModuleTest(unittest.TestCase): ...@@ -920,7 +887,7 @@ class CapaModuleTest(unittest.TestCase):
self.assertEqual(seed, 1) self.assertEqual(seed, 1)
# Check the problem # Check the problem
get_request_dict = { CapaFactory.input_key(): '3.14'} get_request_dict = {CapaFactory.input_key(): '3.14'}
module.check_problem(get_request_dict) module.check_problem(get_request_dict)
# Expect that the seed is the same # Expect that the seed is the same
...@@ -992,6 +959,7 @@ class CapaModuleTest(unittest.TestCase): ...@@ -992,6 +959,7 @@ class CapaModuleTest(unittest.TestCase):
success = _retry_and_check(5, success = _retry_and_check(5,
lambda: _reset_and_get_seed(module) != seed) lambda: _reset_and_get_seed(module) != seed)
# TODO: change this comparison to module.seed is not None?
self.assertTrue(module.seed != None) self.assertTrue(module.seed != None)
msg = 'Could not get a new seed from reset after 5 tries' msg = 'Could not get a new seed from reset after 5 tries'
self.assertTrue(success, msg) self.assertTrue(success, msg)
...@@ -76,6 +76,11 @@ class Command(BaseCommand): ...@@ -76,6 +76,11 @@ class Command(BaseCommand):
for hist_module in hist_modules: for hist_module in hist_modules:
self.remove_studentmodulehistory_input_state(hist_module, save_changes) self.remove_studentmodulehistory_input_state(hist_module, save_changes)
if self.num_visited % 1000 == 0:
LOG.info(" Progress: updated {0} of {1} student modules".format(self.num_changed, self.num_visited))
LOG.info(" Progress: updated {0} of {1} student history modules".format(self.num_hist_changed,
self.num_hist_visited))
@transaction.autocommit @transaction.autocommit
def remove_studentmodule_input_state(self, module, save_changes): def remove_studentmodule_input_state(self, module, save_changes):
''' Fix the grade assigned to a StudentModule''' ''' Fix the grade assigned to a StudentModule'''
......
...@@ -15,7 +15,6 @@ from scipy.optimize import curve_fit ...@@ -15,7 +15,6 @@ from scipy.optimize import curve_fit
from django.conf import settings from django.conf import settings
from django.db.models import Sum, Max from django.db.models import Sum, Max
from psychometrics.models import * from psychometrics.models import *
from xmodule.modulestore import Location
log = logging.getLogger("mitx.psychometrics") log = logging.getLogger("mitx.psychometrics")
...@@ -246,6 +245,7 @@ def generate_plots_for_problem(problem): ...@@ -246,6 +245,7 @@ def generate_plots_for_problem(problem):
yset['ydat'] = ydat yset['ydat'] = ydat
if len(ydat) > 3: # try to fit to logistic function if enough data points if len(ydat) > 3: # try to fit to logistic function if enough data points
try:
cfp = curve_fit(func_2pl, xdat, ydat, [1.0, max_attempts / 2.0]) cfp = curve_fit(func_2pl, xdat, ydat, [1.0, max_attempts / 2.0])
yset['fitparam'] = cfp yset['fitparam'] = cfp
yset['fitpts'] = func_2pl(np.array(xdat), *cfp[0]) yset['fitpts'] = func_2pl(np.array(xdat), *cfp[0])
...@@ -253,6 +253,8 @@ def generate_plots_for_problem(problem): ...@@ -253,6 +253,8 @@ def generate_plots_for_problem(problem):
fitx = np.linspace(xdat[0], xdat[-1], 100) fitx = np.linspace(xdat[0], xdat[-1], 100)
yset['fitx'] = fitx yset['fitx'] = fitx
yset['fity'] = func_2pl(np.array(fitx), *cfp[0]) yset['fity'] = func_2pl(np.array(fitx), *cfp[0])
except Exception as err:
log.debug('Error in psychoanalyze curve fitting: %s' % err)
dataset['grade_%d' % grade] = yset dataset['grade_%d' % grade] = yset
...@@ -302,7 +304,7 @@ def make_psychometrics_data_update_handler(course_id, user, module_state_key): ...@@ -302,7 +304,7 @@ def make_psychometrics_data_update_handler(course_id, user, module_state_key):
Construct and return a procedure which may be called to update Construct and return a procedure which may be called to update
the PsychometricsData instance for the given StudentModule instance. the PsychometricsData instance for the given StudentModule instance.
""" """
sm = studentmodule.objects.get_or_create( sm, status = StudentModule.objects.get_or_create(
course_id=course_id, course_id=course_id,
student=user, student=user,
module_state_key=module_state_key, module_state_key=module_state_key,
...@@ -329,7 +331,11 @@ def make_psychometrics_data_update_handler(course_id, user, module_state_key): ...@@ -329,7 +331,11 @@ def make_psychometrics_data_update_handler(course_id, user, module_state_key):
return return
pmd.done = done pmd.done = done
pmd.attempts = state['attempts'] try:
pmd.attempts = state.get('attempts', 0)
except:
log.exception("no attempts for %s (state=%s)" % (sm, sm.state))
try: try:
checktimes = eval(pmd.checktimes) # update log of attempt timestamps checktimes = eval(pmd.checktimes) # update log of attempt timestamps
except: except:
......
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