diff --git a/common/lib/xmodule/xmodule/abtest_module.py b/common/lib/xmodule/xmodule/abtest_module.py index c0a53d048f..06d4e0b2d2 100644 --- a/common/lib/xmodule/xmodule/abtest_module.py +++ b/common/lib/xmodule/xmodule/abtest_module.py @@ -45,7 +45,7 @@ class ABTestModule(ABTestFields, XModule): """ def __init__(self, *args, **kwargs): - XModule.__init__(self, *args, **kwargs) + super(ABTestModule, self).__init__(*args, **kwargs) if self.group is None: self.group = group_from_value( diff --git a/common/lib/xmodule/xmodule/annotatable_module.py b/common/lib/xmodule/xmodule/annotatable_module.py index ca85065577..fbc175b5b9 100644 --- a/common/lib/xmodule/xmodule/annotatable_module.py +++ b/common/lib/xmodule/xmodule/annotatable_module.py @@ -50,7 +50,7 @@ class AnnotatableModule(AnnotatableFields, XModule): icon_class = 'annotatable' def __init__(self, *args, **kwargs): - XModule.__init__(self, *args, **kwargs) + super(AnnotatableModule, self).__init__(*args, **kwargs) xmltree = etree.fromstring(self.data) diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index 6d664acbf6..cf6c2e3dce 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -190,7 +190,7 @@ class CapaModule(CapaFields, XModule): """ Accepts the same arguments as xmodule.x_module:XModule.__init__ """ - XModule.__init__(self, *args, **kwargs) + super(CapaModule, self).__init__(*args, **kwargs) due_date = self.due diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index 6dc2ac045b..68a0d65617 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -412,7 +412,7 @@ class CombinedOpenEndedModule(CombinedOpenEndedFields, XModule): See DEFAULT_DATA for a sample. """ - XModule.__init__(self, *args, **kwargs) + super(CombinedOpenEndedModule, self).__init__(*args, **kwargs) self.system.set('location', self.location) diff --git a/common/lib/xmodule/xmodule/crowdsource_hinter.py b/common/lib/xmodule/xmodule/crowdsource_hinter.py index 62bfe5b586..5a1091f6fb 100644 --- a/common/lib/xmodule/xmodule/crowdsource_hinter.py +++ b/common/lib/xmodule/xmodule/crowdsource_hinter.py @@ -75,7 +75,7 @@ class CrowdsourceHinterModule(CrowdsourceHinterFields, XModule): js_module_name = "Hinter" def __init__(self, *args, **kwargs): - XModule.__init__(self, *args, **kwargs) + super(CrowdsourceHinterModule, self).__init__(*args, **kwargs) # We need to know whether we are working with a FormulaResponse problem. try: responder = self.get_display_items()[0].lcp.responders.values()[0] diff --git a/common/lib/xmodule/xmodule/foldit_module.py b/common/lib/xmodule/xmodule/foldit_module.py index e1714ff96b..655ff1911a 100644 --- a/common/lib/xmodule/xmodule/foldit_module.py +++ b/common/lib/xmodule/xmodule/foldit_module.py @@ -39,7 +39,7 @@ class FolditModule(FolditFields, XModule): required_sublevel_half_credit="3" show_leaderboard="false"/> """ - XModule.__init__(self, *args, **kwargs) + super(FolditModule, self).__init__(*args, **kwargs) self.due_time = self.due def is_complete(self): diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py index 4a1715c48d..72915eb7b3 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py @@ -93,7 +93,6 @@ class CombinedOpenEndedV1Module(): Definition file should have one or many task blocks, a rubric block, and a prompt block. See DEFAULT_DATA in combined_open_ended_module for a sample. """ - self.instance_state = instance_state self.display_name = instance_state.get('display_name', "Open Ended") diff --git a/common/lib/xmodule/xmodule/randomize_module.py b/common/lib/xmodule/xmodule/randomize_module.py index 00baf3f140..71d23012d1 100644 --- a/common/lib/xmodule/xmodule/randomize_module.py +++ b/common/lib/xmodule/xmodule/randomize_module.py @@ -39,7 +39,7 @@ class RandomizeModule(RandomizeFields, XModule): modules. """ def __init__(self, *args, **kwargs): - XModule.__init__(self, *args, **kwargs) + super(RandomizeModule, self).__init__(*args, **kwargs) # NOTE: calling self.get_children() creates a circular reference-- # it calls get_child_descriptors() internally, but that doesn't work until diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py index 291d7a1ea1..62e93cb90e 100644 --- a/common/lib/xmodule/xmodule/seq_module.py +++ b/common/lib/xmodule/xmodule/seq_module.py @@ -38,7 +38,7 @@ class SequenceModule(SequenceFields, XModule): def __init__(self, *args, **kwargs): - XModule.__init__(self, *args, **kwargs) + super(SequenceModule, self).__init__(*args, **kwargs) # if position is specified in system, then use that instead if getattr(self.system, 'position', None) is not None: diff --git a/common/lib/xmodule/xmodule/tests/test_capa_module.py b/common/lib/xmodule/xmodule/tests/test_capa_module.py index 889376ba42..73d2eb111f 100644 --- a/common/lib/xmodule/xmodule/tests/test_capa_module.py +++ b/common/lib/xmodule/xmodule/tests/test_capa_module.py @@ -133,7 +133,6 @@ class CapaFactory(object): DictFieldData(field_data), ScopeIds(None, None, location, location), ) - system.xmodule_instance = module if correct: # TODO: probably better to actually set the internal state properly, but... diff --git a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py index b72eeab66b..e1b2a4ebe2 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -664,7 +664,6 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): static_data=self.static_data, metadata=self.metadata, instance_state=instance_state) - self.test_system.xmodule_instance = module return combinedoe def ai_state_reset(self, task_state, task_number=None): @@ -717,6 +716,7 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): def test_state_pe_single(self): self.ai_state_success(TEST_STATE_PE_SINGLE, iscore=0, tasks=[self.task_xml2]) + class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore): """ Test the student flow in the combined open ended xmodule @@ -726,31 +726,42 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore): assessment = [0, 1] hint = "blah" - def setUp(self): - self.test_system = get_test_system() - self.test_system.open_ended_grading_interface = None - self.test_system.xqueue['interface'] = Mock( + def get_module_system(self, descriptor): + test_system = get_test_system() + test_system.open_ended_grading_interface = None + test_system.xqueue['interface'] = Mock( send_to_queue=Mock(side_effect=[1, "queued"]) ) + + return test_system + + def setUp(self): self.setup_modulestore(COURSE) + def _handle_ajax(self, dispatch, content): + # Load the module from persistence + module = self._module() + + # Call handle_ajax on the module + result = module.handle_ajax(dispatch, content) + + # Persist the state + module.save() + + return result + + def _module(self): + return self.get_module_from_location(self.problem_location, COURSE) + def test_open_ended_load_and_save(self): """ See if we can load the module and save an answer @return: """ - # Load the module - module = self.get_module_from_location(self.problem_location, COURSE) - # Try saving an answer - module.handle_ajax("save_answer", {"student_answer": self.answer}) - # Save our modifications to the underlying KeyValueStore so they can be persisted - module.save() - task_one_json = json.loads(module.task_states[0]) - self.assertEqual(task_one_json['child_history'][0]['answer'], self.answer) + self._handle_ajax("save_answer", {"student_answer": self.answer}) - module = self.get_module_from_location(self.problem_location, COURSE) - task_one_json = json.loads(module.task_states[0]) + task_one_json = json.loads(self._module().task_states[0]) self.assertEqual(task_one_json['child_history'][0]['answer'], self.answer) def test_open_ended_flow_reset(self): @@ -759,42 +770,37 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore): @return: """ assessment = [0, 1] - module = self.get_module_from_location(self.problem_location, COURSE) # Simulate a student saving an answer - html = module.handle_ajax("get_html", {}) - module.save() - module.handle_ajax("save_answer", {"student_answer": self.answer}) - module.save() - html = module.handle_ajax("get_html", {}) - module.save() + self._handle_ajax("get_html", {}) + self._handle_ajax("save_answer", {"student_answer": self.answer}) + self._handle_ajax("get_html", {}) # Mock a student submitting an assessment assessment_dict = MultiDict({'assessment': sum(assessment)}) assessment_dict.extend(('score_list[]', val) for val in assessment) - module.handle_ajax("save_assessment", assessment_dict) - module.save() - task_one_json = json.loads(module.task_states[0]) + self._handle_ajax("save_assessment", assessment_dict) + + task_one_json = json.loads(self._module().task_states[0]) self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment) - rubric = module.handle_ajax("get_combined_rubric", {}) - module.save() + + self._handle_ajax("get_combined_rubric", {}) # Move to the next step in the problem - module.handle_ajax("next_problem", {}) - module.save() - self.assertEqual(module.current_task_number, 0) + self._handle_ajax("next_problem", {}) + self.assertEqual(self._module().current_task_number, 0) - html = module.render('student_view').content + html = self._module().render('student_view').content self.assertIsInstance(html, basestring) - rubric = module.handle_ajax("get_combined_rubric", {}) - module.save() + rubric = self._handle_ajax("get_combined_rubric", {}) self.assertIsInstance(rubric, basestring) - self.assertEqual(module.state, "assessing") - module.handle_ajax("reset", {}) - module.save() - self.assertEqual(module.current_task_number, 0) + + self.assertEqual(self._module().state, "assessing") + + self._handle_ajax("reset", {}) + self.assertEqual(self._module().current_task_number, 0) def test_open_ended_flow_correct(self): """ @@ -803,42 +809,36 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore): @return: """ assessment = [1, 1] - # Load the module - module = self.get_module_from_location(self.problem_location, COURSE) # Simulate a student saving an answer - module.handle_ajax("save_answer", {"student_answer": self.answer}) - module.save() - status = module.handle_ajax("get_status", {}) - module.save() + self._handle_ajax("save_answer", {"student_answer": self.answer}) + status = self._handle_ajax("get_status", {}) self.assertIsInstance(status, basestring) # Mock a student submitting an assessment assessment_dict = MultiDict({'assessment': sum(assessment)}) assessment_dict.extend(('score_list[]', val) for val in assessment) - module.handle_ajax("save_assessment", assessment_dict) - module.save() - task_one_json = json.loads(module.task_states[0]) + self._handle_ajax("save_assessment", assessment_dict) + + task_one_json = json.loads(self._module().task_states[0]) self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment) # Move to the next step in the problem try: - module.handle_ajax("next_problem", {}) - module.save() + self._handle_ajax("next_problem", {}) except GradingServiceError: # This error is okay. We don't have a grading service to connect to! pass - self.assertEqual(module.current_task_number, 1) + self.assertEqual(self._module().current_task_number, 1) try: - module.render('student_view') + self._module().render('student_view') except GradingServiceError: # This error is okay. We don't have a grading service to connect to! pass # Try to get the rubric from the module - module.handle_ajax("get_combined_rubric", {}) - module.save() + self._handle_ajax("get_combined_rubric", {}) # Make a fake reply from the queue queue_reply = { @@ -856,29 +856,26 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore): }) } - module.handle_ajax("check_for_score", {}) - module.save() + self._handle_ajax("check_for_score", {}) # Update the module with the fake queue reply - module.handle_ajax("score_update", queue_reply) - module.save() + self._handle_ajax("score_update", queue_reply) + + module = self._module() self.assertFalse(module.ready_to_reset) self.assertEqual(module.current_task_number, 1) # Get html and other data client will request module.render('student_view') - module.handle_ajax("skip_post_assessment", {}) - module.save() + self._handle_ajax("skip_post_assessment", {}) # Get all results - module.handle_ajax("get_combined_rubric", {}) - module.save() + self._handle_ajax("get_combined_rubric", {}) # reset the problem - module.handle_ajax("reset", {}) - module.save() - self.assertEqual(module.state, "initial") + self._handle_ajax("reset", {}) + self.assertEqual(self._module().state, "initial") class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore): @@ -890,14 +887,32 @@ class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore): assessment = [0, 1] hint = "blah" - def setUp(self): - self.test_system = get_test_system() - self.test_system.open_ended_grading_interface = None - self.test_system.xqueue['interface'] = Mock( + def get_module_system(self, descriptor): + test_system = get_test_system() + test_system.open_ended_grading_interface = None + test_system.xqueue['interface'] = Mock( send_to_queue=Mock(side_effect=[1, "queued"]) ) + return test_system + + def setUp(self): self.setup_modulestore(COURSE) + def _handle_ajax(self, dispatch, content): + # Load the module from persistence + module = self._module() + + # Call handle_ajax on the module + result = module.handle_ajax(dispatch, content) + + # Persist the state + module.save() + + return result + + def _module(self): + return self.get_module_from_location(self.problem_location, COURSE) + def test_reset_fail(self): """ Test the flow of the module if we complete the self assessment step and then reset @@ -905,39 +920,32 @@ class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore): @return: """ assessment = [0, 1] - module = self.get_module_from_location(self.problem_location, COURSE) - module.save() # Simulate a student saving an answer - module.handle_ajax("save_answer", {"student_answer": self.answer}) - module.save() + self._handle_ajax("save_answer", {"student_answer": self.answer}) # Mock a student submitting an assessment assessment_dict = MultiDict({'assessment': sum(assessment)}) assessment_dict.extend(('score_list[]', val) for val in assessment) - module.handle_ajax("save_assessment", assessment_dict) - module.save() - task_one_json = json.loads(module.task_states[0]) + self._handle_ajax("save_assessment", assessment_dict) + task_one_json = json.loads(self._module().task_states[0]) self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment) # Move to the next step in the problem - module.handle_ajax("next_problem", {}) - module.save() - self.assertEqual(module.current_task_number, 0) + self._handle_ajax("next_problem", {}) + self.assertEqual(self._module().current_task_number, 0) - html = module.render('student_view').content + html = self._module().render('student_view').content self.assertIsInstance(html, basestring) # Module should now be done - rubric = module.handle_ajax("get_combined_rubric", {}) - module.save() + rubric = self._handle_ajax("get_combined_rubric", {}) self.assertIsInstance(rubric, basestring) - self.assertEqual(module.state, "done") + self.assertEqual(self._module().state, "done") # Try to reset, should fail because only 1 attempt is allowed - reset_data = json.loads(module.handle_ajax("reset", {})) - module.save() + reset_data = json.loads(self._handle_ajax("reset", {})) self.assertEqual(reset_data['success'], False) class OpenEndedModuleXmlImageUploadTest(unittest.TestCase, DummyModulestore): @@ -951,13 +959,16 @@ class OpenEndedModuleXmlImageUploadTest(unittest.TestCase, DummyModulestore): answer_link = "http://www.edx.org" autolink_tag = "'.format(self.id) @@ -737,7 +738,7 @@ class XModuleDescriptor(XModuleMixin, HTMLSnippet, ResourceTemplates, XBlock): assert self.xmodule_runtime.error_descriptor_class is not None if self.xmodule_runtime.xmodule_instance is None: try: - self.xmodule_runtime.xmodule_instance = self.xmodule_runtime.construct_xblock_from_class( + self.xmodule_runtime.construct_xblock_from_class( self.module_class, descriptor=self, scope_ids=self.scope_ids, @@ -1041,6 +1042,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs """ The url prefix to be used by XModules to call into handle_ajax """ + assert self.xmodule_instance is not None return self.handler_url(self.xmodule_instance, 'xmodule_handler', '', '').rstrip('/?')