From 448c8121c332d2517e8f96b3e0716fe68262a12e Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 9 Apr 2013 13:37:37 -0400 Subject: [PATCH 01/31] Patch combinedopenended to work if self assessment is not first --- .../combined_open_ended_modulev1.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) 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 59df481954..5fa6e737d2 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 @@ -417,13 +417,16 @@ class CombinedOpenEndedV1Module(): else: last_post_evaluation = task.format_feedback_with_evaluation(self.system, last_post_assessment) last_post_assessment = last_post_evaluation - rubric_data = task._parse_score_msg(task.child_history[-1].get('post_assessment', ""), self.system) - rubric_scores = rubric_data['rubric_scores'] - grader_types = rubric_data['grader_types'] - feedback_items = rubric_data['feedback_items'] - feedback_dicts = rubric_data['feedback_dicts'] - grader_ids = rubric_data['grader_ids'] - submission_ids = rubric_data['submission_ids'] + try: + rubric_data = task._parse_score_msg(task.child_history[-1].get('post_assessment', ""), self.system) + except: + rubric_data = {} + rubric_scores = rubric_data.get('rubric_scores') + grader_types = rubric_data.get('grader_types') + feedback_items = rubric_data.get('feedback_items') + feedback_dicts = rubric_data.get('feedback_dicts') + grader_ids = rubric_data.get('grader_ids') + submission_ids = rubric_data.get('submission_ids') elif task_type == "selfassessment": rubric_scores = last_post_assessment grader_types = ['SA'] @@ -441,7 +444,7 @@ class CombinedOpenEndedV1Module(): human_state = task.HUMAN_NAMES[state] else: human_state = state - if len(grader_types) > 0: + if grader_types is not None and len(grader_types) > 0: grader_type = grader_types[0] else: grader_type = "IN" From 9cca3072c3211e34233be599feb17244c096115d Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 9 Apr 2013 13:53:51 -0400 Subject: [PATCH 02/31] Fix skip behavior for staff --- .../open_ended_grading/staff_grading_service.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lms/djangoapps/open_ended_grading/staff_grading_service.py b/lms/djangoapps/open_ended_grading/staff_grading_service.py index 57bfd7df42..885f6bbfa1 100644 --- a/lms/djangoapps/open_ended_grading/staff_grading_service.py +++ b/lms/djangoapps/open_ended_grading/staff_grading_service.py @@ -310,19 +310,22 @@ def save_grade(request, course_id): if request.method != 'POST': raise Http404 - - required = set(['score', 'feedback', 'submission_id', 'location', 'submission_flagged', 'rubric_scores[]']) - actual = set(request.POST.keys()) + p = request.POST + required = set(['score', 'feedback', 'submission_id', 'location', 'submission_flagged']) + skipped = 'skipped' in p + if not skipped: + required|=set(['rubric_scores[]']) + actual = set(p.keys()) missing = required - actual if len(missing) > 0: return _err_response('Missing required keys {0}'.format( ', '.join(missing))) grader_id = unique_id_for_user(request.user) - p = request.POST + location = p['location'] - skipped = 'skipped' in p + try: result_json = staff_grading_service().save_grade(course_id, From 45a3dd4ee01c3d85a3aa5dc6e2e887e179d7acef Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 9 Apr 2013 14:13:29 -0400 Subject: [PATCH 03/31] Fix file uploads to work after error --- .../lib/xmodule/xmodule/js/src/combinedopenended/display.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee b/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee index c749d65b45..3ce3539c7f 100644 --- a/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee @@ -322,6 +322,7 @@ class @CombinedOpenEnded save_answer: (event) => event.preventDefault() max_filesize = 2*1000*1000 #2MB + pre_can_upload_files = @can_upload_files if @child_state == 'initial' files = "" if @can_upload_files == true @@ -353,6 +354,7 @@ class @CombinedOpenEnded @find_assessment_elements() @rebind() else + @can_upload_files = pre_can_upload_files @gentle_alert response.error $.ajaxWithPrefix("#{@ajax_url}/save_answer",settings) From 112fb4539bbb39579bcc47caa77fd8cfc56758fa Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 9 Apr 2013 14:43:41 -0400 Subject: [PATCH 04/31] Correctly calculate score for combinedopenended and peer assessment --- .../xmodule/combined_open_ended_module.py | 2 +- .../combined_open_ended_modulev1.py | 15 ++++++++----- .../xmodule/xmodule/peer_grading_module.py | 21 ++++++++++++++----- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index 29d1270893..8337beab5a 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -14,7 +14,7 @@ from xmodule.open_ended_grading_classes.xblock_field_types import StringyFloat log = logging.getLogger("mitx.courseware") V1_SETTINGS_ATTRIBUTES = ["display_name", "attempts", "is_graded", "accept_file_upload", - "skip_spelling_checks", "due", "graceperiod"] + "skip_spelling_checks", "due", "graceperiod", "weight"] V1_STUDENT_ATTRIBUTES = ["current_task_number", "task_states", "state", "student_attempts", "ready_to_reset"] 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 5fa6e737d2..4d064824df 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 @@ -131,6 +131,7 @@ class CombinedOpenEndedV1Module(): self.state = instance_state.get('state', self.INITIAL) self.student_attempts = instance_state.get('student_attempts', 0) + self.weight = instance_state.get('weight', 1) #Allow reset is true if student has failed the criteria to move to the next child task self.ready_to_reset = instance_state.get('ready_to_reset', False) @@ -736,13 +737,17 @@ class CombinedOpenEndedV1Module(): max_score = None score = None if self.check_if_done_and_scored(): - last_response = self.get_last_response(self.current_task_number) - max_score = last_response['max_score'] - score = last_response['score'] + scores = [] + for i in xrange(0,self.current_task_number): + last_response = self.get_last_response(i) + max_score = last_response['max_score'] * float(self.weight) + score = last_response['score'] * float(self.weight) + scores.append(score) + score = max(scores) score_dict = { - 'score': score, - 'total': max_score, + 'score': score , + 'total': max_score , } return score_dict diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py index 5075507bce..007446d57e 100644 --- a/common/lib/xmodule/xmodule/peer_grading_module.py +++ b/common/lib/xmodule/xmodule/peer_grading_module.py @@ -178,8 +178,16 @@ class PeerGradingModule(PeerGradingFields, XModule): pass def get_score(self): + max_score = None + score = None + score_dict = { + 'score': score, + 'total': max_score, + } if self.use_for_single_location not in TRUE_DICT or self.is_graded not in TRUE_DICT: - return None + return score_dict + + try: count_graded = self.student_data_for_location['count_graded'] @@ -198,10 +206,13 @@ class PeerGradingModule(PeerGradingFields, XModule): #Ensures that once a student receives a final score for peer grading, that it does not change. self.student_data_for_location = response - score_dict = { - 'score': int(count_graded >= count_required and count_graded>0) * int(self.weight), - 'total': self.max_grade * int(self.weight), - } + try: + score = int(count_graded >= count_required and count_graded>0) * float(self.weight) + total = self.max_grade * float(self.weight) + score_dict['score'] = score + score_dict['total'] = total + except: + pass return score_dict From 247ccc37a67aefa9d1dd5360bc97e4bf24c9154d Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 9 Apr 2013 14:47:26 -0400 Subject: [PATCH 05/31] Code reformat, patch score gen --- .../combined_open_ended_modulev1.py | 16 ++++++++++------ .../lib/xmodule/xmodule/peer_grading_module.py | 8 +++----- 2 files changed, 13 insertions(+), 11 deletions(-) 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 4d064824df..9c8f631f2c 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 @@ -740,14 +740,18 @@ class CombinedOpenEndedV1Module(): scores = [] for i in xrange(0,self.current_task_number): last_response = self.get_last_response(i) - max_score = last_response['max_score'] * float(self.weight) - score = last_response['score'] * float(self.weight) - scores.append(score) - score = max(scores) + try: + max_score = last_response['max_score'] * float(self.weight) + score = last_response['score'] * float(self.weight) + scores.append(score) + except: + pass + if len(scores)>0: + score = max(scores) score_dict = { - 'score': score , - 'total': max_score , + 'score': score, + 'total': max_score, } return score_dict diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py index 007446d57e..c4d5f81ed4 100644 --- a/common/lib/xmodule/xmodule/peer_grading_module.py +++ b/common/lib/xmodule/xmodule/peer_grading_module.py @@ -183,12 +183,10 @@ class PeerGradingModule(PeerGradingFields, XModule): score_dict = { 'score': score, 'total': max_score, - } + } if self.use_for_single_location not in TRUE_DICT or self.is_graded not in TRUE_DICT: return score_dict - - try: count_graded = self.student_data_for_location['count_graded'] count_required = self.student_data_for_location['count_required'] @@ -207,7 +205,7 @@ class PeerGradingModule(PeerGradingFields, XModule): self.student_data_for_location = response try: - score = int(count_graded >= count_required and count_graded>0) * float(self.weight) + score = int(count_graded >= count_required and count_graded > 0) * float(self.weight) total = self.max_grade * float(self.weight) score_dict['score'] = score score_dict['total'] = total @@ -588,5 +586,5 @@ class PeerGradingDescriptor(PeerGradingFields, RawDescriptor): stores_state = True has_score = True - always_recalculate_grades=True + always_recalculate_grades = True template_dir_name = "peer_grading" From 418f218eec1583f70420b220d2bb672921e6af8e Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 9 Apr 2013 15:33:11 -0400 Subject: [PATCH 06/31] Fix some templates, minor code reformats --- .../combined_open_ended_modulev1.py | 4 ++-- .../xmodule/xmodule/templates/combinedopenended/default.yaml | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) 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 9c8f631f2c..903b3133ed 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 @@ -738,7 +738,7 @@ class CombinedOpenEndedV1Module(): score = None if self.check_if_done_and_scored(): scores = [] - for i in xrange(0,self.current_task_number): + for i in xrange(0, self.current_task_number): last_response = self.get_last_response(i) try: max_score = last_response['max_score'] * float(self.weight) @@ -746,7 +746,7 @@ class CombinedOpenEndedV1Module(): scores.append(score) except: pass - if len(scores)>0: + if len(scores) > 0: score = max(scores) score_dict = { diff --git a/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml b/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml index 515d9071b1..a11367b46f 100644 --- a/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml +++ b/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml @@ -1,10 +1,9 @@ --- metadata: display_name: Open Ended Response - max_attempts: 1 + attempts: 1 is_graded: False version: 1 - display_name: Open Ended Response skip_spelling_checks: False accept_file_upload: False weight: "" From 7d381474901bd9a722a651cb215f749bab53c707 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 9 Apr 2013 15:34:35 -0400 Subject: [PATCH 07/31] Remove attempts field from peer grading template --- common/lib/xmodule/xmodule/templates/peer_grading/default.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/common/lib/xmodule/xmodule/templates/peer_grading/default.yaml b/common/lib/xmodule/xmodule/templates/peer_grading/default.yaml index 1ba8f978d6..23d41d616f 100644 --- a/common/lib/xmodule/xmodule/templates/peer_grading/default.yaml +++ b/common/lib/xmodule/xmodule/templates/peer_grading/default.yaml @@ -1,7 +1,6 @@ --- metadata: display_name: Peer Grading Interface - attempts: 1 use_for_single_location: False link_to_location: None is_graded: False From 463a88ccfbac036296935c8bd171cad8ae24b67d Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 9 Apr 2013 16:54:27 -0400 Subject: [PATCH 08/31] Display rubric to students after calibration --- .../xmodule/xmodule/css/combinedopenended/display.scss | 1 + .../js/src/peergrading/peer_grading_problem.coffee | 4 +++- common/lib/xmodule/xmodule/peer_grading_module.py | 9 +++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/common/lib/xmodule/xmodule/css/combinedopenended/display.scss b/common/lib/xmodule/xmodule/css/combinedopenended/display.scss index 20700ab092..8378f60023 100644 --- a/common/lib/xmodule/xmodule/css/combinedopenended/display.scss +++ b/common/lib/xmodule/xmodule/css/combinedopenended/display.scss @@ -122,6 +122,7 @@ div.combined-rubric-container { span.rubric-category { font-size: .9em; + font-weight: bold; } padding-bottom: 5px; padding-top: 10px; diff --git a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee index 4bdb4bdf05..f57227223c 100644 --- a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee +++ b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee @@ -443,7 +443,6 @@ class @PeerGradingProblem calibration_wrapper = $('.calibration-feedback-wrapper') calibration_wrapper.html("

The score you gave was: #{@grade}. The actual score is: #{response.actual_score}

") - score = parseInt(@grade) actual_score = parseInt(response.actual_score) @@ -452,6 +451,9 @@ class @PeerGradingProblem else calibration_wrapper.append("

You may want to review the rubric again.

") + if response.actual_rubric != undefined + calibration_wrapper.append("
Instructor Scored Rubric: #{response.actual_rubric}
") + # disable score selection and submission from the grading interface $("input[name='score-selection']").attr('disabled', true) @submit_button.hide() diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py index c4d5f81ed4..3916c76d37 100644 --- a/common/lib/xmodule/xmodule/peer_grading_module.py +++ b/common/lib/xmodule/xmodule/peer_grading_module.py @@ -15,6 +15,7 @@ from xmodule.open_ended_grading_classes.xblock_field_types import StringyFloat from xmodule.fields import Date from xmodule.open_ended_grading_classes.peer_grading_service import PeerGradingService, GradingServiceError, MockPeerGradingService +from open_ended_grading_classes import combined_open_ended_rubric log = logging.getLogger(__name__) @@ -394,7 +395,7 @@ class PeerGradingModule(PeerGradingFields, XModule): except etree.XMLSyntaxError: #This is a dev_facing_error log.exception("Cannot parse rubric string. Raw string: {0}" - .format(rubric)) + .format("")) #This is a student_facing_error return {'success': False, 'error': 'Error displaying submission. Please notify course staff.'} @@ -434,12 +435,16 @@ class PeerGradingModule(PeerGradingFields, XModule): try: response = self.peer_gs.save_calibration_essay(location, grader_id, calibration_essay_id, submission_key, score, feedback, rubric_scores) + log.debug("RESPONSE RESPONSE : {0}".format(response)) + if 'actual_rubric' in response: + rubric_renderer = combined_open_ended_rubric.CombinedOpenEndedRubric(self.system, True) + response['actual_rubric'] = rubric_renderer.render_rubric(response['actual_rubric'])['html'] return response except GradingServiceError: #This is a dev_facing_error log.exception( "Error saving calibration grade, location: {0}, submission_id: {1}, submission_key: {2}, grader_id: {3}".format( - location, submission_id, submission_key, grader_id)) + location, submission_key, grader_id)) #This is a student_facing_error return self._err_response('There was an error saving your score. Please notify course staff.') From d0ecbbb4cf3b266f110bb46108c18a25ab1e1628 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 10 Apr 2013 15:10:48 -0400 Subject: [PATCH 09/31] Fix hotkeys in peer and staff grading to use ctrl prefix --- .../js/src/peergrading/peer_grading_problem.coffee | 10 ++++++++-- .../coffee/src/staff_grading/staff_grading.coffee | 12 ++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee index f57227223c..b48ac9a919 100644 --- a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee +++ b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee @@ -161,6 +161,7 @@ class @PeerGradingProblem constructor: (backend) -> @prompt_wrapper = $('.prompt-wrapper') @backend = backend + @is_ctrl = false # get the location of the problem @@ -212,6 +213,7 @@ class @PeerGradingProblem @answer_unknown_checkbox = $('.answer-unknown-checkbox') $(window).keydown @keydown_handler + $(window).keyup @keyup_handler @collapse_question() @@ -338,13 +340,17 @@ class @PeerGradingProblem @grade = Rubric.get_total_score() keydown_handler: (event) => - if event.which == 13 && @submit_button.is(':visible') + if event.which == 17 && @is_ctrl==false + @is_ctrl=true + else if event.which == 13 && @submit_button.is(':visible') && @is_ctrl==true if @calibration @submit_calibration_essay() else @submit_grade() - + keyup_handler: (event) => + if event.which == 17 && @is_ctrl==true + @is_ctrl=false ########## diff --git a/lms/static/coffee/src/staff_grading/staff_grading.coffee b/lms/static/coffee/src/staff_grading/staff_grading.coffee index 6af9ecf5d1..ca200570de 100644 --- a/lms/static/coffee/src/staff_grading/staff_grading.coffee +++ b/lms/static/coffee/src/staff_grading/staff_grading.coffee @@ -185,6 +185,7 @@ class @StaffGrading $(window).keydown @keydown_handler + $(window).keyup @keyup_handler @question_header = $('.question-header') @question_header.click @collapse_question @collapse_question() @@ -206,6 +207,7 @@ class @StaffGrading @num_pending = 0 @score_lst = [] @grade = null + @is_ctrl = false @problems = null @@ -231,10 +233,16 @@ class @StaffGrading @state = state_graded @submit_button.show() - keydown_handler: (e) => - if e.which == 13 && !@list_view && Rubric.check_complete() + keydown_handler: (event) => + if event.which == 17 && @is_ctrl==false + @is_ctrl=true + else if @is_ctrl==true && event.which == 13 && !@list_view && Rubric.check_complete() @submit_and_get_next() + keyup_handler: (event) => + if event.which == 17 && @is_ctrl==true + @is_ctrl=false + set_button_text: (text) => @action_button.attr('value', text) From 799c8282bca304ad54f613072e79fc4ebb8871b5 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 10 Apr 2013 15:15:22 -0400 Subject: [PATCH 10/31] Fix hotkeys for combined open ended --- .../js/src/combinedopenended/display.coffee | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee b/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee index 3ce3539c7f..fa090785d5 100644 --- a/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee @@ -90,6 +90,7 @@ class @CombinedOpenEnded @element=element @reinitialize(element) $(window).keydown @keydown_handler + $(window).keyup @keyup_handler reinitialize: (element) -> @wrapper=$(element).find('section.xmodule_CombinedOpenEndedModule') @@ -104,6 +105,7 @@ class @CombinedOpenEnded @location = @el.data('location') # set up handlers for click tracking Rubric.initialize(@location) + @is_ctrl = false @allow_reset = @el.data('allow_reset') @reset_button = @$('.reset-button') @@ -362,10 +364,15 @@ class @CombinedOpenEnded else @errors_area.html(@out_of_sync_message) - keydown_handler: (e) => - # only do anything when the key pressed is the 'enter' key - if e.which == 13 && @child_state == 'assessing' && Rubric.check_complete() - @save_assessment(e) + keydown_handler: (event) => + if event.which == 17 && @is_ctrl==false + @is_ctrl=true + else if @is_ctrl==true && event.which == 13 && @child_state == 'assessing' && Rubric.check_complete() + @save_assessment(event) + + keyup_handler: (event) => + if event.which == 17 && @is_ctrl==true + @is_ctrl=false save_assessment: (event) => event.preventDefault() From cef4d0cb0911639a26c498c0707c7e6af5d89195 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 10 Apr 2013 15:25:05 -0400 Subject: [PATCH 11/31] Display instructor feedback --- .../xmodule/js/src/peergrading/peer_grading_problem.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee index b48ac9a919..de5b5be46a 100644 --- a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee +++ b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee @@ -459,6 +459,7 @@ class @PeerGradingProblem if response.actual_rubric != undefined calibration_wrapper.append("
Instructor Scored Rubric: #{response.actual_rubric}
") + calibration_wrapper.append("
Instructor Feedback: #{response.actual_feedback}
") # disable score selection and submission from the grading interface $("input[name='score-selection']").attr('disabled', true) From 2a5631da86cd5638edf80a56a88c219961ba6e18 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 10 Apr 2013 15:26:45 -0400 Subject: [PATCH 12/31] Code cleanup --- .../xmodule/js/src/peergrading/peer_grading_problem.coffee | 1 + common/lib/xmodule/xmodule/peer_grading_module.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee index de5b5be46a..4574ec3c93 100644 --- a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee +++ b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee @@ -459,6 +459,7 @@ class @PeerGradingProblem if response.actual_rubric != undefined calibration_wrapper.append("
Instructor Scored Rubric: #{response.actual_rubric}
") + if response.actual_feedback!=undefined calibration_wrapper.append("
Instructor Feedback: #{response.actual_feedback}
") # disable score selection and submission from the grading interface diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py index 3916c76d37..de4922e60a 100644 --- a/common/lib/xmodule/xmodule/peer_grading_module.py +++ b/common/lib/xmodule/xmodule/peer_grading_module.py @@ -435,7 +435,6 @@ class PeerGradingModule(PeerGradingFields, XModule): try: response = self.peer_gs.save_calibration_essay(location, grader_id, calibration_essay_id, submission_key, score, feedback, rubric_scores) - log.debug("RESPONSE RESPONSE : {0}".format(response)) if 'actual_rubric' in response: rubric_renderer = combined_open_ended_rubric.CombinedOpenEndedRubric(self.system, True) response['actual_rubric'] = rubric_renderer.render_rubric(response['actual_rubric'])['html'] From a64d57ae1d12cc898feb8fc7d2ac7f9efd4ffba5 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 10 Apr 2013 16:01:56 -0400 Subject: [PATCH 13/31] Add popup when flag box is checked --- .../js/src/peergrading/peer_grading_problem.coffee | 9 +++++++++ .../peer_grading/peer_grading_problem.html | 14 +++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee index 4574ec3c93..6785ab0541 100644 --- a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee +++ b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee @@ -184,6 +184,7 @@ class @PeerGradingProblem @grading_message.hide() @question_header = $('.question-header') @question_header.click @collapse_question + @flag_submission_confirmation = $('.flag-submission-confirmation') @grading_wrapper =$('.grading-wrapper') @calibration_feedback_panel = $('.calibration-feedback') @@ -235,9 +236,13 @@ class @PeerGradingProblem @calibration_interstitial_page.hide() @is_calibrated_check() + @flag_student_checkbox.click => + @flag_box_checked() + @calibration_feedback_button.hide() @calibration_feedback_panel.hide() @error_container.hide() + @flag_submission_confirmation.hide() @is_calibrated_check() @@ -285,6 +290,10 @@ class @PeerGradingProblem # ########## + flag_box_checked: () => + if @flag_student_checkbox.is(':checked') + $( ".flag-submission-confirmation" ).dialog() + # called after we perform an is_student_calibrated check calibration_check_callback: (response) => if response.success diff --git a/lms/templates/peer_grading/peer_grading_problem.html b/lms/templates/peer_grading/peer_grading_problem.html index 87559ec877..aa74fd9a6b 100644 --- a/lms/templates/peer_grading/peer_grading_problem.html +++ b/lms/templates/peer_grading/peer_grading_problem.html @@ -43,8 +43,8 @@

Please include some written feedback as well.

-
Flag this submission for review by course staff (use if the submission contains inappropriate content)
-
I do not know how to grade this question
+
This submission has explicit or pornographic content :
+
I do not know how to grade this question :
@@ -82,6 +82,14 @@ - + +
+

Are you sure that you want to flag this submission?

+
+ Please only flag explicit or pornographic content. +
+ + + From 9f04769c00b0caa80bf720ff63e652ccf91c7f3b Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 10 Apr 2013 16:16:13 -0400 Subject: [PATCH 14/31] Better confirmation for flagging --- .../js/src/peergrading/peer_grading_problem.coffee | 14 +++++++++++++- .../peer_grading/peer_grading_problem.html | 9 +++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee index 6785ab0541..7c2e9695b1 100644 --- a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee +++ b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee @@ -185,6 +185,11 @@ class @PeerGradingProblem @question_header = $('.question-header') @question_header.click @collapse_question @flag_submission_confirmation = $('.flag-submission-confirmation') + @flag_submission_confirmation_button = $('.flag-submission-confirmation-button') + @flag_submission_removal_button = $('.flag-submission-removal-button') + + @flag_submission_confirmation_button.click @close_dialog_box + @flag_submission_removal_button.click @remove_flag @grading_wrapper =$('.grading-wrapper') @calibration_feedback_panel = $('.calibration-feedback') @@ -290,9 +295,16 @@ class @PeerGradingProblem # ########## + remove_flag: () => + @flag_student_checkbox.removeAttr("checked") + @close_dialog_box() + + close_dialog_box: () => + $( ".flag-submission-confirmation" ).dialog('close') + flag_box_checked: () => if @flag_student_checkbox.is(':checked') - $( ".flag-submission-confirmation" ).dialog() + $( ".flag-submission-confirmation" ).dialog({ height: 400, width: 400 }) # called after we perform an is_student_calibrated check calibration_check_callback: (response) => diff --git a/lms/templates/peer_grading/peer_grading_problem.html b/lms/templates/peer_grading/peer_grading_problem.html index aa74fd9a6b..b4b900b874 100644 --- a/lms/templates/peer_grading/peer_grading_problem.html +++ b/lms/templates/peer_grading/peer_grading_problem.html @@ -85,8 +85,13 @@

Are you sure that you want to flag this submission?

-
- Please only flag explicit or pornographic content. +

+ Please only flag explicit or pornographic content. Click the button below if you understand this and still want to flag the submission. +

+
+ + +
From 820a2b407a699aae1b1cea2f053f327ea63cc108 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 10 Apr 2013 17:06:02 -0400 Subject: [PATCH 15/31] Add in js image upload preview --- .../xmodule/js/src/combinedopenended/display.coffee | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee b/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee index fa090785d5..8c5461ff56 100644 --- a/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee @@ -491,8 +491,10 @@ class @CombinedOpenEnded if @accept_file_upload == "True" if window.File and window.FileReader and window.FileList and window.Blob @can_upload_files = true - @file_upload_area.html('') + @file_upload_area.html('Uploaded image') @file_upload_area.show() + $('.file-upload-preview').hide() + $('.file-upload-box').change @preview_image else @gentle_alert 'File uploads are required for this question, but are not supported in this browser. Try the newest version of google chrome. Alternatively, if you have uploaded the image to the web, you can paste a link to it into the answer box.' @@ -548,3 +550,11 @@ class @CombinedOpenEnded log_feedback_selection: (event) -> target_selection = $(event.target).val() Logger.log 'oe_feedback_response_selected', {value: target_selection} + + preview_image: () => + if $('.file-upload-box')[0].files && $('.file-upload-box')[0].files[0] + reader = new FileReader() + reader.onload = (e) => + $('.file-upload-preview').attr('src', e.target.result).width(150).height(150) + $('.file-upload-preview').show() + reader.readAsDataURL($('.file-upload-box')[0].files[0]) From ca2eb9cd1b331636799e9b992bcf833746bc8957 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 10 Apr 2013 17:33:43 -0400 Subject: [PATCH 16/31] Add in tests for combinedopenended scoring --- .../xmodule/xmodule/tests/test_combined_open_ended.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 1950389399..3f55d22f14 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -323,6 +323,7 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): 's3_interface': test_util_open_ended.S3_INTERFACE, 'open_ended_grading_interface': test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE, 'skip_basic_checks': False, + 'is_graded' : True, } oeparam = etree.XML(''' @@ -369,7 +370,7 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): self.descriptor, static_data=self.static_data, metadata=self.metadata, - instance_state={}) + instance_state=self.static_data) def test_get_tag_name(self): name = self.combinedoe.get_tag_name("Tag") @@ -406,3 +407,10 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): def test_container_weight(self): weight = self.combinedoe_container.weight self.assertEqual(weight,1) + + def test_get_score(self): + score_dict = self.combinedoe.get_score() + self.assertEqual(score_dict['score'], None) + self.assertEqual(score_dict['total'], None) + + From 09e18cb8159e58d03f77c9d199e1aacb2af57283 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 10 Apr 2013 17:38:31 -0400 Subject: [PATCH 17/31] Add in tests for alternate xml orderings --- .../xmodule/tests/test_combined_open_ended.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) 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 3f55d22f14..8c192929b0 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -354,7 +354,11 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): ''' definition = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml1, task_xml2]} full_definition = definition_template.format(prompt=prompt, rubric=rubric, task1=task_xml1, task2=task_xml2) + definition_oe = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml2, task_xml2]} + definition_sa = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml1, task_xml1]} descriptor = Mock(data=full_definition) + descriptor_oe = Mock(data=definition_oe) + descriptor_sa = Mock(data=definition_sa) test_system = test_system() combinedoe_container = CombinedOpenEndedModule(test_system, location, @@ -371,6 +375,20 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): static_data=self.static_data, metadata=self.metadata, instance_state=self.static_data) + self.combinedoe_oe = CombinedOpenEndedV1Module(self.test_system, + self.location, + self.definition_oe, + self.descriptor_oe, + static_data=self.static_data, + metadata=self.metadata, + instance_state=self.static_data) + self.combinedoe_sa = CombinedOpenEndedV1Module(self.test_system, + self.location, + self.definition_sa, + self.descriptor_sa, + static_data=self.static_data, + metadata=self.metadata, + instance_state=self.static_data) def test_get_tag_name(self): name = self.combinedoe.get_tag_name("Tag") @@ -413,4 +431,13 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): self.assertEqual(score_dict['score'], None) self.assertEqual(score_dict['total'], None) + def test_open_ended_task_order(self): + changed = self.combinedoe_oe.update_task_states() + self.assertFalse(changed) + + def test_self_assessment_task_order(self): + changed = self.combinedoe_sa.update_task_states() + self.assertFalse(changed) + + From 442d0fcf4fcc99fc3d530d01b08a8c7e0ee8eec9 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 10 Apr 2013 17:41:10 -0400 Subject: [PATCH 18/31] Add tests for orderings with only one task --- .../xmodule/tests/test_combined_open_ended.py | 61 +++++++++++++------ 1 file changed, 44 insertions(+), 17 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 8c192929b0..e55dc66145 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -356,9 +356,13 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): full_definition = definition_template.format(prompt=prompt, rubric=rubric, task1=task_xml1, task2=task_xml2) definition_oe = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml2, task_xml2]} definition_sa = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml1, task_xml1]} + definition_sa_only = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml1]} + definition_oe_only = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml2]} descriptor = Mock(data=full_definition) descriptor_oe = Mock(data=definition_oe) descriptor_sa = Mock(data=definition_sa) + descriptor_oe_only = Mock(data=definition_oe) + descriptor_sa_only = Mock(data=definition_sa) test_system = test_system() combinedoe_container = CombinedOpenEndedModule(test_system, location, @@ -375,21 +379,6 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): static_data=self.static_data, metadata=self.metadata, instance_state=self.static_data) - self.combinedoe_oe = CombinedOpenEndedV1Module(self.test_system, - self.location, - self.definition_oe, - self.descriptor_oe, - static_data=self.static_data, - metadata=self.metadata, - instance_state=self.static_data) - self.combinedoe_sa = CombinedOpenEndedV1Module(self.test_system, - self.location, - self.definition_sa, - self.descriptor_sa, - static_data=self.static_data, - metadata=self.metadata, - instance_state=self.static_data) - def test_get_tag_name(self): name = self.combinedoe.get_tag_name("Tag") self.assertEqual(name, "t") @@ -432,11 +421,49 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): self.assertEqual(score_dict['total'], None) def test_open_ended_task_order(self): - changed = self.combinedoe_oe.update_task_states() + combinedoe_oe = CombinedOpenEndedV1Module(self.test_system, + self.location, + self.definition_oe, + self.descriptor_oe, + static_data=self.static_data, + metadata=self.metadata, + instance_state=self.static_data) + changed = combinedoe_oe.update_task_states() self.assertFalse(changed) def test_self_assessment_task_order(self): - changed = self.combinedoe_sa.update_task_states() + combinedoe_sa = CombinedOpenEndedV1Module(self.test_system, + self.location, + self.definition_sa, + self.descriptor_sa, + static_data=self.static_data, + metadata=self.metadata, + instance_state=self.static_data) + + changed = combinedoe_sa.update_task_states() + self.assertFalse(changed) + + def test_open_ended_only_task_order(self): + combinedoe_oe = CombinedOpenEndedV1Module(self.test_system, + self.location, + self.definition_oe_only, + self.descriptor_oe_only, + static_data=self.static_data, + metadata=self.metadata, + instance_state=self.static_data) + changed = combinedoe_oe.update_task_states() + self.assertFalse(changed) + + def test_self_assessment_only_task_order(self): + combinedoe_sa = CombinedOpenEndedV1Module(self.test_system, + self.location, + self.definition_sa_only, + self.descriptor_sa_only, + static_data=self.static_data, + metadata=self.metadata, + instance_state=self.static_data) + + changed = combinedoe_sa.update_task_states() self.assertFalse(changed) From 4d3b4a60d670a743a311e9eb2aa2563f01d8e14f Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Thu, 11 Apr 2013 11:51:27 -0400 Subject: [PATCH 19/31] Significantly less verbose test code --- .../xmodule/tests/test_combined_open_ended.py | 53 +++++-------------- 1 file changed, 13 insertions(+), 40 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 e55dc66145..fa6f7c8547 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -420,51 +420,24 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): self.assertEqual(score_dict['score'], None) self.assertEqual(score_dict['total'], None) - def test_open_ended_task_order(self): - combinedoe_oe = CombinedOpenEndedV1Module(self.test_system, - self.location, - self.definition_oe, - self.descriptor_oe, - static_data=self.static_data, - metadata=self.metadata, - instance_state=self.static_data) - changed = combinedoe_oe.update_task_states() - self.assertFalse(changed) - - def test_self_assessment_task_order(self): - combinedoe_sa = CombinedOpenEndedV1Module(self.test_system, - self.location, - self.definition_sa, - self.descriptor_sa, - static_data=self.static_data, - metadata=self.metadata, - instance_state=self.static_data) - - changed = combinedoe_sa.update_task_states() - self.assertFalse(changed) - - def test_open_ended_only_task_order(self): - combinedoe_oe = CombinedOpenEndedV1Module(self.test_system, + def test_alternate_orderings(self): + t1 = self.task_xml1 + t2 = self.task_xml2 + xml_to_test = [[t1], [t2], [t1,t1], [t1,t2], [t2,t2], [t2,t1], [t1,t2,t1]] + for xml in xml_to_test: + definition = {'prompt': etree.XML(self.prompt), 'rubric': etree.XML(self.rubric), 'task_xml': xml} + descriptor = Mock(data=definition) + combinedoe = CombinedOpenEndedV1Module(self.test_system, self.location, - self.definition_oe_only, - self.descriptor_oe_only, + definition, + descriptor, static_data=self.static_data, metadata=self.metadata, instance_state=self.static_data) - changed = combinedoe_oe.update_task_states() - self.assertFalse(changed) - def test_self_assessment_only_task_order(self): - combinedoe_sa = CombinedOpenEndedV1Module(self.test_system, - self.location, - self.definition_sa_only, - self.descriptor_sa_only, - static_data=self.static_data, - metadata=self.metadata, - instance_state=self.static_data) - - changed = combinedoe_sa.update_task_states() - self.assertFalse(changed) + changed = combinedoe.update_task_states() + self.assertFalse(changed) + From 358482c55b23d9298d07fface15ac04256b42ae3 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Thu, 11 Apr 2013 11:54:00 -0400 Subject: [PATCH 20/31] Add in test for child weight --- .../xmodule/tests/test_combined_open_ended.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 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 fa6f7c8547..212da3cca7 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -354,15 +354,7 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): ''' definition = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml1, task_xml2]} full_definition = definition_template.format(prompt=prompt, rubric=rubric, task1=task_xml1, task2=task_xml2) - definition_oe = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml2, task_xml2]} - definition_sa = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml1, task_xml1]} - definition_sa_only = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml1]} - definition_oe_only = {'prompt': etree.XML(prompt), 'rubric': etree.XML(rubric), 'task_xml': [task_xml2]} descriptor = Mock(data=full_definition) - descriptor_oe = Mock(data=definition_oe) - descriptor_sa = Mock(data=definition_sa) - descriptor_oe_only = Mock(data=definition_oe) - descriptor_sa_only = Mock(data=definition_sa) test_system = test_system() combinedoe_container = CombinedOpenEndedModule(test_system, location, @@ -415,6 +407,10 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): weight = self.combinedoe_container.weight self.assertEqual(weight,1) + def test_container_child_weight(self): + weight = self.combinedoe_container.child_module.weight + self.assertEqual(weight,1) + def test_get_score(self): score_dict = self.combinedoe.get_score() self.assertEqual(score_dict['score'], None) From 9acc59227992eca70cd2ebe88080256ac4ef5120 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 16 Apr 2013 10:23:08 -0400 Subject: [PATCH 21/31] Comments for hotkeys --- .../lib/xmodule/xmodule/js/src/combinedopenended/display.coffee | 2 ++ .../xmodule/js/src/peergrading/peer_grading_problem.coffee | 2 ++ lms/static/coffee/src/staff_grading/staff_grading.coffee | 2 ++ 3 files changed, 6 insertions(+) diff --git a/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee b/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee index 8c5461ff56..da41cad9ef 100644 --- a/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee @@ -365,12 +365,14 @@ class @CombinedOpenEnded @errors_area.html(@out_of_sync_message) keydown_handler: (event) => + #Previously, responses were submitted when hitting enter. Add in a modifier that ensures that ctrl+enter is needed. if event.which == 17 && @is_ctrl==false @is_ctrl=true else if @is_ctrl==true && event.which == 13 && @child_state == 'assessing' && Rubric.check_complete() @save_assessment(event) keyup_handler: (event) => + #Handle keyup event when ctrl key is released if event.which == 17 && @is_ctrl==true @is_ctrl=false diff --git a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee index 7c2e9695b1..9483932f80 100644 --- a/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee +++ b/common/lib/xmodule/xmodule/js/src/peergrading/peer_grading_problem.coffee @@ -361,6 +361,7 @@ class @PeerGradingProblem @grade = Rubric.get_total_score() keydown_handler: (event) => + #Previously, responses were submitted when hitting enter. Add in a modifier that ensures that ctrl+enter is needed. if event.which == 17 && @is_ctrl==false @is_ctrl=true else if event.which == 13 && @submit_button.is(':visible') && @is_ctrl==true @@ -370,6 +371,7 @@ class @PeerGradingProblem @submit_grade() keyup_handler: (event) => + #Handle keyup event when ctrl key is released if event.which == 17 && @is_ctrl==true @is_ctrl=false diff --git a/lms/static/coffee/src/staff_grading/staff_grading.coffee b/lms/static/coffee/src/staff_grading/staff_grading.coffee index ca200570de..f4a3360d1e 100644 --- a/lms/static/coffee/src/staff_grading/staff_grading.coffee +++ b/lms/static/coffee/src/staff_grading/staff_grading.coffee @@ -234,12 +234,14 @@ class @StaffGrading @submit_button.show() keydown_handler: (event) => + #Previously, responses were submitted when hitting enter. Add in a modifier that ensures that ctrl+enter is needed. if event.which == 17 && @is_ctrl==false @is_ctrl=true else if @is_ctrl==true && event.which == 13 && !@list_view && Rubric.check_complete() @submit_and_get_next() keyup_handler: (event) => + #Handle keyup event when ctrl key is released if event.which == 17 && @is_ctrl==true @is_ctrl=false From 0d4b9d26cfb3abf688edd711dfddd614d9d781b4 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 16 Apr 2013 10:51:23 -0400 Subject: [PATCH 22/31] Add in a test, rescale preview images --- .../js/src/combinedopenended/display.coffee | 19 ++++++++++++++++++- lms/djangoapps/open_ended_grading/tests.py | 10 +++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee b/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee index da41cad9ef..d4c2ff00ae 100644 --- a/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee @@ -553,10 +553,27 @@ class @CombinedOpenEnded target_selection = $(event.target).val() Logger.log 'oe_feedback_response_selected', {value: target_selection} + remove_attribute: (name) => + if $('.file-upload-preview').attr(name) + $('.file-upload-preview')[0].removeAttribute(name) + preview_image: () => if $('.file-upload-box')[0].files && $('.file-upload-box')[0].files[0] reader = new FileReader() reader.onload = (e) => - $('.file-upload-preview').attr('src', e.target.result).width(150).height(150) + max_dim = 150 + @remove_attribute('src') + @remove_attribute('height') + @remove_attribute('width') + $('.file-upload-preview').attr('src', e.target.result) + height_px = $('.file-upload-preview')[0].height + width_px = $('.file-upload-preview')[0].width + scale_factor = 0 + if height_px>width_px + scale_factor = height_px/max_dim + else + scale_factor = width_px/max_dim + $('.file-upload-preview')[0].width = width_px/scale_factor + $('.file-upload-preview')[0].height = height_px/scale_factor $('.file-upload-preview').show() reader.readAsDataURL($('.file-upload-box')[0].files[0]) diff --git a/lms/djangoapps/open_ended_grading/tests.py b/lms/djangoapps/open_ended_grading/tests.py index e554fdf0e1..93d27d8e24 100644 --- a/lms/djangoapps/open_ended_grading/tests.py +++ b/lms/djangoapps/open_ended_grading/tests.py @@ -97,7 +97,7 @@ class TestStaffGradingService(LoginEnrollmentTestCase): self.assertIsNotNone(d['rubric']) - def test_save_grade(self): + def save_grade_base(self,skip=False): self.login(self.instructor, self.password) url = reverse('staff_grading_save_grade', kwargs={'course_id': self.course_id}) @@ -108,12 +108,20 @@ class TestStaffGradingService(LoginEnrollmentTestCase): 'location': self.location, 'submission_flagged': "true", 'rubric_scores[]': ['1', '2']} + if skip: + data.update({'skipped' : True}) r = self.check_for_post_code(200, url, data) d = json.loads(r.content) self.assertTrue(d['success'], str(d)) self.assertEquals(d['submission_id'], self.mock_service.cnt) + def test_save_grade(self): + self.save_grade_base(skip=False) + + def test_save_grade_skip(self): + self.save_grade_base(skip=True) + def test_get_problem_list(self): self.login(self.instructor, self.password) From dc7913dc1e9137073752477c61587f8d7e969629 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 16 Apr 2013 10:55:58 -0400 Subject: [PATCH 23/31] Add in a log debug message for except clause. --- .../open_ended_grading_classes/combined_open_ended_modulev1.py | 2 ++ 1 file changed, 2 insertions(+) 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 903b3133ed..e79ab4c25e 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 @@ -421,6 +421,8 @@ class CombinedOpenEndedV1Module(): try: rubric_data = task._parse_score_msg(task.child_history[-1].get('post_assessment', ""), self.system) except: + log.debug("Could not parse rubric data from child history. " + "Likely we have not yet initialized a previous step, so this is perfectly fine.") rubric_data = {} rubric_scores = rubric_data.get('rubric_scores') grader_types = rubric_data.get('grader_types') From b1ea6b2012f517d006fcd41bffd7edeaf130f55e Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 16 Apr 2013 10:58:58 -0400 Subject: [PATCH 24/31] Add in comments about max score calculation --- .../open_ended_grading_classes/combined_open_ended_modulev1.py | 3 +++ 1 file changed, 3 insertions(+) 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 e79ab4c25e..f1f2f04c61 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 @@ -739,10 +739,13 @@ class CombinedOpenEndedV1Module(): max_score = None score = None if self.check_if_done_and_scored(): + #Finds the maximum score of all student attempts and keeps it. scores = [] for i in xrange(0, self.current_task_number): last_response = self.get_last_response(i) try: + #This could fail if weight is not defined (is None), or if the last response does not have the needed data. + #Neither is a critical issue, and that particular task score can be skipped for computation. max_score = last_response['max_score'] * float(self.weight) score = last_response['score'] * float(self.weight) scores.append(score) From 338a57768fd4e759a0286c4bcd9260d4eec8ad9f Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 16 Apr 2013 11:01:57 -0400 Subject: [PATCH 25/31] Remove try except block for pg scoring --- common/lib/xmodule/xmodule/peer_grading_module.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py index de4922e60a..fc007475dc 100644 --- a/common/lib/xmodule/xmodule/peer_grading_module.py +++ b/common/lib/xmodule/xmodule/peer_grading_module.py @@ -205,13 +205,11 @@ class PeerGradingModule(PeerGradingFields, XModule): #Ensures that once a student receives a final score for peer grading, that it does not change. self.student_data_for_location = response - try: + if self.weight is not None: score = int(count_graded >= count_required and count_graded > 0) * float(self.weight) total = self.max_grade * float(self.weight) score_dict['score'] = score score_dict['total'] = total - except: - pass return score_dict From 2f6b7d1e443341216b798a55fc8c6713f200c902 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 16 Apr 2013 11:41:35 -0400 Subject: [PATCH 26/31] Better max score handling --- .../combined_open_ended_modulev1.py | 42 +++++++++++++------ .../openendedchild.py | 6 +++ 2 files changed, 36 insertions(+), 12 deletions(-) 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 f1f2f04c61..d586478fa1 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 @@ -403,6 +403,7 @@ class CombinedOpenEndedV1Module(): self.static_data, instance_state=task_state) last_response = task.latest_answer() last_score = task.latest_score() + all_scores = task.all_scores() last_post_assessment = task.latest_post_assessment(self.system) last_post_feedback = "" feedback_dicts = [{}] @@ -460,6 +461,7 @@ class CombinedOpenEndedV1Module(): last_response_dict = { 'response': last_response, 'score': last_score, + 'all_scores' : all_scores, 'post_assessment': last_post_assessment, 'type': task_type, 'max_score': max_score, @@ -738,21 +740,37 @@ class CombinedOpenEndedV1Module(): """ max_score = None score = None - if self.check_if_done_and_scored(): + if self.is_scored and self.weight is not None: #Finds the maximum score of all student attempts and keeps it. - scores = [] - for i in xrange(0, self.current_task_number): + score_mat = [] + for i in xrange(0, len(self.task_states)): + #For each task, extract all student scores on that task (each attempt for each task) last_response = self.get_last_response(i) - try: - #This could fail if weight is not defined (is None), or if the last response does not have the needed data. - #Neither is a critical issue, and that particular task score can be skipped for computation. - max_score = last_response['max_score'] * float(self.weight) - score = last_response['score'] * float(self.weight) - scores.append(score) - except: - pass - if len(scores) > 0: + max_score = last_response.get('max_score', None) + score = last_response.get('all_scores', None) + if score is not None: + #Convert none scores and weight scores properly + for z in xrange(0,len(score)): + if score[z] is None: + score[z] = 0 + score[z] *= float(self.weight) + score_mat.append(score) + + if len(score_mat) > 0: + #Currently, assume that the final step is the correct one, and that those are the final scores. + #This will change in the future, which is why the machinery above exists to extract all scores on all steps + #TODO: better final score handling. + scores = score_mat[-1] score = max(scores) + else: + score = 0 + + if max_score is not None: + #Weight the max score if it is not None + max_score *= float(self.weight) + else: + #Without a max_score, we cannot have a score! + score = None score_dict = { 'score': score, diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py index b9341f0cbe..351acb0918 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py @@ -162,6 +162,12 @@ class OpenEndedChild(object): return None return self.child_history[-1].get('score') + def all_scores(self): + """None if not available""" + if not self.child_history: + return None + return [self.child_history[i].get('score') for i in xrange(0,len(self.child_history))] + def latest_post_assessment(self, system): """Empty string if not available""" if not self.child_history: From 65e251433426692bb7981a9bbcacdfd7fbaee91f Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 16 Apr 2013 11:45:57 -0400 Subject: [PATCH 27/31] Convert some exception clauses --- .../combined_open_ended_modulev1.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 d586478fa1..f0d84a2cc3 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 @@ -145,7 +145,7 @@ class CombinedOpenEndedV1Module(): grace_period_string = self.instance_state.get('graceperiod', None) try: self.timeinfo = TimeInfo(due_date, grace_period_string) - except: + except Exception: log.error("Error parsing due date information in location {0}".format(location)) raise self.display_due_date = self.timeinfo.display_due_date @@ -363,7 +363,7 @@ class CombinedOpenEndedV1Module(): # if link.startswith(XASSET_SRCREF_PREFIX): # Placing try except so that if the error is fixed, this code will start working again. return_html = rewrite_links(html, self.rewrite_content_links) - except: + except Exception: pass return return_html @@ -421,7 +421,7 @@ class CombinedOpenEndedV1Module(): last_post_assessment = last_post_evaluation try: rubric_data = task._parse_score_msg(task.child_history[-1].get('post_assessment', ""), self.system) - except: + except Exception: log.debug("Could not parse rubric data from child history. " "Likely we have not yet initialized a previous step, so this is perfectly fine.") rubric_data = {} From 701bdc55c043f4efbd2b62a20f115aac2a47aae5 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 16 Apr 2013 11:55:54 -0400 Subject: [PATCH 28/31] Minor fixes --- common/lib/xmodule/xmodule/peer_grading_module.py | 5 ++--- lms/djangoapps/open_ended_grading/staff_grading_service.py | 2 ++ lms/templates/peer_grading/peer_grading_problem.html | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py index fc007475dc..db4514d0e0 100644 --- a/common/lib/xmodule/xmodule/peer_grading_module.py +++ b/common/lib/xmodule/xmodule/peer_grading_module.py @@ -392,8 +392,7 @@ class PeerGradingModule(PeerGradingFields, XModule): # if we can't parse the rubric into HTML, except etree.XMLSyntaxError: #This is a dev_facing_error - log.exception("Cannot parse rubric string. Raw string: {0}" - .format("")) + log.exception("Cannot parse rubric string.") #This is a student_facing_error return {'success': False, 'error': 'Error displaying submission. Please notify course staff.'} @@ -440,7 +439,7 @@ class PeerGradingModule(PeerGradingFields, XModule): except GradingServiceError: #This is a dev_facing_error log.exception( - "Error saving calibration grade, location: {0}, submission_id: {1}, submission_key: {2}, grader_id: {3}".format( + "Error saving calibration grade, location: {0}, submission_key: {1}, grader_id: {2}".format( location, submission_key, grader_id)) #This is a student_facing_error return self._err_response('There was an error saving your score. Please notify course staff.') diff --git a/lms/djangoapps/open_ended_grading/staff_grading_service.py b/lms/djangoapps/open_ended_grading/staff_grading_service.py index 885f6bbfa1..2c611b4481 100644 --- a/lms/djangoapps/open_ended_grading/staff_grading_service.py +++ b/lms/djangoapps/open_ended_grading/staff_grading_service.py @@ -313,6 +313,8 @@ def save_grade(request, course_id): p = request.POST required = set(['score', 'feedback', 'submission_id', 'location', 'submission_flagged']) skipped = 'skipped' in p + #If the instructor has skipped grading the submission, then there will not be any rubric scores. + #Only add in the rubric scores if the instructor has not skipped. if not skipped: required|=set(['rubric_scores[]']) actual = set(p.keys()) diff --git a/lms/templates/peer_grading/peer_grading_problem.html b/lms/templates/peer_grading/peer_grading_problem.html index b4b900b874..5ad3136815 100644 --- a/lms/templates/peer_grading/peer_grading_problem.html +++ b/lms/templates/peer_grading/peer_grading_problem.html @@ -86,7 +86,7 @@

Are you sure that you want to flag this submission?

- Please only flag explicit or pornographic content. Click the button below if you understand this and still want to flag the submission. + You are about to flag a submission. You should only flag a submission that contains explicit or offensive content. If the submission is not addressed to the question or is incorrect, you should give it a score of zero and accompanying feedback instead of flagging it.

From 36317b7d29db1c32b0100663006ecf50880b7e97 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 16 Apr 2013 11:59:03 -0400 Subject: [PATCH 29/31] Fix failing test --- common/lib/xmodule/xmodule/tests/test_combined_open_ended.py | 4 ++-- 1 file changed, 2 insertions(+), 2 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 212da3cca7..0c8601d8ac 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -413,8 +413,8 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): def test_get_score(self): score_dict = self.combinedoe.get_score() - self.assertEqual(score_dict['score'], None) - self.assertEqual(score_dict['total'], None) + self.assertEqual(score_dict['score'], 0) + self.assertEqual(score_dict['total'], 1) def test_alternate_orderings(self): t1 = self.task_xml1 From a71658cf7734dba69af1ddd5235c3fc95b7ee8d8 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 16 Apr 2013 12:12:12 -0400 Subject: [PATCH 30/31] Better test for get score --- .../xmodule/tests/test_combined_open_ended.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) 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 0c8601d8ac..e7a9beea33 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -361,6 +361,7 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): descriptor, model_data={'data': full_definition, 'weight' : '1'}) + def setUp(self): # TODO: this constructor call is definitely wrong, but neither branch # of the merge matches the module constructor. Someone (Vik?) should fix this. @@ -434,6 +435,35 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): changed = combinedoe.update_task_states() self.assertFalse(changed) + def test_get_score_realistic(self): + instance_state = r"""{"ready_to_reset": false, "skip_spelling_checks": true, "current_task_number": 1, "weight": 5.0, "graceperiod": "1 day 12 hours 59 minutes 59 seconds", "is_graded": "True", "task_states": ["{\"child_created\": false, \"child_attempts\": 4, \"version\": 1, \"child_history\": [{\"answer\": \"The students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the group\\u2019s procedure, describe what additional information you would need in order to replicate the expe\", \"post_assessment\": \"{\\\"submission_id\\\": 3097, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: More grammar errors than average.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"the students data are recorded in the table below . starting mass g ending mass g difference in mass g marble . . . limestone . . . wood . . . plastic . . . after reading the groups procedure , describe what additional information you would need in order to replicate the expe\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3233, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"After 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"To replicate the experiment, the procedure would require more detail. One piece of information that is omitted is the amount of vinegar used in the experiment. It is also important to know what temperature the experiment was kept at during the 24 hours. Finally, the procedure needs to include details about the experiment, for example if the whole sample must be submerged.\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"e the mass of four different samples.\\r\\nPour vinegar in each of four separate, but identical, containers.\\r\\nPlace a sample of one material into one container and label. Repeat with remaining samples, placing a single sample into a single container.\\r\\nAfter 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"\", \"post_assessment\": \"[3]\", \"score\": 3}], \"max_score\": 3, \"child_state\": \"done\"}", "{\"child_created\": false, \"child_attempts\": 0, \"version\": 1, \"child_history\": [{\"answer\": \"The students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the group\\u2019s procedure, describe what additional information you would need in order to replicate the expe\", \"post_assessment\": \"{\\\"submission_id\\\": 3097, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: More grammar errors than average.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"the students data are recorded in the table below . starting mass g ending mass g difference in mass g marble . . . limestone . . . wood . . . plastic . . . after reading the groups procedure , describe what additional information you would need in order to replicate the expe\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3233, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"After 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the\", \"post_assessment\": \"{\\\"submission_id\\\": 3098, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"after hours , remove the samples from the containers and rinse each sample with distilled water . allow the samples to sit and dry for minutes . determine the mass of each sample . the students data are recorded in the table below . starting mass g ending mass g difference in mass g marble . . . limestone . . . wood . . . plastic . . . after reading the\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3235, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"To replicate the experiment, the procedure would require more detail. One piece of information that is omitted is the amount of vinegar used in the experiment. It is also important to know what temperature the experiment was kept at during the 24 hours. Finally, the procedure needs to include details about the experiment, for example if the whole sample must be submerged.\", \"post_assessment\": \"{\\\"submission_id\\\": 3099, \\\"score\\\": 3, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"to replicate the experiment , the procedure would require more detail . one piece of information that is omitted is the amount of vinegar used in the experiment . it is also important to know what temperature the experiment was kept at during the hours . finally , the procedure needs to include details about the experiment , for example if the whole sample must be submerged .\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3237, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality3\\\"}\", \"score\": 3}, {\"answer\": \"e the mass of four different samples.\\r\\nPour vinegar in each of four separate, but identical, containers.\\r\\nPlace a sample of one material into one container and label. Repeat with remaining samples, placing a single sample into a single container.\\r\\nAfter 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\", \"post_assessment\": \"{\\\"submission_id\\\": 3100, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"e the mass of four different samples . pour vinegar in each of four separate , but identical , containers . place a sample of one material into one container and label . repeat with remaining samples , placing a single sample into a single container . after hours , remove the samples from the containers and rinse each sample with distilled water . allow the samples to sit and dry for minutes . determine the mass of each sample . the students data are recorded in the table below . \\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3239, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"\", \"post_assessment\": \"{\\\"submission_id\\\": 3101, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"invalid essay .\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3241, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}], \"max_score\": 3, \"child_state\": \"done\"}"], "attempts": "10000", "student_attempts": 0, "due": null, "state": "done", "accept_file_upload": false, "display_name": "Science Question -- Machine Assessed"}""" + instance_state = json.loads(instance_state) + rubric = """ + + + + Response Quality + + + + + + + + """ + definition = {'prompt': etree.XML(self.prompt), 'rubric': etree.XML(rubric), 'task_xml': [self.task_xml1, self.task_xml2]} + descriptor = Mock(data=definition) + combinedoe = CombinedOpenEndedV1Module(self.test_system, + self.location, + definition, + descriptor, + static_data=self.static_data, + metadata=self.metadata, + instance_state=instance_state) + score_dict = combinedoe.get_score() + self.assertEqual(score_dict['score'], 15.0) + self.assertEqual(score_dict['total'], 15.0) + From 5125d8b0deff07c13ce40889fdb2b15815a255bb Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 16 Apr 2013 13:48:58 -0400 Subject: [PATCH 31/31] Reformat code --- .../xmodule/combined_open_ended_module.py | 8 +++--- .../combined_open_ended_modulev1.py | 4 +-- .../openendedchild.py | 9 +++--- .../self_assessment_module.py | 2 +- .../xmodule/tests/test_combined_open_ended.py | 28 ++++++++++--------- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index db003b8ad2..120e4f743a 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -106,10 +106,10 @@ class CombinedOpenEndedModule(CombinedOpenEndedFields, XModule): icon_class = 'problem' js = {'coffee': - [resource_string(__name__, 'js/src/combinedopenended/display.coffee'), - resource_string(__name__, 'js/src/collapsible.coffee'), - resource_string(__name__, 'js/src/javascript_loader.coffee'), - ]} + [resource_string(__name__, 'js/src/combinedopenended/display.coffee'), + resource_string(__name__, 'js/src/collapsible.coffee'), + resource_string(__name__, 'js/src/javascript_loader.coffee'), + ]} js_module_name = "CombinedOpenEnded" css = {'scss': [resource_string(__name__, 'css/combinedopenended/display.scss')]} 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 f0d84a2cc3..12f90ed1b3 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 @@ -461,7 +461,7 @@ class CombinedOpenEndedV1Module(): last_response_dict = { 'response': last_response, 'score': last_score, - 'all_scores' : all_scores, + 'all_scores': all_scores, 'post_assessment': last_post_assessment, 'type': task_type, 'max_score': max_score, @@ -750,7 +750,7 @@ class CombinedOpenEndedV1Module(): score = last_response.get('all_scores', None) if score is not None: #Convert none scores and weight scores properly - for z in xrange(0,len(score)): + for z in xrange(0, len(score)): if score[z] is None: score[z] = 0 score[z] *= float(self.weight) diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py index 351acb0918..d5889636ed 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py @@ -72,7 +72,8 @@ class OpenEndedChild(object): try: instance_state = json.loads(instance_state) except: - log.error("Could not load instance state for open ended. Setting it to nothing.: {0}".format(instance_state)) + log.error( + "Could not load instance state for open ended. Setting it to nothing.: {0}".format(instance_state)) else: instance_state = {} @@ -81,8 +82,8 @@ class OpenEndedChild(object): # element. # Scores are on scale from 0 to max_score - self.child_history=instance_state.get('child_history',[]) - self.child_state=instance_state.get('child_state', self.INITIAL) + self.child_history = instance_state.get('child_history', []) + self.child_state = instance_state.get('child_state', self.INITIAL) self.child_created = instance_state.get('child_created', False) self.child_attempts = instance_state.get('child_attempts', 0) @@ -166,7 +167,7 @@ class OpenEndedChild(object): """None if not available""" if not self.child_history: return None - return [self.child_history[i].get('score') for i in xrange(0,len(self.child_history))] + return [self.child_history[i].get('score') for i in xrange(0, len(self.child_history))] def latest_post_assessment(self, system): """Empty string if not available""" diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py index 5fb901d49c..497d2f6eed 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py @@ -291,7 +291,7 @@ class SelfAssessmentDescriptor(): template_dir_name = "selfassessment" def __init__(self, system): - self.system =system + self.system = system @classmethod def definition_from_xml(cls, xml_object, system): 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 e7a9beea33..59f0e222ee 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -323,7 +323,7 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): 's3_interface': test_util_open_ended.S3_INTERFACE, 'open_ended_grading_interface': test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE, 'skip_basic_checks': False, - 'is_graded' : True, + 'is_graded': True, } oeparam = etree.XML(''' @@ -359,7 +359,7 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): combinedoe_container = CombinedOpenEndedModule(test_system, location, descriptor, - model_data={'data': full_definition, 'weight' : '1'}) + model_data={'data': full_definition, 'weight': '1'}) def setUp(self): @@ -372,6 +372,7 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): static_data=self.static_data, metadata=self.metadata, instance_state=self.static_data) + def test_get_tag_name(self): name = self.combinedoe.get_tag_name("Tag") self.assertEqual(name, "t") @@ -406,11 +407,11 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): def test_container_weight(self): weight = self.combinedoe_container.weight - self.assertEqual(weight,1) + self.assertEqual(weight, 1) def test_container_child_weight(self): weight = self.combinedoe_container.child_module.weight - self.assertEqual(weight,1) + self.assertEqual(weight, 1) def test_get_score(self): score_dict = self.combinedoe.get_score() @@ -420,23 +421,23 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): def test_alternate_orderings(self): t1 = self.task_xml1 t2 = self.task_xml2 - xml_to_test = [[t1], [t2], [t1,t1], [t1,t2], [t2,t2], [t2,t1], [t1,t2,t1]] + xml_to_test = [[t1], [t2], [t1, t1], [t1, t2], [t2, t2], [t2, t1], [t1, t2, t1]] for xml in xml_to_test: definition = {'prompt': etree.XML(self.prompt), 'rubric': etree.XML(self.rubric), 'task_xml': xml} descriptor = Mock(data=definition) combinedoe = CombinedOpenEndedV1Module(self.test_system, - self.location, - definition, - descriptor, - static_data=self.static_data, - metadata=self.metadata, - instance_state=self.static_data) + self.location, + definition, + descriptor, + static_data=self.static_data, + metadata=self.metadata, + instance_state=self.static_data) changed = combinedoe.update_task_states() self.assertFalse(changed) def test_get_score_realistic(self): - instance_state = r"""{"ready_to_reset": false, "skip_spelling_checks": true, "current_task_number": 1, "weight": 5.0, "graceperiod": "1 day 12 hours 59 minutes 59 seconds", "is_graded": "True", "task_states": ["{\"child_created\": false, \"child_attempts\": 4, \"version\": 1, \"child_history\": [{\"answer\": \"The students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the group\\u2019s procedure, describe what additional information you would need in order to replicate the expe\", \"post_assessment\": \"{\\\"submission_id\\\": 3097, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: More grammar errors than average.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"the students data are recorded in the table below . starting mass g ending mass g difference in mass g marble . . . limestone . . . wood . . . plastic . . . after reading the groups procedure , describe what additional information you would need in order to replicate the expe\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3233, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"After 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"To replicate the experiment, the procedure would require more detail. One piece of information that is omitted is the amount of vinegar used in the experiment. It is also important to know what temperature the experiment was kept at during the 24 hours. Finally, the procedure needs to include details about the experiment, for example if the whole sample must be submerged.\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"e the mass of four different samples.\\r\\nPour vinegar in each of four separate, but identical, containers.\\r\\nPlace a sample of one material into one container and label. Repeat with remaining samples, placing a single sample into a single container.\\r\\nAfter 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"\", \"post_assessment\": \"[3]\", \"score\": 3}], \"max_score\": 3, \"child_state\": \"done\"}", "{\"child_created\": false, \"child_attempts\": 0, \"version\": 1, \"child_history\": [{\"answer\": \"The students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the group\\u2019s procedure, describe what additional information you would need in order to replicate the expe\", \"post_assessment\": \"{\\\"submission_id\\\": 3097, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: More grammar errors than average.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"the students data are recorded in the table below . starting mass g ending mass g difference in mass g marble . . . limestone . . . wood . . . plastic . . . after reading the groups procedure , describe what additional information you would need in order to replicate the expe\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3233, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"After 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the\", \"post_assessment\": \"{\\\"submission_id\\\": 3098, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"after hours , remove the samples from the containers and rinse each sample with distilled water . allow the samples to sit and dry for minutes . determine the mass of each sample . the students data are recorded in the table below . starting mass g ending mass g difference in mass g marble . . . limestone . . . wood . . . plastic . . . after reading the\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3235, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"To replicate the experiment, the procedure would require more detail. One piece of information that is omitted is the amount of vinegar used in the experiment. It is also important to know what temperature the experiment was kept at during the 24 hours. Finally, the procedure needs to include details about the experiment, for example if the whole sample must be submerged.\", \"post_assessment\": \"{\\\"submission_id\\\": 3099, \\\"score\\\": 3, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"to replicate the experiment , the procedure would require more detail . one piece of information that is omitted is the amount of vinegar used in the experiment . it is also important to know what temperature the experiment was kept at during the hours . finally , the procedure needs to include details about the experiment , for example if the whole sample must be submerged .\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3237, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality3\\\"}\", \"score\": 3}, {\"answer\": \"e the mass of four different samples.\\r\\nPour vinegar in each of four separate, but identical, containers.\\r\\nPlace a sample of one material into one container and label. Repeat with remaining samples, placing a single sample into a single container.\\r\\nAfter 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\", \"post_assessment\": \"{\\\"submission_id\\\": 3100, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"e the mass of four different samples . pour vinegar in each of four separate , but identical , containers . place a sample of one material into one container and label . repeat with remaining samples , placing a single sample into a single container . after hours , remove the samples from the containers and rinse each sample with distilled water . allow the samples to sit and dry for minutes . determine the mass of each sample . the students data are recorded in the table below . \\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3239, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"\", \"post_assessment\": \"{\\\"submission_id\\\": 3101, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"invalid essay .\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3241, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}], \"max_score\": 3, \"child_state\": \"done\"}"], "attempts": "10000", "student_attempts": 0, "due": null, "state": "done", "accept_file_upload": false, "display_name": "Science Question -- Machine Assessed"}""" + instance_state = r"""{"ready_to_reset": false, "skip_spelling_checks": true, "current_task_number": 1, "weight": 5.0, "graceperiod": "1 day 12 hours 59 minutes 59 seconds", "is_graded": "True", "task_states": ["{\"child_created\": false, \"child_attempts\": 4, \"version\": 1, \"child_history\": [{\"answer\": \"The students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the group\\u2019s procedure, describe what additional information you would need in order to replicate the expe\", \"post_assessment\": \"{\\\"submission_id\\\": 3097, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: More grammar errors than average.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"the students data are recorded in the table below . starting mass g ending mass g difference in mass g marble . . . limestone . . . wood . . . plastic . . . after reading the groups procedure , describe what additional information you would need in order to replicate the expe\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3233, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"After 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"To replicate the experiment, the procedure would require more detail. One piece of information that is omitted is the amount of vinegar used in the experiment. It is also important to know what temperature the experiment was kept at during the 24 hours. Finally, the procedure needs to include details about the experiment, for example if the whole sample must be submerged.\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"e the mass of four different samples.\\r\\nPour vinegar in each of four separate, but identical, containers.\\r\\nPlace a sample of one material into one container and label. Repeat with remaining samples, placing a single sample into a single container.\\r\\nAfter 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"\", \"post_assessment\": \"[3]\", \"score\": 3}], \"max_score\": 3, \"child_state\": \"done\"}", "{\"child_created\": false, \"child_attempts\": 0, \"version\": 1, \"child_history\": [{\"answer\": \"The students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the group\\u2019s procedure, describe what additional information you would need in order to replicate the expe\", \"post_assessment\": \"{\\\"submission_id\\\": 3097, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: More grammar errors than average.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"the students data are recorded in the table below . starting mass g ending mass g difference in mass g marble . . . limestone . . . wood . . . plastic . . . after reading the groups procedure , describe what additional information you would need in order to replicate the expe\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3233, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"After 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the\", \"post_assessment\": \"{\\\"submission_id\\\": 3098, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"after hours , remove the samples from the containers and rinse each sample with distilled water . allow the samples to sit and dry for minutes . determine the mass of each sample . the students data are recorded in the table below . starting mass g ending mass g difference in mass g marble . . . limestone . . . wood . . . plastic . . . after reading the\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3235, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"To replicate the experiment, the procedure would require more detail. One piece of information that is omitted is the amount of vinegar used in the experiment. It is also important to know what temperature the experiment was kept at during the 24 hours. Finally, the procedure needs to include details about the experiment, for example if the whole sample must be submerged.\", \"post_assessment\": \"{\\\"submission_id\\\": 3099, \\\"score\\\": 3, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"to replicate the experiment , the procedure would require more detail . one piece of information that is omitted is the amount of vinegar used in the experiment . it is also important to know what temperature the experiment was kept at during the hours . finally , the procedure needs to include details about the experiment , for example if the whole sample must be submerged .\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3237, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality3\\\"}\", \"score\": 3}, {\"answer\": \"e the mass of four different samples.\\r\\nPour vinegar in each of four separate, but identical, containers.\\r\\nPlace a sample of one material into one container and label. Repeat with remaining samples, placing a single sample into a single container.\\r\\nAfter 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\", \"post_assessment\": \"{\\\"submission_id\\\": 3100, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"e the mass of four different samples . pour vinegar in each of four separate , but identical , containers . place a sample of one material into one container and label . repeat with remaining samples , placing a single sample into a single container . after hours , remove the samples from the containers and rinse each sample with distilled water . allow the samples to sit and dry for minutes . determine the mass of each sample . the students data are recorded in the table below . \\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3239, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}, {\"answer\": \"\", \"post_assessment\": \"{\\\"submission_id\\\": 3101, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"invalid essay .\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3241, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"Response Quality0\\\"}\", \"score\": 0}], \"max_score\": 3, \"child_state\": \"done\"}"], "attempts": "10000", "student_attempts": 0, "due": null, "state": "done", "accept_file_upload": false, "display_name": "Science Question -- Machine Assessed"}""" instance_state = json.loads(instance_state) rubric = """ @@ -451,7 +452,8 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): """ - definition = {'prompt': etree.XML(self.prompt), 'rubric': etree.XML(rubric), 'task_xml': [self.task_xml1, self.task_xml2]} + definition = {'prompt': etree.XML(self.prompt), 'rubric': etree.XML(rubric), + 'task_xml': [self.task_xml1, self.task_xml2]} descriptor = Mock(data=definition) combinedoe = CombinedOpenEndedV1Module(self.test_system, self.location,