From f9cca8befdb7794b79486ba2ef9c6132309c0894 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Mon, 4 Feb 2013 11:51:05 -0500 Subject: [PATCH 1/7] Starting a framework for handling the closure of an open ended problem. Currently incomplete. --- .../xmodule/combined_open_ended_module.py | 20 ++++++++++++++----- .../lib/xmodule/xmodule/open_ended_module.py | 9 ++++----- common/lib/xmodule/xmodule/openendedchild.py | 7 ++++++- .../xmodule/xmodule/self_assessment_module.py | 9 +++------ .../xmodule/tests/test_combined_open_ended.py | 10 ++++++++-- .../xmodule/tests/test_self_assessment.py | 6 +++++- 6 files changed, 41 insertions(+), 20 deletions(-) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index 14a59c9004..e9b3d1d4d0 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -188,6 +188,15 @@ class CombinedOpenEndedModule(XModule): self.task_xml = definition['task_xml'] self.setup_next_task() + def closed(self): + return True + #''' Is the student still allowed to submit answers? ''' + #if self.attempts == self.max_attempts: + # return True + #if self.close_date is not None and datetime.datetime.utcnow() > self.close_date: + # return True + + def get_tag_name(self, xml): """ Gets the tag name of a given xml block. @@ -269,7 +278,7 @@ class CombinedOpenEndedModule(XModule): self.current_task_parsed_xml = self.current_task_descriptor.definition_from_xml(etree_xml, self.system) if current_task_state is None and self.current_task_number == 0: self.current_task = child_task_module(self.system, self.location, - self.current_task_parsed_xml, self.current_task_descriptor, self.static_data) + self.current_task_parsed_xml, self.current_task_descriptor, self.static_data, self) self.task_states.append(self.current_task.get_instance_state()) self.state = self.ASSESSING elif current_task_state is None and self.current_task_number > 0: @@ -285,7 +294,7 @@ class CombinedOpenEndedModule(XModule): }) self.current_task = child_task_module(self.system, self.location, self.current_task_parsed_xml, self.current_task_descriptor, self.static_data, - instance_state=current_task_state) + self, instance_state=current_task_state) self.task_states.append(self.current_task.get_instance_state()) self.state = self.ASSESSING else: @@ -293,10 +302,11 @@ class CombinedOpenEndedModule(XModule): current_task_state = self.overwrite_state(current_task_state) self.current_task = child_task_module(self.system, self.location, self.current_task_parsed_xml, self.current_task_descriptor, self.static_data, - instance_state=current_task_state) + self, instance_state=current_task_state) return True + def check_allow_reset(self): """ Checks to see if the student has passed the criteria to move to the next module. If not, sets @@ -404,7 +414,7 @@ class CombinedOpenEndedModule(XModule): task_parsed_xml = task_descriptor.definition_from_xml(etree_xml, self.system) task = children['modules'][task_type](self.system, self.location, task_parsed_xml, task_descriptor, - self.static_data, instance_state=task_state) + self.static_data, self, instance_state=task_state) last_response = task.latest_answer() last_score = task.latest_score() last_post_assessment = task.latest_post_assessment(self.system) @@ -700,4 +710,4 @@ class CombinedOpenEndedDescriptor(XmlDescriptor, EditingDescriptor): for child in ['task']: add_child(child) - return elt \ No newline at end of file + return elt diff --git a/common/lib/xmodule/xmodule/open_ended_module.py b/common/lib/xmodule/xmodule/open_ended_module.py index 94d45d96e3..2d6970e162 100644 --- a/common/lib/xmodule/xmodule/open_ended_module.py +++ b/common/lib/xmodule/xmodule/open_ended_module.py @@ -548,13 +548,12 @@ class OpenEndedModule(openendedchild.OpenEndedChild): @param system: modulesystem @return: Success indicator """ - if self.attempts > self.max_attempts: - # If too many attempts, prevent student from saving answer and - # seeing rubric. In normal use, students shouldn't see this because - # they won't see the reset button once they're out of attempts. + # Once we close the problem, we should not allow students + # to save answers + if self.closed(): return { 'success': False, - 'error': 'Too many attempts.' + 'error': 'Problem is closed.' } if self.state != self.INITIAL: diff --git a/common/lib/xmodule/xmodule/openendedchild.py b/common/lib/xmodule/xmodule/openendedchild.py index 7151ac0723..8c35fb0cae 100644 --- a/common/lib/xmodule/xmodule/openendedchild.py +++ b/common/lib/xmodule/xmodule/openendedchild.py @@ -73,7 +73,7 @@ class OpenEndedChild(object): 'done': 'Problem complete', } - def __init__(self, system, location, definition, descriptor, static_data, + def __init__(self, system, location, definition, descriptor, static_data, parent, instance_state=None, shared_state=None, **kwargs): # Load instance state if instance_state is not None: @@ -87,6 +87,8 @@ class OpenEndedChild(object): # Scores are on scale from 0 to max_score self.history = instance_state.get('history', []) + self.parent = parent + self.state = instance_state.get('state', self.INITIAL) self.created = instance_state.get('created', False) @@ -116,6 +118,9 @@ class OpenEndedChild(object): """ pass + def closed(self): + return self.parent.closed() + def latest_answer(self): """Empty string if not available""" if not self.history: diff --git a/common/lib/xmodule/xmodule/self_assessment_module.py b/common/lib/xmodule/xmodule/self_assessment_module.py index 38a60e11f5..bb8b46559d 100644 --- a/common/lib/xmodule/xmodule/self_assessment_module.py +++ b/common/lib/xmodule/xmodule/self_assessment_module.py @@ -189,14 +189,11 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild): Dictionary with keys 'success' and either 'error' (if not success), or 'rubric_html' (if success). """ - # Check to see if attempts are less than max - if self.attempts > self.max_attempts: - # If too many attempts, prevent student from saving answer and - # seeing rubric. In normal use, students shouldn't see this because - # they won't see the reset button once they're out of attempts. + # Check to see if this problem is closed + if self.closed(): return { 'success': False, - 'error': 'Too many attempts.' + 'error': 'This problem is now closed.' } if self.state != self.INITIAL: 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 c89f5ee848..69c502cd5d 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -43,11 +43,14 @@ class OpenEndedChildTest(unittest.TestCase): 'accept_file_upload' : False, } definition = Mock() + parent = Mock() + parent.closed.return_value = False; descriptor = Mock() def setUp(self): self.openendedchild = OpenEndedChild(test_system, self.location, - self.definition, self.descriptor, self.static_data, self.metadata) + self.definition, self.descriptor, self.static_data, + self.parent, self.metadata) def test_latest_answer_empty(self): @@ -166,6 +169,8 @@ class OpenEndedModuleTest(unittest.TestCase): ''') definition = {'oeparam': oeparam} descriptor = Mock() + parent = Mock() + parent.closed.return_value = False; def setUp(self): test_system.location = self.location @@ -173,7 +178,8 @@ class OpenEndedModuleTest(unittest.TestCase): self.mock_xqueue.send_to_queue.return_value=(None, "Message") test_system.xqueue = {'interface':self.mock_xqueue, 'callback_url':'/', 'default_queuename': 'testqueue', 'waittime': 1} self.openendedmodule = OpenEndedModule(test_system, self.location, - self.definition, self.descriptor, self.static_data, self.metadata) + self.definition, self.descriptor, self.static_data, + self.parent, self.metadata) def test_message_post(self): get = {'feedback': 'feedback text', diff --git a/common/lib/xmodule/xmodule/tests/test_self_assessment.py b/common/lib/xmodule/xmodule/tests/test_self_assessment.py index c5fb82e412..74018cf101 100644 --- a/common/lib/xmodule/xmodule/tests/test_self_assessment.py +++ b/common/lib/xmodule/xmodule/tests/test_self_assessment.py @@ -30,6 +30,8 @@ class SelfAssessmentTest(unittest.TestCase): metadata = {'attempts': '10'} descriptor = Mock() + parent = Mock() + parent.closed.return_value = False def setUp(self): state = json.dumps({'student_answers': ["Answer 1", "answer 2", "answer 3"], @@ -49,7 +51,8 @@ class SelfAssessmentTest(unittest.TestCase): self.module = SelfAssessmentModule(test_system, self.location, self.definition, self.descriptor, - static_data, state, metadata=self.metadata) + static_data, self.parent, + state, metadata=self.metadata) def test_get_html(self): html = self.module.get_html(test_system) @@ -72,6 +75,7 @@ class SelfAssessmentTest(unittest.TestCase): # if we now assess as right, skip the REQUEST_HINT state self.module.save_answer({'student_answer': 'answer 4'}, test_system) + self.parent.closed.assert_called_with() self.module.save_assessment({'assessment': '1'}, test_system) self.assertEqual(self.module.state, self.module.DONE) From 85abc435159d4db466f04c24460b1a53f13f78f6 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Mon, 4 Feb 2013 14:02:42 -0500 Subject: [PATCH 2/7] Add in the ability to handle due dates and grace periods --- .../xmodule/combined_open_ended_module.py | 31 +++++++++++++++---- common/lib/xmodule/xmodule/timeparse.py | 25 +++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index e9b3d1d4d0..4c3e8da8c6 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -7,7 +7,11 @@ from lxml import etree from lxml.html import rewrite_links from path import path import os +import dateutil +import dateutil.parser +import datetime import sys +from timeparse import parse_timedelta from pkg_resources import resource_string @@ -155,12 +159,27 @@ class CombinedOpenEndedModule(XModule): self.attempts = instance_state.get('attempts', 0) + #Allow reset is true if student has failed the criteria to move to the next child task self.allow_reset = instance_state.get('ready_to_reset', False) self.max_attempts = int(self.metadata.get('attempts', MAX_ATTEMPTS)) self.is_scored = self.metadata.get('is_graded', IS_SCORED) in TRUE_DICT self.accept_file_upload = self.metadata.get('accept_file_upload', ACCEPT_FILE_UPLOAD) in TRUE_DICT + display_due_date_string = self.metadata.get('due', None) + if display_due_date_string is not None: + self.display_due_date = dateutil.parser.parse(display_due_date_string) + else: + self.display_due_date = None + + grace_period_string = self.metadata.get('graceperiod', None) + if grace_period_string is not None and self.display_due_date: + self.grace_period = parse_timedelta(grace_period_string) + self.close_date = self.display_due_date + self.grace_period + else: + self.grace_period = None + self.close_date = self.display_due_date + # Used for progress / grading. Currently get credit just for # completion (doesn't matter if you self-assessed correct/incorrect). self._max_score = int(self.metadata.get('max_score', MAX_SCORE)) @@ -189,12 +208,12 @@ class CombinedOpenEndedModule(XModule): self.setup_next_task() def closed(self): - return True - #''' Is the student still allowed to submit answers? ''' - #if self.attempts == self.max_attempts: - # return True - #if self.close_date is not None and datetime.datetime.utcnow() > self.close_date: - # return True + ''' Is the student still allowed to submit answers? ''' + if self.attempts == self.max_attempts: + return True + if self.close_date is not None and datetime.datetime.utcnow() > self.close_date: + return True + def get_tag_name(self, xml): diff --git a/common/lib/xmodule/xmodule/timeparse.py b/common/lib/xmodule/xmodule/timeparse.py index 36c0f725e5..605662654d 100644 --- a/common/lib/xmodule/xmodule/timeparse.py +++ b/common/lib/xmodule/xmodule/timeparse.py @@ -2,9 +2,14 @@ Helper functions for handling time in the format we like. """ import time +import re +from datetime import timedelta TIME_FORMAT = "%Y-%m-%dT%H:%M" +TIMEDELTA_REGEX = re.compile(r'^((?P\d+?) day(?:s?))?(\s)?((?P\d+?) hour(?:s?))?(\s)?((?P\d+?) minute(?:s)?)?(\s)?((?P\d+?) second(?:s)?)?$') + + def parse_time(time_str): """ Takes a time string in TIME_FORMAT @@ -20,3 +25,23 @@ def stringify_time(time_struct): Convert a time struct to a string """ return time.strftime(TIME_FORMAT, time_struct) + +def parse_timedelta(time_str): + """ + time_str: A string with the following components: + day[s] (optional) + hour[s] (optional) + minute[s] (optional) + second[s] (optional) + + Returns a datetime.timedelta parsed from the string + """ + parts = TIMEDELTA_REGEX.match(time_str) + if not parts: + return + parts = parts.groupdict() + time_params = {} + for (name, param) in parts.iteritems(): + if param: + time_params[name] = int(param) + return timedelta(**time_params) From 37900c3f7642c93ab2cf8b94427592c43a7adb4c Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Tue, 5 Feb 2013 15:37:20 -0500 Subject: [PATCH 3/7] Add more error logging for date parsing and make the closure checking more robust --- .../xmodule/combined_open_ended_module.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index 4c3e8da8c6..d85b0f6e17 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -168,14 +168,22 @@ class CombinedOpenEndedModule(XModule): display_due_date_string = self.metadata.get('due', None) if display_due_date_string is not None: - self.display_due_date = dateutil.parser.parse(display_due_date_string) + try: + self.display_due_date = dateutil.parser.parse(display_due_date_string) + except ValueError: + log.error("Could not parse due date {0} for location {1}".format(display_due_date_string, location)) + raise else: self.display_due_date = None grace_period_string = self.metadata.get('graceperiod', None) if grace_period_string is not None and self.display_due_date: - self.grace_period = parse_timedelta(grace_period_string) - self.close_date = self.display_due_date + self.grace_period + try: + self.grace_period = parse_timedelta(grace_period_string) + self.close_date = self.display_due_date + self.grace_period + except: + log.error("Error parsing the grace period {0} for location {1}".format(grace_period_string, location)) + raise else: self.grace_period = None self.close_date = self.display_due_date @@ -209,7 +217,7 @@ class CombinedOpenEndedModule(XModule): def closed(self): ''' Is the student still allowed to submit answers? ''' - if self.attempts == self.max_attempts: + if self.attempts >= self.max_attempts: return True if self.close_date is not None and datetime.datetime.utcnow() > self.close_date: return True From 018412ca262718054ef6736473fa66c8a886bbb2 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Tue, 5 Feb 2013 15:41:23 -0500 Subject: [PATCH 4/7] Return False to make this code clearer --- common/lib/xmodule/xmodule/combined_open_ended_module.py | 1 + 1 file changed, 1 insertion(+) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index d85b0f6e17..ebcb044783 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -221,6 +221,7 @@ class CombinedOpenEndedModule(XModule): return True if self.close_date is not None and datetime.datetime.utcnow() > self.close_date: return True + return False From c70531ae27514aeebbc97e7d047452976af05b47 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Tue, 5 Feb 2013 16:00:16 -0500 Subject: [PATCH 5/7] Move closed check logic into the OpenEndedChild --- .../xmodule/combined_open_ended_module.py | 18 +++++------------- common/lib/xmodule/xmodule/openendedchild.py | 9 +++++---- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index ebcb044783..15a101e876 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -210,20 +210,12 @@ class CombinedOpenEndedModule(XModule): 'rubric': definition['rubric'], 'display_name': self.display_name, 'accept_file_upload': self.accept_file_upload, + 'close_date': self.close_date } self.task_xml = definition['task_xml'] self.setup_next_task() - def closed(self): - ''' Is the student still allowed to submit answers? ''' - if self.attempts >= self.max_attempts: - return True - if self.close_date is not None and datetime.datetime.utcnow() > self.close_date: - return True - return False - - def get_tag_name(self, xml): """ @@ -306,7 +298,7 @@ class CombinedOpenEndedModule(XModule): self.current_task_parsed_xml = self.current_task_descriptor.definition_from_xml(etree_xml, self.system) if current_task_state is None and self.current_task_number == 0: self.current_task = child_task_module(self.system, self.location, - self.current_task_parsed_xml, self.current_task_descriptor, self.static_data, self) + self.current_task_parsed_xml, self.current_task_descriptor, self.static_data) self.task_states.append(self.current_task.get_instance_state()) self.state = self.ASSESSING elif current_task_state is None and self.current_task_number > 0: @@ -322,7 +314,7 @@ class CombinedOpenEndedModule(XModule): }) self.current_task = child_task_module(self.system, self.location, self.current_task_parsed_xml, self.current_task_descriptor, self.static_data, - self, instance_state=current_task_state) + instance_state=current_task_state) self.task_states.append(self.current_task.get_instance_state()) self.state = self.ASSESSING else: @@ -330,7 +322,7 @@ class CombinedOpenEndedModule(XModule): current_task_state = self.overwrite_state(current_task_state) self.current_task = child_task_module(self.system, self.location, self.current_task_parsed_xml, self.current_task_descriptor, self.static_data, - self, instance_state=current_task_state) + instance_state=current_task_state) return True @@ -442,7 +434,7 @@ class CombinedOpenEndedModule(XModule): task_parsed_xml = task_descriptor.definition_from_xml(etree_xml, self.system) task = children['modules'][task_type](self.system, self.location, task_parsed_xml, task_descriptor, - self.static_data, self, instance_state=task_state) + self.static_data, instance_state=task_state) last_response = task.latest_answer() last_score = task.latest_score() last_post_assessment = task.latest_post_assessment(self.system) diff --git a/common/lib/xmodule/xmodule/openendedchild.py b/common/lib/xmodule/xmodule/openendedchild.py index 8c35fb0cae..9fa8959c95 100644 --- a/common/lib/xmodule/xmodule/openendedchild.py +++ b/common/lib/xmodule/xmodule/openendedchild.py @@ -73,7 +73,7 @@ class OpenEndedChild(object): 'done': 'Problem complete', } - def __init__(self, system, location, definition, descriptor, static_data, parent, + def __init__(self, system, location, definition, descriptor, static_data, instance_state=None, shared_state=None, **kwargs): # Load instance state if instance_state is not None: @@ -87,8 +87,6 @@ class OpenEndedChild(object): # Scores are on scale from 0 to max_score self.history = instance_state.get('history', []) - self.parent = parent - self.state = instance_state.get('state', self.INITIAL) self.created = instance_state.get('created', False) @@ -100,6 +98,7 @@ class OpenEndedChild(object): self.rubric = static_data['rubric'] self.display_name = static_data['display_name'] self.accept_file_upload = static_data['accept_file_upload'] + self.close_date = static_data['close_date'] # Used for progress / grading. Currently get credit just for # completion (doesn't matter if you self-assessed correct/incorrect). @@ -119,7 +118,9 @@ class OpenEndedChild(object): pass def closed(self): - return self.parent.closed() + if self.close_date is not None and datetime.utcnow() > self.close_date: + return True + return False def latest_answer(self): """Empty string if not available""" From 31c89e6d031494e737ab9358869365db8cffb4fc Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Tue, 5 Feb 2013 16:06:14 -0500 Subject: [PATCH 6/7] Consolidate error messages. --- common/lib/xmodule/xmodule/open_ended_module.py | 8 +++----- common/lib/xmodule/xmodule/openendedchild.py | 16 ++++++++++++++++ .../xmodule/xmodule/self_assessment_module.py | 8 +++----- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/common/lib/xmodule/xmodule/open_ended_module.py b/common/lib/xmodule/xmodule/open_ended_module.py index 2d6970e162..9d2e3e6a54 100644 --- a/common/lib/xmodule/xmodule/open_ended_module.py +++ b/common/lib/xmodule/xmodule/open_ended_module.py @@ -550,11 +550,9 @@ class OpenEndedModule(openendedchild.OpenEndedChild): """ # Once we close the problem, we should not allow students # to save answers - if self.closed(): - return { - 'success': False, - 'error': 'Problem is closed.' - } + closed, msg = self.check_if_closed() + if closed: + return msg if self.state != self.INITIAL: return self.out_of_sync_error(get) diff --git a/common/lib/xmodule/xmodule/openendedchild.py b/common/lib/xmodule/xmodule/openendedchild.py index 9fa8959c95..185472d0da 100644 --- a/common/lib/xmodule/xmodule/openendedchild.py +++ b/common/lib/xmodule/xmodule/openendedchild.py @@ -122,6 +122,22 @@ class OpenEndedChild(object): return True return False + def check_if_closed(self): + if self.closed(): + return True, { + 'success': False, + 'error': 'This problem is now closed.' + } + elif self.attempts > self.max_attempts: + return True, { + 'success': False, + 'error': 'Too many attempts.' + } + else: + return False, {} + + + def latest_answer(self): """Empty string if not available""" if not self.history: diff --git a/common/lib/xmodule/xmodule/self_assessment_module.py b/common/lib/xmodule/xmodule/self_assessment_module.py index bb8b46559d..14d5c31fc2 100644 --- a/common/lib/xmodule/xmodule/self_assessment_module.py +++ b/common/lib/xmodule/xmodule/self_assessment_module.py @@ -190,11 +190,9 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild): or 'rubric_html' (if success). """ # Check to see if this problem is closed - if self.closed(): - return { - 'success': False, - 'error': 'This problem is now closed.' - } + closed, msg = self.check_if_closed() + if closed: + return msg if self.state != self.INITIAL: return self.out_of_sync_error(get) From a7588410b2fccf86759c8c6ab406d2240abb056d Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Tue, 5 Feb 2013 16:11:04 -0500 Subject: [PATCH 7/7] Fix tests --- .../xmodule/xmodule/tests/test_combined_open_ended.py | 10 ++++------ .../lib/xmodule/xmodule/tests/test_self_assessment.py | 6 ++---- 2 files changed, 6 insertions(+), 10 deletions(-) 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 69c502cd5d..e58e8c024b 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -41,16 +41,15 @@ class OpenEndedChildTest(unittest.TestCase): 'max_score': max_score, 'display_name': 'Name', 'accept_file_upload' : False, + 'close_date': None } definition = Mock() - parent = Mock() - parent.closed.return_value = False; descriptor = Mock() def setUp(self): self.openendedchild = OpenEndedChild(test_system, self.location, self.definition, self.descriptor, self.static_data, - self.parent, self.metadata) + self.metadata) def test_latest_answer_empty(self): @@ -158,6 +157,7 @@ class OpenEndedModuleTest(unittest.TestCase): 'max_score': max_score, 'display_name': 'Name', 'accept_file_upload': False, + 'close_date': None } oeparam = etree.XML(''' @@ -169,8 +169,6 @@ class OpenEndedModuleTest(unittest.TestCase): ''') definition = {'oeparam': oeparam} descriptor = Mock() - parent = Mock() - parent.closed.return_value = False; def setUp(self): test_system.location = self.location @@ -179,7 +177,7 @@ class OpenEndedModuleTest(unittest.TestCase): test_system.xqueue = {'interface':self.mock_xqueue, 'callback_url':'/', 'default_queuename': 'testqueue', 'waittime': 1} self.openendedmodule = OpenEndedModule(test_system, self.location, self.definition, self.descriptor, self.static_data, - self.parent, self.metadata) + self.metadata) def test_message_post(self): get = {'feedback': 'feedback text', diff --git a/common/lib/xmodule/xmodule/tests/test_self_assessment.py b/common/lib/xmodule/xmodule/tests/test_self_assessment.py index 74018cf101..3cae123ffe 100644 --- a/common/lib/xmodule/xmodule/tests/test_self_assessment.py +++ b/common/lib/xmodule/xmodule/tests/test_self_assessment.py @@ -30,8 +30,6 @@ class SelfAssessmentTest(unittest.TestCase): metadata = {'attempts': '10'} descriptor = Mock() - parent = Mock() - parent.closed.return_value = False def setUp(self): state = json.dumps({'student_answers': ["Answer 1", "answer 2", "answer 3"], @@ -47,11 +45,12 @@ class SelfAssessmentTest(unittest.TestCase): 'max_score': 1, 'display_name': "Name", 'accept_file_upload' : False, + 'close_date': None } self.module = SelfAssessmentModule(test_system, self.location, self.definition, self.descriptor, - static_data, self.parent, + static_data, state, metadata=self.metadata) def test_get_html(self): @@ -75,7 +74,6 @@ class SelfAssessmentTest(unittest.TestCase): # if we now assess as right, skip the REQUEST_HINT state self.module.save_answer({'student_answer': 'answer 4'}, test_system) - self.parent.closed.assert_called_with() self.module.save_assessment({'assessment': '1'}, test_system) self.assertEqual(self.module.state, self.module.DONE)