Example #1
0
def finalize_expired_submission(sub):
    """
    Expire submissions by posting back to LMS with error message.
    Input:
        timed_out_list from check_if_expired method
    Output:
        Success code.
    """

    grader_dict = {
        'score': 0,
        'feedback': error_template.format(errors="Error scoring submission."),
        'status': GraderStatus.failure,
        'grader_id': "0",
        'grader_type': sub.next_grader_type,
        'confidence': 1,
        'submission_id' : sub.id,
        }

    sub.state = SubmissionState.finished
    sub.save()

    grade = create_grader(grader_dict,sub)

    statsd.increment("open_ended_assessment.grading_controller.expire_submissions.finalize_expired_submission",
                     tags=[
                         "course:{0}".format(sub.course_id),
                         "location:{0}".format(sub.location),
                         'grader_type:{0}'.format(sub.next_grader_type)
                     ])

    return True
Example #2
0
def create_and_handle_grader_object(grader_dict):
    """
    Creates a Grader object and associates it with a given submission
    Input is grader dictionary with keys:
     feedback, status, grader_id, grader_type, confidence, score,submission_id, errors
        Feedback should be a dictionary with as many keys as needed.
        Errors is a string containing errors.
    """
    for tag in ["feedback", "status", "grader_id", "grader_type", "confidence", "score", "submission_id", "errors"]:
        if tag not in grader_dict:
            return False, "{0} tag not in input dictionary.".format(tag)

    try:
        sub = Submission.objects.get(id=int(grader_dict['submission_id']))
    except:
        return False, "Error getting submission."

    try:
        grader_dict['feedback'] = json.loads(grader_dict['feedback'])
    except:
        pass

    if not isinstance(grader_dict['feedback'], dict):
        grader_dict['feedback'] = {'feedback': grader_dict['feedback']}

    for k in grader_dict['feedback']:
        grader_dict['feedback'][k] = util.sanitize_html(grader_dict['feedback'][k])

    if grader_dict['status'] == GraderStatus.failure:
        grader_dict['feedback'] = ' '.join(grader_dict['errors'])

    grader_dict['feedback'] = json.dumps(grader_dict['feedback'])

    grade = create_grader(grader_dict, sub)

    #Check to see if rubric scores were passed to the function, and handle if so.
    if 'rubric_scores_complete' in grader_dict and 'rubric_scores' in grader_dict:
        try:
            grader_dict['rubric_scores']=json.loads(grader_dict['rubric_scores'])
        except:
            pass

        if grader_dict['rubric_scores_complete'] in ['True', "TRUE", 'true', True]:
            grader_dict['rubric_scores']=[int(r) for r in grader_dict['rubric_scores']]
            try:
                rubric_functions.generate_rubric_object(grade,grader_dict['rubric_scores'], sub.rubric)
            except:
                log.exception("Problem with getting rubric scores from dict : {0}".format(grader_dict))

    #TODO: Need some kind of logic somewhere else to handle setting next_grader

    sub.previous_grader_type = grade.grader_type
    sub.next_grader_type = grade.grader_type

    #check to see if submission is flagged.  If so, put it in a flagged state
    submission_is_flagged = grader_dict.get('is_submission_flagged', False)
    if submission_is_flagged:
        sub.state = SubmissionState.flagged
    else:
        #TODO: Some kind of logic to decide when sub is finished grading.

        #If we are calling this after a basic check and the score is 0, that means that the submission is bad, so mark as finished
        if(grade.status_code == GraderStatus.success and grade.grader_type in ["BC"] and grade.score==0):
            sub.state = SubmissionState.finished
        #If submission is ML or IN graded, and was successful, state is finished
        elif(grade.status_code == GraderStatus.success and grade.grader_type in ["IN", "ML"]):
            sub.state = SubmissionState.finished
        elif(grade.status_code == GraderStatus.success and grade.grader_type in ["PE"]):
            #If grading type is Peer, and was successful, check to see how many other times peer grading has succeeded.
            successful_peer_grader_count = sub.get_successful_peer_graders().count()
            #If number of successful peer graders equals the needed count, finalize submission.
            if successful_peer_grader_count >= settings.PEER_GRADER_COUNT:
                sub.state = SubmissionState.finished
            else:
                sub.state = SubmissionState.waiting_to_be_graded
        #If something fails, immediately mark it for regrading
        #TODO: Get better logic for handling failure cases
        elif(grade.status_code == GraderStatus.failure and sub.state == SubmissionState.being_graded):
            number_of_failures = sub.get_unsuccessful_graders().count()
            #If it has failed too many times, just return an error
            if number_of_failures > settings.MAX_NUMBER_OF_TIMES_TO_RETRY_GRADING:
                finalize_expired_submission(sub)
            else:
                sub.state = SubmissionState.waiting_to_be_graded

    #Increment statsd whenever a grader object is saved.
    statsd.increment("open_ended_assessment.grading_controller.controller.create_grader_object",
        tags=["submission_state:{0}".format(sub.state),
              "grader_type:{0}".format(grade.grader_type),
              "grader_status:{0}".format(grade.status_code),
              "location:{0}".format(sub.location),
              "course_id:{0}".format(sub.course_id),
              "next_grader_type:{0}".format(sub.next_grader_type),
              "score:{0}".format(grade.score),
        ]
    )

    sub.save()

    #Insert timing finalization code
    finalize_timing(sub, grade)

    return True, {'submission_id': sub.xqueue_submission_id, 'submission_key': sub.xqueue_submission_key}