Esempio n. 1
0
def instructor_grading_list_submissions(ctx, course, assignment_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(course, assignment)
    teams = sorted(teams_registrations.keys(), key=operator.attrgetter("team_id"))

    conn = create_connection(course, ctx.obj['config'])
    
    if conn is None:
        print "Could not connect to git server."
        ctx.exit(CHISUBMIT_FAIL)

    for team in teams:
        registration = teams_registrations[team]

        if registration.final_submission is None:
            print "%25s NOT SUBMITTED" % team.team_id
        else:
            submission_commit = conn.get_commit(course, team, registration.final_submission.commit_sha)
            if submission_commit is not None:
                if registration.is_ready_for_grading():
                    print "%25s SUBMITTED (READY for grading)" % team.team_id
                else:
                    print "%25s SUBMITTED (NOT READY for grading)" % team.team_id
            else:
                print "%25s ERROR: Submitted but commit %s not found in repository" % (team.team_id, registration.final_submission.commit_sha)
    
    return CHISUBMIT_SUCCESS
Esempio n. 2
0
def instructor_grading_push_grading(ctx, course, assignment_id, to_students, all_teams, only, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    if to_students:
        print "You are going to push the grading branches to the student repositories."
        print "If you do so, students will be able to see their grading!"
        print 
        print "Are you sure you want to continue? (y/n): ", 
        
        if not yes:
            yesno = raw_input()
        else:
            yesno = 'y'
            print 'y'
            
        if yesno not in ('y', 'Y', 'yes', 'Yes', 'YES'):
            ctx.exit(CHISUBMIT_FAIL)
        print
    else:
        print "Pushing grading to staging repositories. Only instructors and graders will"
        print "be able to access this grading. If you want to push the grading to the"
        print "student repositories, use the --to-students option"
        print         
    
    teams_registrations = get_teams_registrations(course, assignment, only = only, only_ready_for_grading=not all_teams)
    teams = sorted(teams_registrations.keys(), key=operator.attrgetter("team_id"))

    for team in teams:
        registration = teams_registrations[team]
        print ("Pushing grading branch for team %s... " % team.team_id),
        gradingrepo_push_grading_branch(ctx.obj['config'], course, team, registration, to_students = to_students)
        print "done."

    return CHISUBMIT_SUCCESS
Esempio n. 3
0
def grader_push_grading(ctx, course, assignment_id, grader, only, skip_rubric_validation):
    if grader is None:
        user = ctx.obj["client"].get_user()    
        
        grader = get_grader_or_exit(ctx, course, user.username)
    else:
        grader = get_grader_or_exit(ctx, course, grader)

    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(course, assignment, grader = grader, only = only, only_ready_for_grading=True)
    
    if len(teams_registrations) == 0:
        print "No teams found"
        ctx.exit(CHISUBMIT_FAIL)

    for team, registration in teams_registrations.items():
        if not skip_rubric_validation:
            valid, error_msg = validate_repo_rubric(ctx, course, assignment, team, registration)
            if not valid:
                print "Not pushing branch for team %s. Rubric does not validate: %s" % (team.team_id, error_msg)
                continue
        
        print "Pushing grading branch for team %s... " % team.team_id
        gradingrepo_push_grading_branch(ctx.obj['config'], course, team, registration)

    return CHISUBMIT_SUCCESS
Esempio n. 4
0
def instructor_grading_pull_grading(ctx, course, assignment_id, from_students, only, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
    
    if from_students:
        print "Pulling grading from the student repositories is an uncommon operation."
        print "Instead, you should only ever make changes to the grading in the staging"
        print "repositories, and push those changes to the student repositories (which"
        print "should always mirror what is in the staging repositories). So, there should"
        print "never be a need to pull grading from a student repository."
        print 
        print "Are you sure you want to continue and pull the grading from"
        print "the student repositories? (y/n): ", 
        
        if not yes:
            yesno = raw_input()
        else:
            yesno = 'y'
            print 'y'
            
        if yesno not in ('y', 'Y', 'yes', 'Yes', 'YES'):
            ctx.exit(CHISUBMIT_FAIL)    
    
    teams_registrations = get_teams_registrations(course, assignment, only = only)
    teams = sorted(teams_registrations.keys(), key=operator.attrgetter("team_id"))

    for team in teams:
        registration = teams_registrations[team]
        print "Pulling grading branch for team %s... " % team.team_id
        gradingrepo_pull_grading_branch(ctx.obj['config'], course, team, registration, from_students = from_students)

    return CHISUBMIT_SUCCESS
Esempio n. 5
0
def instructor_grading_list_grader_assignments(ctx, course, assignment_id, grader_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    if grader_id is not None:
        grader = get_grader_or_exit(ctx, course, grader_id)
    else:
        grader = None

    teams_registrations = get_teams_registrations(course, assignment)
    
    teams = teams_registrations.keys()
    teams.sort(key=operator.attrgetter("team_id"))

    for t in teams:
        registration = teams_registrations[t]
        if grader is None:
            if registration.grader is None:
                grader_str = "<no-grader-assigned>"
            else:
                grader_str = registration.grader.user.username
            print t.team_id, grader_str
        else:
            if grader == registration.grader.user.username:
                print t.team_id

    return CHISUBMIT_SUCCESS
Esempio n. 6
0
def grader_validate_rubrics(ctx, course, assignment_id, grader, only):
    if grader is None:
        user = ctx.obj["client"].get_user()    
        
        grader = get_grader_or_exit(ctx, course, user.username)
    else:
        grader = get_grader_or_exit(ctx, course, grader)

    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(course, assignment, grader = grader, only = only)
    
    all_valid = True
    for team, registration in teams_registrations.items():
        valid, error_msg = validate_repo_rubric(ctx, course, assignment, team, registration)

        if valid:
            print "%s: Rubric OK." % team.team_id
        else:
            print "%s: Rubric ERROR: %s" % (team.team_id, error_msg)
            all_valid = False
            
    if not all_valid:
        ctx.exit(CHISUBMIT_FAIL)
    else:
        return CHISUBMIT_SUCCESS
Esempio n. 7
0
def grader_push_grading(ctx, course, assignment_id, grader, only, skip_rubric_validation):
    if grader is None:
        user = ctx.obj["client"].get_user()    
        
        grader = get_grader_or_exit(ctx, course, user.username)
    else:
        grader = get_grader_or_exit(ctx, course, grader)

    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(course, assignment, grader = grader, only = only, only_ready_for_grading=True)
    
    if len(teams_registrations) == 0:
        print "No teams found"
        ctx.exit(CHISUBMIT_FAIL)

    for team, registration in teams_registrations.items():
        if not skip_rubric_validation:
            valid, error_msg = validate_repo_rubric(ctx, course, assignment, team, registration)
            if not valid:
                print "Not pushing branch for team %s. Rubric does not validate: %s" % (team.team_id, error_msg)
                continue
        
        print "Pushing grading branch for team %s... " % team.team_id
        gradingrepo_push_grading_branch(ctx.obj['config'], course, team, registration)

    return CHISUBMIT_SUCCESS
Esempio n. 8
0
def instructor_grading_list_submissions(ctx, course, assignment_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(course, assignment)
    teams = sorted(list(teams_registrations.keys()),
                   key=operator.attrgetter("team_id"))

    conn = create_connection(course, ctx.obj['config'])

    if conn is None:
        print("Could not connect to git server.")
        ctx.exit(CHISUBMIT_FAIL)

    for team in teams:
        registration = teams_registrations[team]

        if registration.final_submission is None:
            print("%25s NOT SUBMITTED" % team.team_id)
        else:
            submission_commit = conn.get_commit(
                course, team, registration.final_submission.commit_sha)
            if submission_commit is not None:
                if registration.is_ready_for_grading():
                    print("%25s SUBMITTED (READY for grading)" % team.team_id)
                else:
                    print("%25s SUBMITTED (NOT READY for grading)" %
                          team.team_id)
            else:
                print(
                    "%25s ERROR: Submitted but commit %s not found in repository"
                    % (team.team_id, registration.final_submission.commit_sha))

    return CHISUBMIT_SUCCESS
Esempio n. 9
0
def instructor_assignment_register(ctx, course, assignment_id, student, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    if len(student) < assignment.min_students or len(
            student) > assignment.max_students:
        print(
            "You specified %i students, but this assignment requires teams with at least %i students and at most %i students"
            % (len(student), assignment.min_students, assignment.max_students))
        print()
        print("Are you sure you want to proceed? (y/n): ", end=' ')

        if not yes:
            yesno = input()
        else:
            yesno = 'y'
            print('y')

        if yesno not in ('y', 'Y', 'yes', 'Yes', 'YES'):
            ctx.exit(CHISUBMIT_FAIL)

    assignment.register(students=student)

    print("Registration successful.")

    return CHISUBMIT_SUCCESS
Esempio n. 10
0
def instructor_grading_set_grade(ctx, course, team_id, assignment_id,
                                 rubric_component_description, points):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
    team = get_team_or_exit(ctx, course, team_id)
    registration = get_assignment_registration_or_exit(ctx, team,
                                                       assignment_id)

    rubric_components = assignment.get_rubric_components()

    rubric_component = [
        rc for rc in rubric_components
        if rc.description == rubric_component_description
    ]

    if len(rubric_component) == 0:
        print("No such rubric component in %s: %s" %
              (assignment_id, rubric_component_description))
        ctx.exit(CHISUBMIT_FAIL)
    elif len(rubric_component) > 1:
        print(
            "ERROR: Server returned more than one rubric component for '%s' in %s"
            % (rubric_component_description, assignment_id))
        print(
            "       This should not happen. Please contact the chisubmit administrator."
        )
        ctx.exit(CHISUBMIT_FAIL)
    else:
        rc = rubric_component[0]

        try:
            registration.set_grade(rc, points)
            ctx.exit(CHISUBMIT_SUCCESS)
        except ValueError as ve:
            print(ve)
            ctx.exit(CHISUBMIT_FAIL)
Esempio n. 11
0
def instructor_grading_list_grader_assignments(ctx, course, assignment_id,
                                               grader_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    if grader_id is not None:
        grader = get_grader_or_exit(ctx, course, grader_id)
    else:
        grader = None

    teams_registrations = get_teams_registrations(course, assignment)

    teams = list(teams_registrations.keys())
    teams.sort(key=operator.attrgetter("team_id"))

    for t in teams:
        registration = teams_registrations[t]
        if grader is None:
            if registration.grader is None:
                grader_str = "<no-grader-assigned>"
            else:
                grader_str = registration.grader.user.username
            print(t.team_id, grader_str)
        else:
            if grader == registration.grader.user.username:
                print(t.team_id)

    return CHISUBMIT_SUCCESS
Esempio n. 12
0
def instructor_assignment_add_rubric(ctx, course, assignment_id, rubric_file,
                                     yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    try:
        rubric = RubricFile.from_file(rubric_file)
    except ChisubmitRubricException as cre:
        print("ERROR: Rubric does not validate (%s)" % (cre))
        ctx.exit(CHISUBMIT_FAIL)

    rubric_components = assignment.get_rubric_components()

    if len(rubric_components) > 0:
        print("This assignment already has a rubric. If you load this")
        print("new rubric, the old one will be REMOVED. If grading of")
        print("this assignment has already begun, doing this may break")
        print("existing rubric files completed by the graders.")
        print()
        if not ask_yesno(yes=yes):
            ctx.exit(CHISUBMIT_FAIL)
        print()
        for rc in rubric_components:
            rc.delete()

    order = 10
    for rc in rubric.rubric_components:
        points = rubric.points_possible[rc]
        assignment.create_rubric_component(rc, points, order)
        order += 10

    return CHISUBMIT_SUCCESS
Esempio n. 13
0
def instructor_grading_set_grade(ctx, course, team_id, assignment_id, rubric_component_description, points):   
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
    team = get_team_or_exit(ctx, course, team_id)
    registration = get_assignment_registration_or_exit(ctx, team, assignment_id)
     
    rubric_components = assignment.get_rubric_components()
    
    rubric_component = [rc for rc in rubric_components if rc.description == rubric_component_description]
    
    if len(rubric_component) == 0:
        print "No such rubric component in %s: %s" % (assignment_id, rubric_component_description)
        ctx.exit(CHISUBMIT_FAIL)
    elif len(rubric_component) > 1:
        print "ERROR: Server returned more than one rubric component for '%s' in %s" % (rubric_component_description, assignment_id)
        print "       This should not happen. Please contact the chisubmit administrator."
        ctx.exit(CHISUBMIT_FAIL)
    else:
        rc = rubric_component[0]
        
        try:
            registration.set_grade(rc, points)
            ctx.exit(CHISUBMIT_SUCCESS)
        except ValueError, ve:
            print ve.message
            ctx.exit(CHISUBMIT_FAIL)
Esempio n. 14
0
def instructor_assignment_add_rubric(ctx, course, assignment_id, rubric_file, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    try:
        rubric = RubricFile.from_file(rubric_file) 
    except ChisubmitRubricException as cre:
        print("ERROR: Rubric does not validate (%s)" % (cre))
        ctx.exit(CHISUBMIT_FAIL)
    
    rubric_components = assignment.get_rubric_components()

    if len(rubric_components) > 0:
        print("This assignment already has a rubric. If you load this")
        print("new rubric, the old one will be REMOVED. If grading of")
        print("this assignment has already begun, doing this may break")
        print("existing rubric files completed by the graders.")
        print()
        if not ask_yesno(yes=yes):
            ctx.exit(CHISUBMIT_FAIL)
        print()
        for rc in rubric_components:
            rc.delete()
    
    order = 10
    for rc in rubric.rubric_components:
        points = rubric.points_possible[rc]
        assignment.create_rubric_component(rc, points, order)
        order += 10

    return CHISUBMIT_SUCCESS
Esempio n. 15
0
def grader_validate_rubrics(ctx, course, assignment_id, grader, only):
    if grader is None:
        user = ctx.obj["client"].get_user()

        grader = get_grader_or_exit(ctx, course, user.username)
    else:
        grader = get_grader_or_exit(ctx, course, grader)

    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(course,
                                                  assignment,
                                                  grader=grader,
                                                  only=only)

    all_valid = True
    for team, registration in list(teams_registrations.items()):
        valid, error_msg = validate_repo_rubric(ctx, course, assignment, team,
                                                registration)

        if valid:
            print("%s: Rubric OK." % team.team_id)
        else:
            print("%s: Rubric ERROR: %s" % (team.team_id, error_msg))
            all_valid = False

    if not all_valid:
        ctx.exit(CHISUBMIT_FAIL)
    else:
        return CHISUBMIT_SUCCESS
Esempio n. 16
0
def student_assignment_register(ctx, course, assignment_id, partner):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    user = ctx.obj["client"].get_user()

    try:
        course.get_instructor(user.username)

        # If get_instructor doesn't raise an exception, then the user
        # is an instructor, and we don't include the user in the list
        # of partners.
        r = assignment.register(students=partner)
    except UnknownObjectException:
        # Otherwise, we include the current user
        if user.username in partner:
            print(
                "You specified your own username in --partner. You should use this"
            )
            print("option to specify your partners, not including yourself.")
            ctx.exit(CHISUBMIT_FAIL)

        r = assignment.register(students=partner + (user.username, ))

    print("Your registration for %s (%s) is complete." %
          (r.registration.assignment.assignment_id,
           r.registration.assignment.name))

    if len(r.team_members) > 1:
        some_unconfirmed = False
        print()
        print("Your team name is '%s'." % r.team.team_id)
        print()
        print("The team is composed of the following students:")
        print()
        for tm in r.team_members:
            if tm.confirmed:
                conf = ""
            else:
                conf = "UNCONFIRMED"
                some_unconfirmed = True

            print(" - %s, %s (%s) %s" %
                  (tm.student.user.last_name, tm.student.user.first_name,
                   tm.student.user.username, conf))

        if some_unconfirmed:
            print()
            print(
                "Note: Some students have not yet confirmed that they are part of"
            )
            print(
                "      this team. To confirm they are part of this team, they just"
            )
            print(
                "      need to register as a team themselves (using this same")
            print("      command, and listing the same team members).")

    return CHISUBMIT_SUCCESS
Esempio n. 17
0
def instructor_assignment_stats(ctx, course, assignment_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
             
    all_students = course.get_students()
         
    student_dict = {s.user.username: s.user for s in all_students if not s.dropped}
    students = set(student_dict.keys())
    dropped = set([s.user.username for s in all_students if s.dropped])
    
    teams_unconfirmed = []
    nteams = 0
    nstudents = len(student_dict)
    nstudents_assignment = 0
    nsubmissions = 0
    nstudents_submitted = 0
    unsubmitted = []
    
    teams = course.get_teams(include_students=True, include_assignments=True)

    for team in teams:
        try:
            registrations = team.get_assignment_registrations()
            registrations = [r for r in registrations if r.assignment_id == assignment_id]
            if len(registrations) == 1:
                registration = registrations[0]
            else:
                continue
        except UnknownObjectException:
            continue
        
        unconfirmed = False
        includes_dropped = False
        team_members = team.get_team_members()
        for tm in team_members:
            if tm.username not in dropped:
                try:
                    students.remove(tm.username)
                    nstudents_assignment += 1
                    if not tm.confirmed:
                        unconfirmed = True
                except KeyError, ke:
                    print "WARNING: Student %s seems to be in more than one team (offending team: %s)" % (tm.username, team.team_id)
            else:
                includes_dropped = True

        if not includes_dropped:
            nteams += 1
            
            if registration.final_submission is not None:
                nsubmissions += 1
                nstudents_submitted += len(team_members)
            else:
                unsubmitted.append(team)
            
        if unconfirmed:
            teams_unconfirmed.append(team)
Esempio n. 18
0
def student_assignment_cancel_registration(ctx, course, assignment_id, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    # Get registration
    team, registration = get_team_registration_from_user(ctx, course, assignment)
    team_members = team.get_team_members()  
    
    if len(team_members) == 1:
        student = team_members[0].student        
        individual = True
        print("You (%s %s) currently have an INDIVIDUAL registration for %s (%s)" % (student.user.first_name, student.user.last_name, assignment.assignment_id, assignment.name))
    else:
        students = [tm.student for tm in team_members]
        individual = False
        print("You currently have a TEAM registration for %s (%s)." % (assignment.assignment_id, assignment.name))
        print()
        print("Team %s has the following students:" % team.team_id)
        for s in students:
            print(" - %s %s" % (s.user.first_name, s.user.last_name))         
    
    print()
    
    if registration.final_submission is not None:
        if individual:
            print("You have already made a submission for %s." % assignment_id)
        else:
            print("Team %s has already made a submission for assignment %s." % (team.team_id, assignment_id))
        print()
        print("Please cancel your submission first, and then try canceling your registration.")
        ctx.exit(CHISUBMIT_FAIL)

    if individual:
        print("Are you sure you want to cancel your registration for this assignment? (y/n): ", end=' ')
    else:
        print("Are you sure you want to cancel this team's registration for the assignment? (y/n): ", end=' ')
     
    
    if not yes:
        yesno = input()
    else:
        yesno = 'y'
        print('y')
    
    if yesno in ('y', 'Y', 'yes', 'Yes', 'YES'):        
        try:
            registration.cancel()
            print()
            print("Your registration has been cancelled.")
            ctx.exit(CHISUBMIT_SUCCESS)
        except BadRequestException as bre:
            response_data = bre.json
            print("ERROR: Your registration cannot be cancelled. The server reported the following:")
            print()
            bre.print_errors()

            ctx.exit(CHISUBMIT_FAIL)
Esempio n. 19
0
def instructor_grading_create_grading_repos(ctx, course, assignment_id,
                                            all_teams, only, master):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(
        course, assignment, only=only, only_ready_for_grading=not all_teams)

    if len(teams_registrations) == 0:
        ctx.exit(CHISUBMIT_FAIL)

    teams = sorted(teams_registrations.keys(),
                   key=operator.attrgetter("team_id"))

    for team in teams:
        registration = teams_registrations[team]
        repo = GradingGitRepo.get_grading_repo(ctx.obj['config'], course, team,
                                               registration)

        if repo is None:
            print("%40s -- Creating grading repo... " % team.team_id),

            repo = GradingGitRepo.create_grading_repo(ctx.obj['config'],
                                                      course,
                                                      team,
                                                      registration,
                                                      staging_only=not master)
            repo.sync()

            if registration.final_submission is not None:
                if repo.has_grading_branch_staging():
                    gradingrepo_pull_grading_branch(ctx.obj['config'], course,
                                                    team, registration)
                    print "done"
                else:
                    if master:
                        repo.create_grading_branch()
                        print "done (and created grading branch)"
                    else:
                        print "done (warning: could not pull grading branch; it does not exist)"
            else:
                print "done (note: has not submitted yet)"
        else:
            print("%40s -- Updating grading repo... " % team.team_id),
            if repo.has_grading_branch_staging():
                gradingrepo_pull_grading_branch(ctx.obj['config'], course,
                                                team, registration)
                print "done (pulled latest grading branch)"
            elif repo.has_grading_branch():
                print "nothing to update (grading branch is not in staging)"
            elif registration.final_submission is not None and master:
                repo.create_grading_branch()
                print "done (created missing grading branch)"
            else:
                print "nothing to update (there is no grading branch)"

    return CHISUBMIT_SUCCESS
Esempio n. 20
0
def grader_pull_grading(ctx, course, grader, assignment_id):
    if grader is None:
        user = ctx.obj["client"].get_user()

        grader = get_grader_or_exit(ctx, course, user.username)
    else:
        grader = get_grader_or_exit(ctx, course, grader)

    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(course,
                                                  assignment,
                                                  grader=grader)

    if len(teams_registrations) == 0:
        print("No teams found")
        ctx.exit(CHISUBMIT_FAIL)

    teams = sorted(list(teams_registrations.keys()),
                   key=operator.attrgetter("team_id"))

    for team in teams:
        registration = teams_registrations[team]
        repo = GradingGitRepo.get_grading_repo(ctx.obj['config'], course, team,
                                               registration)

        if repo is None:
            print(("%40s -- Creating grading repo... " % team.team_id),
                  end=' ')
            repo = GradingGitRepo.create_grading_repo(ctx.obj['config'],
                                                      course,
                                                      team,
                                                      registration,
                                                      staging_only=True)
            repo.sync()
            gradingrepo_pull_grading_branch(ctx.obj['config'], course, team,
                                            registration)
            repo.set_grader_author()

            print("done")
        else:
            print(("%40s -- Pulling grading branch..." % team.team_id),
                  end=' ')
            gradingrepo_pull_grading_branch(ctx.obj['config'], course, team,
                                            registration)
            print("done")

        rubricfile = "%s.rubric.txt" % assignment.assignment_id
        rubricfilepath = "%s/%s" % (repo.repo_path, rubricfile)
        if not os.path.exists(rubricfilepath):
            rubric = RubricFile.from_assignment(assignment)
            rubric.save(rubricfilepath, include_blank_comments=True)

    return CHISUBMIT_SUCCESS
Esempio n. 21
0
def instructor_team_pull_repos(ctx, course, assignment_id, directory, only_ready_for_grading, reset, only):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    conn = create_connection(course, ctx.obj['config'])
    
    teams_registrations = get_teams_registrations(course, assignment, only = only)

    directory = os.path.expanduser(directory)
    
    if not os.path.exists(directory):
        os.makedirs(directory)

    teams = sorted([t for t in teams_registrations.keys() if t.active], key = operator.attrgetter("team_id"))

    max_len = max([len(t.team_id) for t in teams])

    for team in teams:
        registration = teams_registrations[team]
        team_dir = "%s/%s" % (directory, team.team_id)
        team_git_url = conn.get_repository_git_url(course, team) 

        if not registration.is_ready_for_grading() and only_ready_for_grading:
            print "%-*s  SKIPPING (not ready for grading)" % (max_len, team.team_id)
            continue
        
        try:
            msg = ""
            if not os.path.exists(team_dir):
                r = LocalGitRepo.create_repo(team_dir, clone_from_url=team_git_url)
                msg = "Cloned repo"
            else:
                r = LocalGitRepo(team_dir)
                if reset:
                    r.fetch("origin")
                    r.reset_branch("origin", "master")
                    msg = "Reset to match origin/master" 
                else:
                    if r.repo.is_dirty():
                        print "%-*s  ERROR: Cannot pull. Local repository has unstaged changes." % (max_len, team.team_id)
                        continue
                    r.checkout_branch("master")
                    r.pull("origin", "master")
                    msg = "Pulled latest changes"
            if only_ready_for_grading:
                r.checkout_commit(registration.final_submission.commit_sha)
                msg += " and checked out commit %s" % (registration.final_submission.commit_sha)               
            print "%-*s  %s" % (max_len, team.team_id, msg)
        except ChisubmitException, ce:
            print "%-*s  ERROR: Could not checkout or pull master branch (%s)" % (max_len, team.team_id, ce.message)
        except GitCommandError, gce:
            print "%-*s  ERROR: Could not checkout or pull master branch" % (max_len, team.team_id)
            print gce
Esempio n. 22
0
def student_assignment_register(ctx, course, assignment_id, partner):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
    
    user = ctx.obj["client"].get_user()
    
    try:
        course.get_instructor(user.username)
        
        # If get_instructor doesn't raise an exception, then the user
        # is an instructor, and we don't include the user in the list
        # of partners.
        r = assignment.register(students = partner)    
    except UnknownObjectException:
        # Otherwise, we include the current user
        if user.username in partner:
            print("You specified your own username in --partner. You should use this")
            print("option to specify your partners, not including yourself.")
            ctx.exit(CHISUBMIT_FAIL)
        
        r = assignment.register(students = partner + (user.username,))    

    print("Your registration for %s (%s) is complete." % (r.registration.assignment.assignment_id, r.registration.assignment.name))
    
    if len(r.team_members) > 1:
        some_unconfirmed = False
        print() 
        print("Your team name is '%s'." % r.team.team_id)
        print()
        print("The team is composed of the following students:")
        print()
        for tm in r.team_members:
            if tm.confirmed:
                conf = ""
            else:
                conf = "UNCONFIRMED"
                some_unconfirmed = True
                
            print(" - %s, %s (%s) %s" % (tm.student.user.last_name, 
                                         tm.student.user.first_name,
                                         tm.student.user.username,
                                         conf))
             
        if some_unconfirmed:
            print()
            print("Note: Some students have not yet confirmed that they are part of")
            print("      this team. To confirm they are part of this team, they just")
            print("      need to register as a team themselves (using this same")
            print("      command, and listing the same team members).")
    
    return CHISUBMIT_SUCCESS
Esempio n. 23
0
def instructor_grading_push_grading(ctx, course, assignment_id, to_students,
                                    all_teams, only, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    if to_students:
        print(
            "You are going to push the grading branches to the student repositories."
        )
        print("If you do so, students will be able to see their grading!")
        print()
        print("Are you sure you want to continue? (y/n): ", end=' ')

        if not yes:
            yesno = input()
        else:
            yesno = 'y'
            print('y')

        if yesno not in ('y', 'Y', 'yes', 'Yes', 'YES'):
            ctx.exit(CHISUBMIT_FAIL)
        print()
    else:
        print(
            "Pushing grading to staging repositories. Only instructors and graders will"
        )
        print(
            "be able to access this grading. If you want to push the grading to the"
        )
        print("student repositories, use the --to-students option")
        print()

    teams_registrations = get_teams_registrations(
        course, assignment, only=only, only_ready_for_grading=not all_teams)
    teams = sorted(list(teams_registrations.keys()),
                   key=operator.attrgetter("team_id"))

    for team in teams:
        registration = teams_registrations[team]
        print(("Pushing grading branch for team %s... " % team.team_id),
              end=' ')
        gradingrepo_push_grading_branch(ctx.obj['config'],
                                        course,
                                        team,
                                        registration,
                                        to_students=to_students)
        print("done.")

    return CHISUBMIT_SUCCESS
Esempio n. 24
0
def instructor_grading_pull_grading(ctx, course, assignment_id, from_students,
                                    only, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    if from_students:
        print(
            "Pulling grading from the student repositories is an uncommon operation."
        )
        print(
            "Instead, you should only ever make changes to the grading in the staging"
        )
        print(
            "repositories, and push those changes to the student repositories (which"
        )
        print(
            "should always mirror what is in the staging repositories). So, there should"
        )
        print("never be a need to pull grading from a student repository.")
        print()
        print("Are you sure you want to continue and pull the grading from")
        print("the student repositories? (y/n): ", end=' ')

        if not yes:
            yesno = input()
        else:
            yesno = 'y'
            print('y')

        if yesno not in ('y', 'Y', 'yes', 'Yes', 'YES'):
            ctx.exit(CHISUBMIT_FAIL)

    teams_registrations = get_teams_registrations(course,
                                                  assignment,
                                                  only=only)
    teams = sorted(list(teams_registrations.keys()),
                   key=operator.attrgetter("team_id"))

    for team in teams:
        registration = teams_registrations[team]
        print("Pulling grading branch for team %s... " % team.team_id)
        gradingrepo_pull_grading_branch(ctx.obj['config'],
                                        course,
                                        team,
                                        registration,
                                        from_students=from_students)

    return CHISUBMIT_SUCCESS
Esempio n. 25
0
def instructor_validate_rubrics(ctx, course, assignment_id, grader, only):
    if grader is not None:
        grader = get_grader_or_exit(ctx, course, grader)

    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(course, assignment, grader = grader, only = only)
    
    for team, registration in teams_registrations.items():
        valid, error_msg = validate_repo_rubric(ctx, course, assignment, team, registration)

        if valid:
            print "%s: Rubric OK." % team.team_id
        else:
            print "%s: Rubric ERROR: %s" % (team.team_id, error_msg)

    return CHISUBMIT_SUCCESS
Esempio n. 26
0
def instructor_grading_create_grading_repos(ctx, course, assignment_id, all_teams, only, master):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
    
    teams_registrations = get_teams_registrations(course, assignment, only = only, only_ready_for_grading=not all_teams)

    if len(teams_registrations) == 0:
        ctx.exit(CHISUBMIT_FAIL)
        
    teams = sorted(teams_registrations.keys(), key=operator.attrgetter("team_id"))

    for team in teams:
        registration = teams_registrations[team]
        repo = GradingGitRepo.get_grading_repo(ctx.obj['config'], course, team, registration)

        if repo is None:
            print ("%20s -- Creating grading repo... " % team.team_id),
                
            repo = GradingGitRepo.create_grading_repo(ctx.obj['config'], course, team, registration, staging_only = not master)
            repo.sync()
            
            if registration.final_submission is not None:
                if repo.has_grading_branch_staging():
                    gradingrepo_pull_grading_branch(ctx.obj['config'], course, team, registration)
                    print "done"
                else:
                    if master:
                        repo.create_grading_branch()
                        print "done (and created grading branch)"
                    else:
                        print "done (warning: could not pull grading branch; it does not exist)"
            else:
                print "done (note: has not submitted yet)"
        else:
            print "%20s -- Updating grading repo... " % team.team_id
            if repo.has_grading_branch_staging():
                gradingrepo_pull_grading_branch(ctx.obj['config'], course, team, registration)
                print "done (pulled latest grading branch)"
            elif registration.final_submission is not None and master:
                repo.create_grading_branch()
                print "done (created missing grading branch)"
            else:
                print "nothing to update (there is no grading branch)"

    return CHISUBMIT_SUCCESS
Esempio n. 27
0
def grader_pull_grading(ctx, course, grader, assignment_id):
    if grader is None:
        user = ctx.obj["client"].get_user()    
        
        grader = get_grader_or_exit(ctx, course, user.username)
    else:
        grader = get_grader_or_exit(ctx, course, grader)
        
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(course, assignment, grader = grader)
    
    if len(teams_registrations) == 0:
        print "No teams found"
        ctx.exit(CHISUBMIT_FAIL)

    teams = sorted(teams_registrations.keys(), key=operator.attrgetter("team_id"))

    for team in teams:
        registration = teams_registrations[team]
        repo = GradingGitRepo.get_grading_repo(ctx.obj['config'], course, team, registration)

        if repo is None:
            print ("%20s -- Creating grading repo... " % team.team_id),
            repo = GradingGitRepo.create_grading_repo(ctx.obj['config'], course, team, registration, staging_only = True)
            repo.sync()
            gradingrepo_pull_grading_branch(ctx.obj['config'], course, team, registration)
            repo.set_grader_author()
            
            print "done"
        else:
            print ("%20s -- Pulling grading branch..." % team.team_id),
            gradingrepo_pull_grading_branch(ctx.obj['config'], course, team, registration)
            print "done"
            
        rubricfile = "%s.rubric.txt" % assignment.assignment_id
        rubricfilepath = "%s/%s" % (repo.repo_path, rubricfile)
        if not os.path.exists(rubricfilepath):
            rubric = RubricFile.from_assignment(assignment)
            rubric.save(rubricfilepath, include_blank_comments=True)            
        
    return CHISUBMIT_SUCCESS
Esempio n. 28
0
def instructor_validate_rubrics(ctx, course, assignment_id, grader, only):
    if grader is not None:
        grader = get_grader_or_exit(ctx, course, grader)

    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(course,
                                                  assignment,
                                                  grader=grader,
                                                  only=only)

    for team, registration in list(teams_registrations.items()):
        valid, error_msg = validate_repo_rubric(ctx, course, assignment, team,
                                                registration)

        if valid:
            print("%s: Rubric OK." % team.team_id)
        else:
            print("%s: Rubric ERROR: %s" % (team.team_id, error_msg))

    return CHISUBMIT_SUCCESS
Esempio n. 29
0
def instructor_assignment_register(ctx, course, assignment_id, student, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
    
    if len(student) < assignment.min_students or len(student) > assignment.max_students:
        print("You specified %i students, but this assignment requires teams with at least %i students and at most %i students" % (len(student), assignment.min_students, assignment.max_students))
        print()
        print("Are you sure you want to proceed? (y/n): ", end=' ') 
        
        if not yes:
            yesno = input()
        else:
            yesno = 'y'
            print('y')
    
        if yesno not in ('y', 'Y', 'yes', 'Yes', 'YES'):
            ctx.exit(CHISUBMIT_FAIL)

    assignment.register(students = student)
    
    print("Registration successful.")
    
    return CHISUBMIT_SUCCESS
Esempio n. 30
0
def shared_team_list(ctx, course, ids, assignment, include_inactive):
    teams = course.get_teams()
    teams.sort(key=operator.attrgetter("team_id"))

    assignment_id = assignment
    if assignment_id is not None:
        assignment = get_assignment_or_exit(ctx, course, assignment_id)
    else:
        assignment = None

    for team in teams:
        registrations = team.get_assignment_registrations()
        
        if assignment is not None:
            if not assignment.assignment_id in [r.assignment.assignment_id for r in registrations]:
                continue
            
        if not (team.active or include_inactive):
            continue
        
        if ids:
            print team.team_id
        else:
            team_members = team.get_team_members()
            
            if len(team_members) == 0:
                students = "No students"
            else:
                students = "Students: " + ",".join([tm.student.user.username for tm in team_members])
            if len(registrations) == 0:
                assignments = "No assignments"
            else:
                assignments = "Assignments: " + ",".join([r.assignment.assignment_id for r in registrations])
            fields = [team.team_id, students, assignments]

            print "  ".join(fields)

    return CHISUBMIT_SUCCESS
Esempio n. 31
0
def instructor_grading_show_grading_status(ctx, course, assignment_id, by_grader, include_diff_urls, use_stored_grades):
    assignment = get_assignment_or_exit(ctx, course, assignment_id, include_rubric = True)
    rubric_components = assignment.get_rubric_components()

    teams_registrations = get_teams_registrations(course, assignment, include_grades = True)
    teams = sorted(teams_registrations.keys(), key=operator.attrgetter("team_id"))
    
    team_status = []
    graders = set()
    
    for team in teams:
        registration = teams_registrations[team]

        if registration.grader is None:
            grader_str = "<no grader assigned>"
        else:
            grader_str = registration.grader.user.username
        graders.add(grader_str)
        
        grading_status = None
        
        if use_stored_grades:
            grades = registration.get_grades()
            total_grade = registration.get_total_grade()
            
            graded_rc_ids = [g.rubric_component_id for g in grades]            
        else:
            total_grade = 0.0
            repo = GradingGitRepo.get_grading_repo(ctx.obj['config'], course, team, registration)
            if repo is None:
                grading_status = "NO GRADING REPO"
            else:
                rubricfile = repo.repo_path + "/%s.rubric.txt" % assignment.assignment_id
        
                if not os.path.exists(rubricfile):
                    grading_status = "NOT GRADED - No rubric"
                else:        
                    try:
                        rubric = RubricFile.from_file(open(rubricfile), assignment)
            
                        graded_rc_ids = [rc.id for rc in rubric_components if rubric.points[rc.description] is not None]  
                
                        for rc in rubric_components:
                            grade = rubric.points[rc.description]
                            if grade is not None:
                                total_grade += grade
                
                        if rubric.penalties is not None:
                            for p in rubric.penalties.values():
                                total_grade += p
                
                        if rubric.bonuses is not None:
                            for p in rubric.bonuses.values():
                                total_grade += p  
                    except ChisubmitRubricException, cre:
                        grading_status = "ERROR: Rubric does not validate (%s)" % (cre.message)
                        
        if grading_status is None:
            has_some = False
            has_all = True
            for rc in rubric_components:
                if rc.id in graded_rc_ids:
                    has_some = True
                else:
                    has_all = False
                            
            if not has_some:
                grading_status = "NOT GRADED"
            elif has_all:
                grading_status = "GRADED"
            else:
                grading_status = "PARTIALLY GRADED"

            
        if include_diff_urls and has_some:
            commit_sha = registration.final_submission.commit_sha[:8]
            diff_url = "https://mit.cs.uchicago.edu/%s-staging/%s/compare/%s...%s-grading" % (course.course_id, team.team_id, commit_sha, assignment.assignment_id)
        else:
            diff_url = ""
            
        team_status.append((team.team_id, grader_str, total_grade, diff_url, grading_status))
Esempio n. 32
0
def instructor_assignment_update_rubric(ctx, course, assignment_id,
                                        rubric_component, description, points,
                                        add, edit, remove, up, down, yes):
    num_cmds = len([x for x in [add, edit, remove, up, down] if x is True])
    if num_cmds > 1:
        print(
            "You can only specify one of the following: --add / --edit / --remove / --up / --down"
        )
        ctx.exit(CHISUBMIT_FAIL)
    if num_cmds == 0:
        print(
            "You must specify one of the following: --add / --edit / --remove / --up / --down"
        )
        ctx.exit(CHISUBMIT_FAIL)
    if add and points is None:
        print("The --add option requires the --points option")
        ctx.exit(CHISUBMIT_FAIL)
    if edit and not (description or points):
        print(
            "The --edit option requires the --description option or the --points option (or both)"
        )
        ctx.exit(CHISUBMIT_FAIL)
    if (remove or up or down) and points is not None:
        print("The --points option cannot be used with --remove/--up/--down")
        ctx.exit(CHISUBMIT_FAIL)
    if (remove or up or down) and points is not None:
        print("The --points option cannot be used with --remove/--up/--down")
        ctx.exit(CHISUBMIT_FAIL)

    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    rubric_components = assignment.get_rubric_components()

    rcs = [(i, rc) for i, rc in enumerate(rubric_components)
           if rc.description == rubric_component]
    if len(rcs) == 0:
        if not add:
            print("No such rubric component: %s" % rubric_component)
            ctx.exit(CHISUBMIT_FAIL)
        else:
            i, rc = None, None
    elif len(rcs) > 1:
        print("Multiple rubric components with this name: %s" %
              rubric_component)
        print("(this should not happen)")
        ctx.exit(CHISUBMIT_FAIL)
    else:
        i, rc = rcs[0]

    if add:
        if rc is not None:
            print("There is already a rubric component with this name: %s" %
                  rubric_component)
            ctx.exit(CHISUBMIT_FAIL)

        if len(rubric_components) == 0:
            last_order = 0
        else:
            last_order = rubric_components[-1].order

        assignment.create_rubric_component(rubric_component, points,
                                           last_order + 10)
    elif edit:
        if description is not None:
            print("If grading of this assignment has begun, changing the")
            print("description of a rubric component may break existing")
            print("rubric files completed by the graders.")
            print()
            if not ask_yesno(yes=yes):
                ctx.exit(CHISUBMIT_FAIL)
            print()
            rc.description = description
        if points is not None:
            rc.points = points
    elif remove:
        print("If grading of this assignment has begun, removing")
        print("a rubric component may break existing rubric files")
        print("completed by the graders.")
        print()
        if not ask_yesno(yes=yes):
            ctx.exit(CHISUBMIT_FAIL)
        print()
        rc.delete()
    elif up:
        if i - 1 >= 0:
            other_rc = rubric_components[i - 1]
            other_rc_order = rubric_components[i - 1].order

            other_rc.order = rc.order
            rc.order = other_rc_order
    elif down:
        if i + 1 < len(rubric_components):
            other_rc = rubric_components[i + 1]
            other_rc_order = rubric_components[i + 1].order

            other_rc.order = rc.order
            rc.order = other_rc_order
Esempio n. 33
0
def student_assignment_cancel_submit(ctx, course, assignment_id, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    # Determine team for this assignment
    team, registration = get_team_registration_from_user(ctx, course, assignment)
    team_members = team.get_team_members()    
    
    if len(team_members) == 1:
        individual = True
    else:
        individual = False    
    
    if registration.final_submission is None:
        if individual:
            print("You have not made a submission for assignment %s," % assignment_id)
        else:
            print("Team %s has not made a submission for assignment %s," % (team.team_id, assignment_id))
        print("so there is nothing to cancel.")
        ctx.exit(CHISUBMIT_FAIL)
        
    if registration.grading_started:
        print("You cannot cancel this submission.")
        print("You made a submission and it has already been sent to the graders for grading.")
        print("Please contact an instructor if you wish to amend your submission.")

        ctx.exit(CHISUBMIT_FAIL)        
            
    conn = create_connection(course, ctx.obj['config'])
    
    if conn is None:
        print("Could not connect to git server.")
        ctx.exit(CHISUBMIT_FAIL)
        
    submission_commit = conn.get_commit(course, team, registration.final_submission.commit_sha)
        
    print()
    print("This is your existing submission for assignment %s:" % assignment_id)
    print()
    if submission_commit is None:
        print("WARNING: Previously submitted commit '%s' is not in the repository!" % registration.final_submission.commit_sha)
    else:
        print_commit(submission_commit)
    print()    

    print("Are you sure you want to cancel this submission? (y/n): ", end=' ') 
    
    if not yes:
        yesno = input()
    else:
        yesno = 'y'
        print('y')
    
    if yesno in ('y', 'Y', 'yes', 'Yes', 'YES'):
        registration.final_submission_id = None
        
        # TODO: Can't do this until GitLab supports updating tags
        #    
        # message = "Extensions: %i\n" % extensions_requested
        # if submission_tag is None:
        #     conn.create_submission_tag(course, team, tag_name, message, commit.sha)
        # else:
        #     conn.update_submission_tag(course, team, tag_name, message, commit.sha)
        print()
        print("Your submission has been cancelled.")
Esempio n. 34
0
def instructor_assignment_update_rubric(ctx, course, assignment_id, rubric_component, description, points, add, edit, remove, up, down, yes):
    num_cmds = len([x for x in [add,edit,remove,up,down] if x is True])
    if num_cmds > 1:
        print("You can only specify one of the following: --add / --edit / --remove / --up / --down")
        ctx.exit(CHISUBMIT_FAIL)
    if num_cmds == 0:
        print("You must specify one of the following: --add / --edit / --remove / --up / --down")
        ctx.exit(CHISUBMIT_FAIL)
    if add and points is None:
        print("The --add option requires the --points option")
        ctx.exit(CHISUBMIT_FAIL)
    if edit and not (description or points):
        print("The --edit option requires the --description option or the --points option (or both)")
        ctx.exit(CHISUBMIT_FAIL)
    if (remove or up or down) and points is not None:
        print("The --points option cannot be used with --remove/--up/--down")        
        ctx.exit(CHISUBMIT_FAIL)
    if (remove or up or down) and points is not None:
        print("The --points option cannot be used with --remove/--up/--down")        
        ctx.exit(CHISUBMIT_FAIL)
    
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
  
    rubric_components = assignment.get_rubric_components()
    
    rcs = [(i, rc) for i, rc in enumerate(rubric_components) if rc.description == rubric_component]
    if len(rcs) == 0:
        if not add:
            print("No such rubric component: %s" % rubric_component)
            ctx.exit(CHISUBMIT_FAIL)
        else:
            i, rc = None, None
    elif len(rcs) > 1:
        print("Multiple rubric components with this name: %s" % rubric_component)
        print("(this should not happen)")
        ctx.exit(CHISUBMIT_FAIL)
    else:
        i, rc = rcs[0]
    
    if add:
        if rc is not None:
            print("There is already a rubric component with this name: %s" % rubric_component)
            ctx.exit(CHISUBMIT_FAIL)
        
        if len(rubric_components) == 0:
            last_order = 0
        else:
            last_order = rubric_components[-1].order

        assignment.create_rubric_component(rubric_component, points, last_order + 10)
    elif edit:
        if description is not None:
            print("If grading of this assignment has begun, changing the")
            print("description of a rubric component may break existing")
            print("rubric files completed by the graders.")
            print()
            if not ask_yesno(yes=yes):
                ctx.exit(CHISUBMIT_FAIL)
            print()            
            rc.description = description
        if points is not None:
            rc.points = points
    elif remove:
        print("If grading of this assignment has begun, removing")
        print("a rubric component may break existing rubric files")
        print("completed by the graders.")
        print()
        if not ask_yesno(yes=yes):
            ctx.exit(CHISUBMIT_FAIL)
        print()            
        rc.delete()   
    elif up:
        if i-1 >= 0:
            other_rc = rubric_components[i-1]
            other_rc_order = rubric_components[i-1].order
            
            other_rc.order = rc.order
            rc.order = other_rc_order
    elif down:
        if i+1 < len(rubric_components):
            other_rc = rubric_components[i+1]
            other_rc_order = rubric_components[i+1].order
            
            other_rc.order = rc.order
            rc.order = other_rc_order       
Esempio n. 35
0
def instructor_assignment_register(ctx, course, assignment_id, student):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    assignment.register(students=student)

    return CHISUBMIT_SUCCESS
Esempio n. 36
0
def student_assignment_submit(ctx, course, assignment_id, commit_sha, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    # Determine team for this assignment
    team, registration = get_team_registration_from_user(ctx, course, assignment)
    team_members = team.get_team_members()    
                
    title = "SUBMISSION FOR ASSIGNMENT %s (%s)" % (assignment.assignment_id, assignment.name)
    print(title)
    print("-" * len(title))
    print()
    if len(team_members) == 1:
        student = team_members[0].student
        individual = True
        print("This is an INDIVIDUAL submission for %s %s" % (student.user.first_name, student.user.last_name))
    else:
        students = [tm.student for tm in team_members]
        individual = False
        print("This is a TEAM submission for team %s with the following students:" % team.team_id)
        for s in students:
            print(" - %s %s" % (s.user.first_name, s.user.last_name))
    print()
                
    conn = create_connection(course, ctx.obj['config'])
    
    if conn is None:
        print("Could not connect to git server.")
        ctx.exit(CHISUBMIT_FAIL)
    
    if commit_sha is None:
        commit = conn.get_latest_commit(course, team)

        if commit is None:
            print("It seems there are no commits in your repository, so I cannot submit anything")
            ctx.exit(CHISUBMIT_FAIL)
                
        user_specified_commit = False
    else:    
        commit = conn.get_commit(course, team, commit_sha)
        
        if commit is None:
            print("Commit %s does not exist in repository" % commit_sha)
            ctx.exit(CHISUBMIT_FAIL)

        user_specified_commit = True
        
    try:
        submit_response = registration.submit(commit.sha, dry_run = True)
    except BadRequestException as bre:
        response_data = bre.json
        
        if "extensions_needed" in response_data and "extensions_available" in response_data:
            extensions_needed = response_data["extensions_needed"]
            extensions_available = response_data["extensions_available"]
            
            deadline_utc = parse(response_data["deadline"])
            submitted_at_utc = parse(response_data["submitted_at"])
            deadline_local = convert_datetime_to_local(deadline_utc)
            submitted_at_local = convert_datetime_to_local(submitted_at_utc)        
            
            if extensions_needed > extensions_available:
                msg1 = "You do not have enough extensions to submit this assignment."
                msg2 = "You would need %i extensions to submit this assignment at this " \
                       "time, but you only have %i left" % (extensions_needed, extensions_available)
    
                print()
                print(msg1)
                print()            
                print("     Deadline (UTC): %s" % deadline_utc.isoformat(sep=" "))
                print("          Now (UTC): %s" % submitted_at_utc.isoformat(sep=" "))
                print() 
                print("   Deadline (Local): %s" % deadline_local.isoformat(sep=" "))
                print("        Now (Local): %s" % submitted_at_local.isoformat(sep=" "))
                print() 
                print(msg2) 
                print()
            else:
                print("ERROR: Your submission cannot be completed. The server reported the following:")
                print()
                bre.print_errors()
        else:
            print("ERROR: Your submission cannot be completed. The server reported the following:")
            print()
            bre.print_errors()

        ctx.exit(CHISUBMIT_FAIL)
    
    if registration.final_submission is not None:
        prior_commit_sha = registration.final_submission.commit_sha
        prior_extensions_used = registration.final_submission.extensions_used             
        prior_submitted_at_utc = registration.final_submission.submitted_at
        prior_submitted_at_local = convert_datetime_to_local(prior_submitted_at_utc)            
        
        submission_commit = conn.get_commit(course, team, prior_commit_sha)            
        
        if prior_commit_sha == commit.sha:
            print("You have already submitted assignment %s" % registration.assignment.assignment_id)
            print()
            print("You submitted the following commit on %s:" % prior_submitted_at_local)
            print()
            if submission_commit is None:
                print("WARNING: Previously submitted commit '%s' is not in the repository!" % prior_commit_sha)
            else:
                print_commit(submission_commit)
            print()
            if user_specified_commit:
                print("You are trying to submit the same commit again (%s)" % prior_commit_sha)
                print("If you want to re-submit, please specify a different commit.")
            else:
                print("The above commit is the latest commit in your repository.")
                print()
                print("If you were expecting to see a different commit, make sure you've pushed")
                print("your latest code to your repository.")
            ctx.exit(CHISUBMIT_FAIL)
            
        print("You have already submitted assignment %s" % registration.assignment.assignment_id)
        print()
        print("You submitted the following commit on %s:" % prior_submitted_at_local)
        print()
        if submission_commit is None:
            print("WARNING: Previously submitted commit '%s' is not in the repository!" % prior_commit_sha)
        else:
            print_commit(submission_commit)
        print()

        msg = "IF YOU CONTINUE, THE ABOVE SUBMISSION FOR %s (%s) WILL BE CANCELLED." % (registration.assignment.assignment_id, registration.assignment.name)
        
        print("!"*len(msg))
        print(msg)
        print("!"*len(msg))
        print()        
        if not user_specified_commit:
            print("If you continue, your submission will instead point to the latest commit in your repository:")
        else:
            print("If you continue, your submission will instead point to the following commit:")                
    else:
        if not user_specified_commit:
            print("The latest commit in your repository is the following:")
        else:
            print("The commit you are submitting is the following:")
    print()
    print_commit(commit)
    print()
    print("PLEASE VERIFY THIS IS THE EXACT COMMIT YOU WANT TO SUBMIT")
    print()
    if individual:
        print("You currently have %i extensions" % (submit_response.extensions_before))
    else:
        print("Your team currently has %i extensions" % (submit_response.extensions_before))
    print()
    if registration.final_submission is not None:
        print("You used %i extensions in your previous submission of this assignment." % prior_extensions_used)
        print("and you are going to use %i additional extensions now." % (submit_response.extensions_needed - prior_extensions_used))
    else:
        print("You are going to use %i extensions on this submission." % submit_response.extensions_needed)
    print()
    print("You will have %i extensions left after this submission." % submit_response.extensions_after)
    print()
    
    if submit_response.in_grace_period:
        print("NOTE: You are submitting after the deadline, but the instructor has")
        print("allowed some extra time after the deadline for students to submit")
        print("without having to consume an extension.")
        print()
     
    print("Are you sure you want to continue? (y/n): ", end=' ') 
    
    if not yes:
        yesno = input()
    else:
        yesno = 'y'
        print('y')
    
    if yesno in ('y', 'Y', 'yes', 'Yes', 'YES'):
        try:
            submit_response = registration.submit(commit.sha, dry_run=False)
            
            # TODO: Can't do this until GitLab supports updating tags
            #    
            # message = "Extensions: %i\n" % extensions_requested
            # if submission_tag is None:
            #     conn.create_submission_tag(course, team, tag_name, message, commit.sha)
            # else:
            #     conn.update_submission_tag(course, team, tag_name, message, commit.sha)
            
            print()
            print("Your submission has been completed.")

            if submit_response.in_grace_period:
                print()
                print("Your submission was made during the deadline's grace period. This means")
                print("that, although your submission was technically made *after* the")
                print("deadline, we are counting it as if it had been made before the deadline.")
                print()
                print("In the future, you should not rely on the presence of this grace period!")
                print("Your instructor may choose not to use one in future assignments, or may")
                print("use a shorter grace period. Your instructor is also aware of what")
                print("submissions are made during the grace period; if you repeatedly submit")
                print("during the grace period, your instructor may charge you an extension")
                print("or refuse to accept your assignment if you are out of extensions.")
            
            return CHISUBMIT_SUCCESS

        except BadRequestException as bre:
            print()        
            print("ERROR: Your submission was not completed. The server reported the following errors:")
            bre.print_errors()
            ctx.exit(CHISUBMIT_FAIL)
    else:
        print("Your submission has not been completed.")
        print()
        print("If you chose not to proceed because the above commit is not the one you wanted")
        print("to submit, make sure you've pushed your latest code to your repository before")
        print("attempting to submit again.")
        print()
        print("If you want to submit a different commit from your latest commit (e.g., an earlier")
        print("commit), you can use the --commit-sha option to specify a different commit.")
        ctx.exit(CHISUBMIT_FAIL)
Esempio n. 37
0
def instructor_assignment_show_rubric(ctx, course, assignment_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    rubric = RubricFile.from_assignment(assignment)
    print(rubric.to_yaml())
Esempio n. 38
0
def instructor_assignment_stats(ctx, course, assignment_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    all_students = course.get_students()

    student_dict = {
        s.user.username: s.user
        for s in all_students if not s.dropped
    }
    students = set(student_dict.keys())
    dropped = set([s.user.username for s in all_students if s.dropped])

    teams_unconfirmed = []
    nteams = 0
    nstudents = len(student_dict)
    nstudents_assignment = 0
    nsubmissions = 0
    nstudents_submitted = 0
    unsubmitted = []

    teams = course.get_teams(include_students=True, include_assignments=True)

    for team in teams:
        try:
            registrations = team.get_assignment_registrations()
            registrations = [
                r for r in registrations if r.assignment_id == assignment_id
            ]
            if len(registrations) == 1:
                registration = registrations[0]
            else:
                continue
        except UnknownObjectException:
            continue

        unconfirmed = False
        includes_dropped = False
        team_members = team.get_team_members()
        for tm in team_members:
            if tm.username not in dropped:
                try:
                    students.remove(tm.username)
                    nstudents_assignment += 1
                    if not tm.confirmed:
                        unconfirmed = True
                except KeyError, ke:
                    print "WARNING: Student %s seems to be in more than one team (offending team: %s)" % (
                        tm.username, team.team_id)
            else:
                includes_dropped = True

        if not includes_dropped:
            nteams += 1

            if registration.final_submission is not None:
                nsubmissions += 1
                nstudents_submitted += len(team_members)
            else:
                unsubmitted.append(team)

        if unconfirmed:
            teams_unconfirmed.append(team)
Esempio n. 39
0
def instructor_grading_assign_graders(ctx, course, assignment_id,
                                      from_assignment, avoid_assignment,
                                      grader_file, dry_run, reset):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    if from_assignment is not None:
        from_assignment = get_assignment_or_exit(ctx, course, from_assignment)

    if avoid_assignment is not None:
        avoid_assignment = get_assignment_or_exit(ctx, course,
                                                  avoid_assignment)

    if reset and from_assignment is not None:
        print("--reset and --from_assignment are mutually exclusive")
        ctx.exit(CHISUBMIT_FAIL)

    if avoid_assignment is not None and from_assignment is not None:
        print(
            "--avoid_assignment and --from_assignment are mutually exclusive")
        ctx.exit(CHISUBMIT_FAIL)

    if grader_file is not None:
        grader_workload = yaml.load(grader_file)
        graders = []

        for username in grader_workload:
            try:
                grader = course.get_grader(username)
                graders.append(grader)
            except UnknownObjectException:
                print("No such grader: %s" % username)
                ctx.exit(CHISUBMIT_FAIL)
    else:
        graders = course.get_graders()
        grader_workload = {g.user.username: "******" for g in graders}

    if len(graders) == 0:
        print("ERROR: No graders.")
        ctx.exit(CHISUBMIT_FAIL)

    teams_registrations = get_teams_registrations(course, assignment)
    teams = list(teams_registrations.keys())

    n_teams = len(teams)
    teams_per_grader = {}
    teams_per_grader_assigned = dict([(g.user.username, 0) for g in graders])
    assigned = 0
    graders_assigned_remainder = []
    for username, workload in list(grader_workload.items()):
        if workload != "remainder":
            if not isinstance(workload, int) or workload <= 0:
                print("Invalid workload for grader '%s': %s" %
                      (username, workload))
            teams_per_grader[username] = workload
            assigned += workload
        else:
            teams_per_grader[username] = None
            graders_assigned_remainder.append(username)

    min_teams_per_grader = old_div((n_teams - assigned),
                                   len(graders_assigned_remainder))
    extra_teams = (n_teams - assigned) % len(graders_assigned_remainder)

    for username in teams_per_grader:
        if teams_per_grader[username] is None:
            teams_per_grader[username] = min_teams_per_grader

    random.seed(course.course_id + assignment_id)
    random.shuffle(graders_assigned_remainder)

    # so many graders in this course that some will end up expecting zero
    # teams to grade. Make sure they are able to get at least one.
    for username in graders_assigned_remainder[:extra_teams]:
        teams_per_grader[username] += 1

    assert sum([v for v in list(teams_per_grader.values())]) == n_teams

    team_grader = {t.team_id: None for t in list(teams_registrations.keys())}

    if from_assignment is not None:
        from_assignment_registrations = get_teams_registrations(
            course, from_assignment)

        common_teams = [
            t for t in teams
            if t in teams_registrations and t in from_assignment_registrations
        ]
        for t in common_teams:
            registration = from_assignment_registrations[t]

            # try to assign the same grader that would grade the same team's other assignment
            grader = registration.grader
            if grader is not None and teams_per_grader[
                    grader.user.username] > 0:
                team_grader[t.team_id] = grader.user.username
                teams_per_grader[grader.user.username] -= 1
                teams_per_grader_assigned[grader.user.username] += 1

    if avoid_assignment is not None:
        avoid_assignment_registrations = get_teams_registrations(
            course, avoid_assignment)

    if not reset:
        for t in teams:
            if teams_registrations[t].grader is None:
                team_grader[t.team_id] = None
            else:
                grader_id = teams_registrations[t].grader.user.username
                team_grader[t.team_id] = grader_id
                teams_per_grader[grader_id] = max(
                    0, teams_per_grader[grader_id] - 1)
                teams_per_grader_assigned[grader_id] += 1

    not_ready_for_grading = []
    ta_avoid = {}
    graders_cycle = itertools.cycle(graders)
    for team, registration in list(teams_registrations.items()):
        if team_grader[team.team_id] is not None:
            continue

        if not registration.is_ready_for_grading():
            not_ready_for_grading.append(team.team_id)
            continue

        graders_left = len(graders)
        for g in graders_cycle:
            # Make sure we don't fall into an infinite loop
            if graders_left == 0:
                print("Cannot find a grader for %s!" % team.team_id)
                break
            else:
                graders_left -= 1

            if teams_per_grader[g.user.username] == 0:
                continue
            else:
                if avoid_assignment is not None:
                    avoid_registration = ta_avoid.setdefault(
                        team.team_id, avoid_assignment_registrations.get(team))
                    if avoid_registration is not None and avoid_registration.grader.user.username == grader.user.username:
                        continue

                valid = True
                for tm in team.get_team_members():
                    if tm.username in g.conflicts_usernames:
                        valid = False
                        break

                if valid:
                    team_grader[team.team_id] = g.user.username
                    teams_per_grader[g.user.username] -= 1
                    teams_per_grader_assigned[g.user.username] += 1
                    break

    for team, registration in list(teams_registrations.items()):
        if team_grader[team.team_id] is None:
            if team.team_id not in not_ready_for_grading:
                print("Team %s has no grader" % (team.team_id))
            else:
                print("Team %s's submission isn't ready for grading yet" %
                      (team.team_id))
        else:
            if not dry_run:
                if registration.grader_username != team_grader[team.team_id]:
                    registration.grader_username = team_grader[team.team_id]
            else:
                print("%s: %s" % (team.team_id, team_grader[team.team_id]))
    print()
    for grader_id, assigned in list(teams_per_grader_assigned.items()):
        if teams_per_grader[grader_id] != 0:
            print(
                grader_id, assigned,
                "(still needs to be assigned %i more assignments)" %
                (teams_per_grader[grader_id]))
        else:
            print(grader_id, assigned)

    return CHISUBMIT_SUCCESS
Esempio n. 40
0
def student_assignment_cancel_registration(ctx, course, assignment_id, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    # Get registration
    team, registration = get_team_registration_from_user(
        ctx, course, assignment)
    team_members = team.get_team_members()

    if len(team_members) == 1:
        student = team_members[0].student
        individual = True
        print(
            "You (%s %s) currently have an INDIVIDUAL registration for %s (%s)"
            % (student.user.first_name, student.user.last_name,
               assignment.assignment_id, assignment.name))
    else:
        students = [tm.student for tm in team_members]
        individual = False
        print("You currently have a TEAM registration for %s (%s)." %
              (assignment.assignment_id, assignment.name))
        print()
        print("Team %s has the following students:" % team.team_id)
        for s in students:
            print(" - %s %s" % (s.user.first_name, s.user.last_name))

    print()

    if registration.final_submission is not None:
        if individual:
            print("You have already made a submission for %s." % assignment_id)
        else:
            print("Team %s has already made a submission for assignment %s." %
                  (team.team_id, assignment_id))
        print()
        print(
            "Please cancel your submission first, and then try canceling your registration."
        )
        ctx.exit(CHISUBMIT_FAIL)

    if individual:
        print(
            "Are you sure you want to cancel your registration for this assignment? (y/n): ",
            end=' ')
    else:
        print(
            "Are you sure you want to cancel this team's registration for the assignment? (y/n): ",
            end=' ')

    if not yes:
        yesno = input()
    else:
        yesno = 'y'
        print('y')

    if yesno in ('y', 'Y', 'yes', 'Yes', 'YES'):
        try:
            registration.cancel()
            print()
            print("Your registration has been cancelled.")
            ctx.exit(CHISUBMIT_SUCCESS)
        except BadRequestException as bre:
            response_data = bre.json
            print(
                "ERROR: Your registration cannot be cancelled. The server reported the following:"
            )
            print()
            bre.print_errors()

            ctx.exit(CHISUBMIT_FAIL)
Esempio n. 41
0
def instructor_assignment_stats(ctx, course, assignment_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    all_students = course.get_students()

    student_dict = {
        s.user.username: s.user
        for s in all_students if not s.dropped
    }
    students = set(student_dict.keys())
    dropped = set([s.user.username for s in all_students if s.dropped])

    teams_unconfirmed = []
    nteams = 0
    nstudents = len(student_dict)
    nstudents_assignment = 0
    nsubmissions = 0
    nstudents_submitted = 0
    unsubmitted = []

    teams = course.get_teams(include_students=True, include_assignments=True)

    for team in teams:
        try:
            registrations = team.get_assignment_registrations()
            registrations = [
                r for r in registrations if r.assignment_id == assignment_id
            ]
            if len(registrations) == 1:
                registration = registrations[0]
            else:
                continue
        except UnknownObjectException:
            continue

        unconfirmed = False
        includes_dropped = False
        team_members = team.get_team_members()
        for tm in team_members:
            if tm.username not in dropped:
                try:
                    students.remove(tm.username)
                    nstudents_assignment += 1
                    if not tm.confirmed:
                        unconfirmed = True
                except KeyError as ke:
                    print(
                        "WARNING: Student %s seems to be in more than one team (offending team: %s)"
                        % (tm.username, team.team_id))
            else:
                includes_dropped = True

        if not includes_dropped:
            nteams += 1

            if registration.final_submission is not None:
                nsubmissions += 1
                nstudents_submitted += len(team_members)
            else:
                unsubmitted.append(team)

        if unconfirmed:
            teams_unconfirmed.append(team)

    assert (nstudents == len(students) + nstudents_assignment)

    title = "Assignment '%s'" % (assignment.name)
    print(title)
    print("=" * len(title))

    print()
    print("%i / %i students in %i teams have signed up for assignment %s" %
          (nstudents_assignment, nstudents, nteams, assignment.assignment_id))
    print()
    print("%i / %i teams have submitted the assignment (%i students)" %
          (nsubmissions, nteams, nstudents_submitted))

    if ctx.obj["verbose"]:
        if len(students) > 0:
            print()
            print("Students who have not yet signed up")
            print("-----------------------------------")
            not_signed_up = [student_dict[sid] for sid in students]
            not_signed_up.sort(key=operator.attrgetter("last_name"))
            for s in not_signed_up:
                print("%s, %s <%s>" % (s.last_name, s.first_name, s.email))

        if len(unsubmitted) > 0:
            print()
            print("Teams that have not submitted")
            print("-----------------------------")
            for t in unsubmitted:
                print(t.team_id)

    return CHISUBMIT_SUCCESS
Esempio n. 42
0
def instructor_assignment_cancel_submit(ctx, course, team_id, assignment_id,
                                        yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
    team = get_team_or_exit(ctx, course, team_id)
    registration = get_assignment_registration_or_exit(
        ctx, team, assignment.assignment_id)

    if registration.final_submission is None:
        print("Team %s has not made a submission for assignment %s," %
              (team.team_id, assignment_id))
        print("so there is nothing to cancel.")
        ctx.exit(CHISUBMIT_FAIL)

    if registration.grader_username is not None:
        print("This submission has already been assigned a grader (%s)" %
              registration.grader_username)
        print(
            "Make sure the grader has been notified to discard this submission."
        )
        print(
            "You must also remove the existing grading branch from the staging server."
        )

        print("Are you sure you want to proceed? (y/n): ", end=' ')

        if not yes:
            yesno = input()
        else:
            yesno = 'y'
            print('y')

        if yesno not in ('y', 'Y', 'yes', 'Yes', 'YES'):
            ctx.exit(CHISUBMIT_FAIL)
        else:
            print()

    if is_submission_ready_for_grading(
            assignment_deadline=registration.assignment.deadline,
            submission_date=registration.final_submission.submitted_at,
            extensions_used=registration.final_submission.extensions_used):
        print(
            "WARNING: You are canceling a submission that is ready for grading!"
        )

    conn = create_connection(course, ctx.obj['config'])

    if conn is None:
        print("Could not connect to git server.")
        ctx.exit(CHISUBMIT_FAIL)

    submission_commit = conn.get_commit(
        course, team, registration.final_submission.commit_sha)

    print()
    print("This is the existing submission for assignment %s:" % assignment_id)
    print()
    if submission_commit is None:
        print(
            "WARNING: Previously submitted commit '%s' is not in the repository!"
            % registration.final_submission.commit_sha)
    else:
        print_commit(submission_commit)
    print()

    print("Are you sure you want to cancel this submission? (y/n): ", end=' ')

    if not yes:
        yesno = input()
    else:
        yesno = 'y'
        print('y')

    if yesno in ('y', 'Y', 'yes', 'Yes', 'YES'):
        registration.final_submission_id = None
        registration.grader_username = None
        registration.grading_started = False

        print()
        print("The submission has been cancelled.")
Esempio n. 43
0
def instructor_grading_show_grading_status(ctx, course, assignment_id,
                                           by_grader, include_diff_urls,
                                           use_stored_grades):
    assignment = get_assignment_or_exit(ctx,
                                        course,
                                        assignment_id,
                                        include_rubric=True)
    rubric_components = assignment.get_rubric_components()

    teams_registrations = get_teams_registrations(
        course, assignment, include_grades=use_stored_grades)
    teams = sorted(list(teams_registrations.keys()),
                   key=operator.attrgetter("team_id"))

    team_status = []
    graders = set()

    for team in teams:
        registration = teams_registrations[team]

        if registration.grader is None:
            grader_str = "<no grader assigned>"
        else:
            grader_str = registration.grader.user.username
        graders.add(grader_str)

        grading_status = None
        diff_url = ""

        if use_stored_grades:
            grades = registration.get_grades()
            total_grade = registration.get_total_grade()

            graded_rc_ids = [g.rubric_component_id for g in grades]
        else:
            total_grade = 0.0
            repo = GradingGitRepo.get_grading_repo(ctx.obj['config'], course,
                                                   team, registration)
            if repo is None:
                grading_status = "NO GRADING REPO"
            else:
                rubricfile = repo.repo_path + "/%s.rubric.txt" % assignment.assignment_id

                if not os.path.exists(rubricfile):
                    grading_status = "NOT GRADED - No rubric"
                else:
                    try:
                        rubric = RubricFile.from_file(open(rubricfile),
                                                      assignment)

                        graded_rc_ids = [
                            rc.id for rc in rubric_components if
                            rubric.points_obtained[rc.description] is not None
                        ]

                        total_grade = rubric.get_total_points_obtained()
                    except ChisubmitRubricException as cre:
                        grading_status = "ERROR: Rubric does not validate (%s)" % (
                            cre)

        if grading_status is None:
            has_some = False
            has_all = True
            for rc in rubric_components:
                if rc.id in graded_rc_ids:
                    has_some = True
                else:
                    has_all = False

            if not has_some:
                grading_status = "NOT GRADED"
            elif has_all:
                grading_status = "GRADED"
            else:
                grading_status = "PARTIALLY GRADED"

            if include_diff_urls and has_some:
                commit_sha = registration.final_submission.commit_sha[:8]
                diff_url = "https://mit.cs.uchicago.edu/%s-staging/%s/compare/%s...%s-grading" % (
                    course.course_id, team.team_id, commit_sha,
                    assignment.assignment_id)

        team_status.append(
            (team.team_id, grader_str, total_grade, diff_url, grading_status))

    if not by_grader:
        for team, grader, total_grade, diff_url, status in team_status:
            print("%-40s %-20s %-20.2f %10s  %s" %
                  (team, status, total_grade, grader, diff_url))
    else:
        all_grades = []
        for grader in sorted(list(graders)):
            print(grader)
            print("-" * len(grader))

            grades = []

            team_status_grader = [ts for ts in team_status if ts[1] == grader]

            for team, _, total_grade, diff_url, status in team_status_grader:
                if status == "NOT GRADED":
                    print("%-40s %s  %s" % (team, status, diff_url))
                else:
                    print("%-40s %s %8.2f  %s" %
                          (team, status, total_grade, diff_url))
                    if status == "GRADED":
                        grades.append(total_grade)

            if len(grades) > 0:
                all_grades += grades
                print_grades_stats(grades)
            print()

        if len(all_grades) > 0:
            print("TOTAL")
            print("-----")
            print_grades_stats(all_grades)

    return CHISUBMIT_SUCCESS
Esempio n. 44
0
def instructor_assignment_show_rubric(ctx, course, assignment_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    rubric = RubricFile.from_assignment(assignment)
    print(rubric.to_yaml())
Esempio n. 45
0
def instructor_grading_create_grading_repos(ctx, course, assignment_id,
                                            all_teams, only, master):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    teams_registrations = get_teams_registrations(
        course, assignment, only=only, only_ready_for_grading=not all_teams)

    if len(teams_registrations) == 0:
        print("There are no grading repos to create.")
        ctx.exit(CHISUBMIT_FAIL)

    teams = sorted(list(teams_registrations.keys()),
                   key=operator.attrgetter("team_id"))

    for team in teams:
        registration = teams_registrations[team]
        repo = GradingGitRepo.get_grading_repo(ctx.obj['config'], course, team,
                                               registration)

        if repo is None:
            print(("%40s -- Creating grading repo... " % team.team_id),
                  end=' ')

            try:
                repo = GradingGitRepo.create_grading_repo(
                    ctx.obj['config'],
                    course,
                    team,
                    registration,
                    staging_only=not master)
                repo.sync()
            except GitCommandError as gce:
                print(gce)

            if registration.final_submission is not None:
                if repo.has_grading_branch_staging():
                    if not registration.grading_started:
                        print(
                            "ERROR: This repo has a grading branch, but is not marked as ready for grading."
                        )
                    else:
                        gradingrepo_pull_grading_branch(
                            ctx.obj['config'], course, team, registration)
                        print("done")
                else:
                    if master:
                        repo.create_grading_branch()
                        registration.grading_started = True
                        print("done (and created grading branch)")
                    else:
                        print(
                            "done (warning: could not pull grading branch; it does not exist)"
                        )
            else:
                if registration.grading_started:
                    print(
                        "ERROR: This team has not submitted this assignment, but the repo is marked as ready for grading."
                    )
                else:
                    print("done (note: has not submitted yet)")
        else:
            print(("%40s -- Updating grading repo... " % team.team_id),
                  end=' ')
            if repo.has_grading_branch_staging():
                if not registration.grading_started:
                    print(
                        "ERROR: This repo has a grading branch, but is not marked as ready for grading."
                    )
                else:
                    try:
                        gradingrepo_pull_grading_branch(
                            ctx.obj['config'], course, team, registration)
                        print("done (pulled latest grading branch)")
                    except GitCommandError as gce:
                        print(gce)
            elif repo.has_grading_branch():
                print("nothing to update (grading branch is not in staging)")
            elif registration.final_submission is not None and master:
                try:
                    repo.create_grading_branch()
                    if not registration.grading_started:
                        registration.grading_started = True
                    print("done (created missing grading branch)")
                except GitCommandError as gce:
                    print(gce)
            else:
                print("nothing to update (there is no grading branch)")

    return CHISUBMIT_SUCCESS
Esempio n. 46
0
def student_assignment_cancel_submit(ctx, course, assignment_id, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    # Determine team for this assignment
    team, registration = get_team_registration_from_user(
        ctx, course, assignment)
    team_members = team.get_team_members()

    if len(team_members) == 1:
        individual = True
    else:
        individual = False

    if registration.final_submission is None:
        if individual:
            print("You have not made a submission for assignment %s," %
                  assignment_id)
        else:
            print("Team %s has not made a submission for assignment %s," %
                  (team.team_id, assignment_id))
        print("so there is nothing to cancel.")
        ctx.exit(CHISUBMIT_FAIL)

    if registration.grading_started:
        print("You cannot cancel this submission.")
        print(
            "You made a submission and it has already been sent to the graders for grading."
        )
        print(
            "Please contact an instructor if you wish to amend your submission."
        )

        ctx.exit(CHISUBMIT_FAIL)

    conn = create_connection(course, ctx.obj['config'])

    if conn is None:
        print("Could not connect to git server.")
        ctx.exit(CHISUBMIT_FAIL)

    submission_commit = conn.get_commit(
        course, team, registration.final_submission.commit_sha)

    print()
    print("This is your existing submission for assignment %s:" %
          assignment_id)
    print()
    if submission_commit is None:
        print(
            "WARNING: Previously submitted commit '%s' is not in the repository!"
            % registration.final_submission.commit_sha)
    else:
        print_commit(submission_commit)
    print()

    print("Are you sure you want to cancel this submission? (y/n): ", end=' ')

    if not yes:
        yesno = input()
    else:
        yesno = 'y'
        print('y')

    if yesno in ('y', 'Y', 'yes', 'Yes', 'YES'):
        registration.final_submission_id = None

        # TODO: Can't do this until GitLab supports updating tags
        #
        # message = "Extensions: %i\n" % extensions_requested
        # if submission_tag is None:
        #     conn.create_submission_tag(course, team, tag_name, message, commit.sha)
        # else:
        #     conn.update_submission_tag(course, team, tag_name, message, commit.sha)
        print()
        print("Your submission has been cancelled.")
Esempio n. 47
0
def instructor_grading_show_grading_status(ctx, course, assignment_id, by_grader, include_diff_urls, use_stored_grades):
    assignment = get_assignment_or_exit(ctx, course, assignment_id, include_rubric = True)
    rubric_components = assignment.get_rubric_components()

    teams_registrations = get_teams_registrations(course, assignment, include_grades = use_stored_grades)
    teams = sorted(list(teams_registrations.keys()), key=operator.attrgetter("team_id"))
    
    team_status = []
    graders = set()
    
    for team in teams:
        registration = teams_registrations[team]

        if registration.grader is None:
            grader_str = "<no grader assigned>"
        else:
            grader_str = registration.grader.user.username
        graders.add(grader_str)
        
        grading_status = None
        diff_url = ""
        
        if use_stored_grades:
            grades = registration.get_grades()
            total_grade = registration.get_total_grade()
            
            graded_rc_ids = [g.rubric_component_id for g in grades]            
        else:
            total_grade = 0.0
            repo = GradingGitRepo.get_grading_repo(ctx.obj['config'], course, team, registration)
            if repo is None:
                grading_status = "NO GRADING REPO"
            else:
                rubricfile = repo.repo_path + "/%s.rubric.txt" % assignment.assignment_id
        
                if not os.path.exists(rubricfile):
                    grading_status = "NOT GRADED - No rubric"
                else:        
                    try:
                        rubric = RubricFile.from_file(open(rubricfile), assignment)

                        graded_rc_ids = [rc.id for rc in rubric_components if rubric.points_obtained[rc.description] is not None]  
                
                        total_grade = rubric.get_total_points_obtained()
                    except ChisubmitRubricException as cre:
                        grading_status = "ERROR: Rubric does not validate (%s)" % (cre)
                        
        if grading_status is None:
            has_some = False
            has_all = True
            for rc in rubric_components:
                if rc.id in graded_rc_ids:
                    has_some = True
                else:
                    has_all = False
                            
            if not has_some:
                grading_status = "NOT GRADED"
            elif has_all:
                grading_status = "GRADED"
            else:
                grading_status = "PARTIALLY GRADED"

            
            if include_diff_urls and has_some:
                commit_sha = registration.final_submission.commit_sha[:8]
                diff_url = "https://mit.cs.uchicago.edu/%s-staging/%s/compare/%s...%s-grading" % (course.course_id, team.team_id, commit_sha, assignment.assignment_id)
            
        team_status.append((team.team_id, grader_str, total_grade, diff_url, grading_status))

    if not by_grader:
        for team, grader, total_grade, diff_url, status in team_status:
            print("%-40s %-20s %-20.2f %10s  %s" % (team, status, total_grade, grader, diff_url))
    else:
        all_grades = []
        for grader in sorted(list(graders)):
            print(grader)
            print("-" * len(grader))
            
            grades = []
            
            team_status_grader = [ts for ts in team_status if ts[1] == grader]
            
            for team, _, total_grade, diff_url, status in team_status_grader:
                if status == "NOT GRADED":
                    print("%-40s %s  %s" % (team, status, diff_url))
                else:
                    print("%-40s %s %8.2f  %s" % (team, status, total_grade, diff_url))
                    if status == "GRADED":
                        grades.append(total_grade)
                        
            if len(grades) > 0:
                all_grades += grades
                print_grades_stats(grades)
            print()

        if len(all_grades) > 0:
            print("TOTAL")
            print("-----")
            print_grades_stats(all_grades)

    return CHISUBMIT_SUCCESS
Esempio n. 48
0
def instructor_grading_collect_rubrics(ctx, course, assignment_id, dry_run, only, grader_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    if grader_id is not None:
        grader = get_grader_or_exit(ctx, course, grader_id)
    else:
        grader = None

    rcs = assignment.get_rubric_components()

    teams_registrations = get_teams_registrations(course, assignment, grader=grader, only=only)
    teams = sorted(teams_registrations.keys(), key=operator.attrgetter("team_id"))
    
    for team in teams:
        registration = teams_registrations[team]
        repo = GradingGitRepo.get_grading_repo(ctx.obj['config'], course, team, registration)
        if repo is None:
            print "Repository for %s does not exist" % (team.team_id)
            continue

        rubricfile = repo.repo_path + "/%s.rubric.txt" % assignment.assignment_id

        if not os.path.exists(rubricfile):
            print "Repository for %s does not have a rubric for assignment %s" % (team.team_id, assignment.assignment_id)
            continue

        try:
            rubric = RubricFile.from_file(open(rubricfile), assignment)
        except ChisubmitRubricException, cre:
            print "ERROR: Rubric for %s does not validate (%s)" % (team.team_id, cre.message)
            continue

        points = []
        for rc in rcs:
            grade = rubric.points[rc.description]
            if grade is None:
                points.append(0.0)
            else:
                if not dry_run:
                    registration.set_grade(rc, grade)
                points.append(grade)

        adjustments = {}
        total_penalties = 0.0
        total_bonuses = 0.0
        if rubric.penalties is not None:
            for desc, p in rubric.penalties.items():
                adjustments[desc] = p
                total_penalties += p

        if rubric.bonuses is not None:
            for desc, p in rubric.bonuses.items():
                adjustments[desc] = p
                total_bonuses += p

        if not dry_run:
            registration.grade_adjustments = adjustments

        if ctx.obj["verbose"]:
            print team.team_id
            print "Points Obtained: %s" % points
            print "Penalties: %.2f" % total_penalties
            print "Bonuses: %.2f" % total_bonuses

        if not dry_run:
            total_grade = registration.get_total_grade()
        else:
            total_grade = sum(points) + total_penalties + total_bonuses
            
        if ctx.obj["verbose"]:
            print "TOTAL: %.2f" % total_grade
            print
        else:
            print "%-40s %.2f" % (team.team_id, total_grade)
Esempio n. 49
0
def shared_assignment_set_attribute(ctx, course, assignment_id, attr_name, attr_value):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
    
    api_obj_set_attribute(ctx, assignment, attr_name, attr_value)
Esempio n. 50
0
def instructor_assignment_add_rubric_component(ctx, course, assignment_id,
                                               description, points):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
    assignment.create_rubric_component(description, points)

    return CHISUBMIT_SUCCESS
Esempio n. 51
0
def instructor_grading_assign_graders(ctx, course, assignment_id, from_assignment, avoid_assignment, grader_file, dry_run, reset):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    if from_assignment is not None:
        from_assignment = get_assignment_or_exit(ctx, course, from_assignment)

    if avoid_assignment is not None:
        avoid_assignment = get_assignment_or_exit(ctx, course, avoid_assignment)

    if reset and from_assignment is not None:
        print "--reset and --from_assignment are mutually exclusive"
        ctx.exit(CHISUBMIT_FAIL)

    if avoid_assignment is not None and from_assignment is not None:
        print "--avoid_assignment and --from_assignment are mutually exclusive"
        ctx.exit(CHISUBMIT_FAIL)

    if grader_file is not None:
        grader_workload = yaml.load(grader_file)
        graders = []
        
        for username in grader_workload:
            try:
                grader = course.get_grader(username)
                graders.append(grader)
            except UnknownObjectException:
                print "No such grader: %s" % username
                ctx.exit(CHISUBMIT_FAIL)
    else:
        graders = course.get_graders()
        grader_workload = {g.user.username: "******" for g in graders}

    if len(graders) == 0:
        print "ERROR: No graders."
        ctx.exit(CHISUBMIT_FAIL)
            
    teams_registrations = get_teams_registrations(course, assignment)
    teams = teams_registrations.keys()

    n_teams = len(teams)
    teams_per_grader = {}
    teams_per_grader_assigned = dict([(g.user.username, 0) for g in graders])    
    assigned = 0
    graders_assigned_remainder = []
    for username, workload in grader_workload.items():
        if workload != "remainder":
            if not isinstance(workload, int) or workload <= 0:
                print "Invalid workload for grader '%s': %s" % (username, workload)
            teams_per_grader[username] = workload
            assigned += workload
        else:
            teams_per_grader[username] = None
            graders_assigned_remainder.append(username)
                        
    min_teams_per_grader = (n_teams - assigned) / len(graders_assigned_remainder)
    extra_teams = (n_teams - assigned) % len(graders_assigned_remainder)

    for username in teams_per_grader:
        if teams_per_grader[username] is None:
            teams_per_grader[username] = min_teams_per_grader
            
    random.seed(course.course_id + assignment_id)
    random.shuffle(graders_assigned_remainder)

    # so many graders in this course that some will end up expecting zero
    # teams to grade. Make sure they are able to get at least one.
    for username in graders_assigned_remainder[:extra_teams]:
        teams_per_grader[username] += 1
    
    assert sum([v for v in teams_per_grader.values()]) == n_teams

    team_grader = {t.team_id: None for t in teams_registrations.keys()}

    if from_assignment is not None:
        from_assignment_registrations = get_teams_registrations(course, from_assignment)
        
        common_teams = [t for t in teams if teams_registrations.has_key(t) and from_assignment_registrations.has_key(t)]
        for t in common_teams:
            registration = from_assignment_registrations[t]

            # try to assign the same grader that would grade the same team's other assignment
            grader = registration.grader
            if grader is not None and teams_per_grader[grader.user.username] > 0:
                team_grader[t.team_id] = grader.user.username 
                teams_per_grader[grader.user.username] -= 1
                teams_per_grader_assigned[grader.user.username] += 1

    if avoid_assignment is not None:
        avoid_assignment_registrations = get_teams_registrations(course, avoid_assignment)

    if not reset:
        for t in teams:
            if teams_registrations[t].grader is None:
                team_grader[t.team_id] = None
            else:
                grader_id = teams_registrations[t].grader.user.username
                team_grader[t.team_id] = grader_id
                teams_per_grader[grader_id] = max(0, teams_per_grader[grader_id] - 1)
                teams_per_grader_assigned[grader_id] += 1

    not_ready_for_grading = []
    ta_avoid = {}
    graders_cycle = itertools.cycle(graders)
    for team, registration in teams_registrations.items():
        if team_grader[team.team_id] is not None:
            continue

        if not registration.is_ready_for_grading():
            not_ready_for_grading.append(team.team_id)
            continue

        for g in graders_cycle:
            if teams_per_grader[g.user.username] == 0:
                continue
            else:
                if avoid_assignment is not None:
                    avoid_registration = ta_avoid.setdefault(team.team_id, avoid_assignment_registrations.get(team))
                    if avoid_registration is not None and avoid_registration.grader.user.username == grader.user.username:
                        continue
                
                valid = True
                for tm in team.get_team_members():
                    conflicts = g.get_conflicts()
                    if tm.username in conflicts:
                        valid = False
                        break

                if valid:
                    team_grader[team.team_id] = g.user.username 
                    teams_per_grader[g.user.username] -= 1
                    teams_per_grader_assigned[g.user.username] += 1                        
                    break                    
    
    for team, registration in teams_registrations.items():
        if team_grader[team.team_id] is None:
            if team.team_id not in not_ready_for_grading:
                print "Team %s has no grader" % (team.team_id)
            else:
                print "Team %s's submission isn't ready for grading yet" % (team.team_id)
        else:
            if not dry_run:
                if registration.grader_username != team_grader[team.team_id]:
                    registration.grader_username = team_grader[team.team_id]
            else:
                print "%s: %s" % (team.team_id, team_grader[team.team_id])
    print 
    for grader_id, assigned in teams_per_grader_assigned.items():
        if teams_per_grader[grader_id] != 0:
            print grader_id, assigned, "(still needs to be assigned %i more assignments)" % (teams_per_grader[grader_id])
        else:
            print grader_id, assigned

    return CHISUBMIT_SUCCESS
Esempio n. 52
0
def instructor_grading_collect_rubrics(ctx, course, assignment_id, dry_run,
                                       only, grader_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)

    if grader_id is not None:
        grader = get_grader_or_exit(ctx, course, grader_id)
    else:
        grader = None

    rcs = assignment.get_rubric_components()

    teams_registrations = get_teams_registrations(course,
                                                  assignment,
                                                  grader=grader,
                                                  only=only)
    teams = sorted(list(teams_registrations.keys()),
                   key=operator.attrgetter("team_id"))

    for team in teams:
        registration = teams_registrations[team]
        repo = GradingGitRepo.get_grading_repo(ctx.obj['config'], course, team,
                                               registration)
        if repo is None:
            print("Repository for %s does not exist" % (team.team_id))
            continue

        rubricfile = repo.repo_path + "/%s.rubric.txt" % assignment.assignment_id

        if not os.path.exists(rubricfile):
            print(
                "Repository for %s does not have a rubric for assignment %s" %
                (team.team_id, assignment.assignment_id))
            continue

        try:
            rubric = RubricFile.from_file(open(rubricfile), assignment)
        except ChisubmitRubricException as cre:
            print("ERROR: Rubric for %s does not validate (%s)" %
                  (team.team_id, cre))
            continue

        points = []
        for rc in rcs:
            grade = rubric.points_obtained[rc.description]
            if grade is None:
                points.append(0.0)
            else:
                if not dry_run:
                    registration.set_grade(rc, grade)
                points.append(grade)

        adjustments = {}
        total_penalties = 0.0
        total_bonuses = 0.0
        if rubric.penalties is not None:
            for desc, p in list(rubric.penalties.items()):
                adjustments[desc] = p
                total_penalties += p

        if rubric.bonuses is not None:
            for desc, p in list(rubric.bonuses.items()):
                adjustments[desc] = p
                total_bonuses += p

        if not dry_run:
            registration.grade_adjustments = adjustments

        if ctx.obj["verbose"]:
            print(team.team_id)
            print("Points Obtained: %s" % points)
            print("Penalties: %.2f" % total_penalties)
            print("Bonuses: %.2f" % total_bonuses)

        if not dry_run:
            total_grade = registration.get_total_grade()
        else:
            total_grade = sum(points) + total_penalties + total_bonuses

        if ctx.obj["verbose"]:
            print("TOTAL: %.2f" % total_grade)
            print()
        else:
            print("%-40s %.2f" % (team.team_id, total_grade))
Esempio n. 53
0
def instructor_assignment_stats(ctx, course, assignment_id):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
             
    all_students = course.get_students()
         
    student_dict = {s.user.username: s.user for s in all_students if not s.dropped}
    students = set(student_dict.keys())
    dropped = set([s.user.username for s in all_students if s.dropped])
    
    teams_unconfirmed = []
    nteams = 0
    nstudents = len(student_dict)
    nstudents_assignment = 0
    nsubmissions = 0
    nstudents_submitted = 0
    unsubmitted = []
    
    teams = course.get_teams(include_students=True, include_assignments=True)

    for team in teams:
        try:
            registrations = team.get_assignment_registrations()
            registrations = [r for r in registrations if r.assignment_id == assignment_id]
            if len(registrations) == 1:
                registration = registrations[0]
            else:
                continue
        except UnknownObjectException:
            continue
        
        unconfirmed = False
        includes_dropped = False
        team_members = team.get_team_members()
        for tm in team_members:
            if tm.username not in dropped:
                try:
                    students.remove(tm.username)
                    nstudents_assignment += 1
                    if not tm.confirmed:
                        unconfirmed = True
                except KeyError as ke:
                    print("WARNING: Student %s seems to be in more than one team (offending team: %s)" % (tm.username, team.team_id))
            else:
                includes_dropped = True

        if not includes_dropped:
            nteams += 1
            
            if registration.final_submission is not None:
                nsubmissions += 1
                nstudents_submitted += len(team_members)
            else:
                unsubmitted.append(team)
            
        if unconfirmed:
            teams_unconfirmed.append(team)
                
    assert(nstudents == len(students) + nstudents_assignment)                
            
    title = "Assignment '%s'" % (assignment.name)
    print(title)
    print("=" * len(title))
               
    print() 
    print("%i / %i students in %i teams have signed up for assignment %s" % (nstudents_assignment, nstudents, nteams, assignment.assignment_id))
    print()
    print("%i / %i teams have submitted the assignment (%i students)" % (nsubmissions, nteams, nstudents_submitted))
    
    if ctx.obj["verbose"]:
        if len(students) > 0:
            print()
            print("Students who have not yet signed up")
            print("-----------------------------------")
            not_signed_up = [student_dict[sid] for sid in students]
            not_signed_up.sort(key=operator.attrgetter("last_name"))
            for s in not_signed_up:
                print("%s, %s <%s>" % (s.last_name, s.first_name, s.email))
                
        if len(unsubmitted) > 0:
            print()
            print("Teams that have not submitted")
            print("-----------------------------")
            for t in unsubmitted:
                print(t.team_id)
                
    return CHISUBMIT_SUCCESS
Esempio n. 54
0
def instructor_grading_create_grading_repos(ctx, course, assignment_id, all_teams, only, master):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
    
    teams_registrations = get_teams_registrations(course, assignment, only = only, only_ready_for_grading=not all_teams)

    if len(teams_registrations) == 0:
        print("There are no grading repos to create.")
        ctx.exit(CHISUBMIT_FAIL)
        
    teams = sorted(list(teams_registrations.keys()), key=operator.attrgetter("team_id"))

    for team in teams:
        registration = teams_registrations[team]
        repo = GradingGitRepo.get_grading_repo(ctx.obj['config'], course, team, registration)
        
        if repo is None:
            print(("%40s -- Creating grading repo... " % team.team_id), end=' ')
                
            try:
                repo = GradingGitRepo.create_grading_repo(ctx.obj['config'], course, team, registration, staging_only = not master)
                repo.sync()
            except GitCommandError as gce:
                print(gce)                 
            
            if registration.final_submission is not None:        
                if repo.has_grading_branch_staging():
                    if not registration.grading_started:
                        print("ERROR: This repo has a grading branch, but is not marked as ready for grading.")
                    else:
                        gradingrepo_pull_grading_branch(ctx.obj['config'], course, team, registration)
                        print("done")
                else:
                    if master:
                        repo.create_grading_branch()
                        registration.grading_started = True
                        print("done (and created grading branch)")
                    else:
                        print("done (warning: could not pull grading branch; it does not exist)")
            else:
                if registration.grading_started:
                    print("ERROR: This team has not submitted this assignment, but the repo is marked as ready for grading.")
                else:
                    print("done (note: has not submitted yet)")
        else:
            print(("%40s -- Updating grading repo... " % team.team_id), end=' ')
            if repo.has_grading_branch_staging():
                if not registration.grading_started:
                    print("ERROR: This repo has a grading branch, but is not marked as ready for grading.")
                else:                
                    try:
                        gradingrepo_pull_grading_branch(ctx.obj['config'], course, team, registration)
                        print("done (pulled latest grading branch)")
                    except GitCommandError as gce:
                        print(gce)         
            elif repo.has_grading_branch():
                print("nothing to update (grading branch is not in staging)")
            elif registration.final_submission is not None and master:
                try:
                    repo.create_grading_branch()
                    if not registration.grading_started:
                        registration.grading_started = True
                    print("done (created missing grading branch)")
                except GitCommandError as gce:
                    print(gce)
            else:
                print("nothing to update (there is no grading branch)")

    return CHISUBMIT_SUCCESS
Esempio n. 55
0
def instructor_assignment_cancel_submit(ctx, course, team_id, assignment_id, yes):
    assignment = get_assignment_or_exit(ctx, course, assignment_id)
    team = get_team_or_exit(ctx, course, team_id)
    registration = get_assignment_registration_or_exit(ctx, team, assignment.assignment_id)
        
    if registration.final_submission is None:
        print("Team %s has not made a submission for assignment %s," % (team.team_id, assignment_id))
        print("so there is nothing to cancel.")
        ctx.exit(CHISUBMIT_FAIL)
        
    if registration.grader_username is not None:
        print("This submission has already been assigned a grader (%s)" % registration.grader_username)
        print("Make sure the grader has been notified to discard this submission.")
        print("You must also remove the existing grading branch from the staging server.")
        
        print("Are you sure you want to proceed? (y/n): ", end=' ') 
        
        if not yes:
            yesno = input()
        else:
            yesno = 'y'
            print('y')
        
        if yesno not in ('y', 'Y', 'yes', 'Yes', 'YES'):
            ctx.exit(CHISUBMIT_FAIL)
        else:
            print()
        
    if is_submission_ready_for_grading(assignment_deadline=registration.assignment.deadline, 
                                       submission_date=registration.final_submission.submitted_at,
                                       extensions_used=registration.final_submission.extensions_used):
        print("WARNING: You are canceling a submission that is ready for grading!")
            
    conn = create_connection(course, ctx.obj['config'])
    
    if conn is None:
        print("Could not connect to git server.")
        ctx.exit(CHISUBMIT_FAIL)
        
    submission_commit = conn.get_commit(course, team, registration.final_submission.commit_sha)
        
    print()
    print("This is the existing submission for assignment %s:" % assignment_id)
    print()
    if submission_commit is None:
        print("WARNING: Previously submitted commit '%s' is not in the repository!" % registration.final_submission.commit_sha)
    else:
        print_commit(submission_commit)
    print()    

    print("Are you sure you want to cancel this submission? (y/n): ", end=' ') 
    
    if not yes:
        yesno = input()
    else:
        yesno = 'y'
        print('y')
    
    if yesno in ('y', 'Y', 'yes', 'Yes', 'YES'):
        registration.final_submission_id = None
        registration.grader_username = None
        registration.grading_started = False
        
        print()
        print("The submission has been cancelled.")
Esempio n. 56
0
def instructor_team_pull_repos(ctx, course, directory, assignment,
                               only_ready_for_grading, reset, only):
    if only_ready_for_grading and assignment is None:
        print(
            "--only-ready-for-grading can only be used with --assignment option"
        )
        ctx.exit(CHISUBMIT_FAIL)

    if assignment is not None:
        assignment = get_assignment_or_exit(ctx, course, assignment)

    conn = create_connection(course, ctx.obj['config'])

    directory = os.path.expanduser(directory)
    if not os.path.exists(directory):
        os.makedirs(directory)

    if assignment is None:
        teams = sorted(course.get_teams(), key=operator.attrgetter("team_id"))
    else:
        teams_registrations = get_teams_registrations(course,
                                                      assignment,
                                                      only=only)
        teams = sorted(
            [t for t in list(teams_registrations.keys()) if t.active],
            key=operator.attrgetter("team_id"))

    max_len = max([len(t.team_id) for t in teams])

    for team in teams:
        team_dir = "%s/%s" % (directory, team.team_id)
        team_git_url = conn.get_repository_git_url(course, team)

        if only_ready_for_grading:
            registration = teams_registrations[team]

            if not registration.is_ready_for_grading(
            ) and only_ready_for_grading:
                print("%-*s  SKIPPING (not ready for grading)" %
                      (max_len, team.team_id))
                continue

        try:
            msg = ""
            if not os.path.exists(team_dir):
                r = LocalGitRepo.create_repo(team_dir,
                                             clone_from_url=team_git_url)
                msg = "Cloned repo"
            else:
                r = LocalGitRepo(team_dir)
                if reset:
                    r.fetch("origin")
                    r.reset_branch("origin", "master")
                    msg = "Reset to match origin/master"
                else:
                    if r.repo.is_dirty():
                        print(
                            "%-*s  ERROR: Cannot pull. Local repository has unstaged changes."
                            % (max_len, team.team_id))
                        continue
                    r.checkout_branch("master")
                    r.pull("origin", "master")
                    msg = "Pulled latest changes"
            if only_ready_for_grading:
                r.checkout_commit(registration.final_submission.commit_sha)
                msg += " and checked out commit %s" % (
                    registration.final_submission.commit_sha)
            print("%-*s  %s" % (max_len, team.team_id, msg))
        except ChisubmitException as ce:
            print(
                "%-*s  ERROR: Could not checkout or pull master branch (%s)" %
                (max_len, team.team_id, ce))
        except GitCommandError as gce:
            print("%-*s  ERROR: Could not checkout or pull master branch" %
                  (max_len, team.team_id))
            print(gce)
        except InvalidGitRepositoryError as igre:
            print(
                "%-*s  ERROR: Directory %s exists but does not contain a valid git repository"
                % (max_len, team.team_id, team_dir))
        except Exception as e:
            print(
                "%-*s  ERROR: Unexpected exception when trying to checkout/pull"
                % (max_len, team.team_id))
            raise

    return CHISUBMIT_SUCCESS
Esempio n. 57
0
def instructor_team_pull_repos(ctx, course, directory, assignment, only_ready_for_grading, reset, only):
    if only_ready_for_grading and assignment is None:
        print("--only-ready-for-grading can only be used with --assignment option")
        ctx.exit(CHISUBMIT_FAIL)
    
    if assignment is not None:
        assignment = get_assignment_or_exit(ctx, course, assignment)

    conn = create_connection(course, ctx.obj['config'])

    directory = os.path.expanduser(directory)
    if not os.path.exists(directory):
        os.makedirs(directory)
    
    if assignment is None:
        teams = sorted(course.get_teams(), key = operator.attrgetter("team_id"))
    else:
        teams_registrations = get_teams_registrations(course, assignment, only = only)
        teams = sorted([t for t in list(teams_registrations.keys()) if t.active], key = operator.attrgetter("team_id"))

    max_len = max([len(t.team_id) for t in teams])

    for team in teams:
        team_dir = "%s/%s" % (directory, team.team_id)
        team_git_url = conn.get_repository_git_url(course, team) 

        if only_ready_for_grading:
            registration = teams_registrations[team]
    
            if not registration.is_ready_for_grading() and only_ready_for_grading:
                print("%-*s  SKIPPING (not ready for grading)" % (max_len, team.team_id))
                continue
        
        try:
            msg = ""
            if not os.path.exists(team_dir):
                r = LocalGitRepo.create_repo(team_dir, clone_from_url=team_git_url)
                msg = "Cloned repo"
            else:
                r = LocalGitRepo(team_dir)
                if reset:
                    r.fetch("origin")
                    r.reset_branch("origin", "master")
                    msg = "Reset to match origin/master" 
                else:
                    if r.repo.is_dirty():
                        print("%-*s  ERROR: Cannot pull. Local repository has unstaged changes." % (max_len, team.team_id))
                        continue
                    r.checkout_branch("master")
                    r.pull("origin", "master")
                    msg = "Pulled latest changes"
            if only_ready_for_grading:
                r.checkout_commit(registration.final_submission.commit_sha)
                msg += " and checked out commit %s" % (registration.final_submission.commit_sha)               
            print("%-*s  %s" % (max_len, team.team_id, msg))
        except ChisubmitException as ce:
            print("%-*s  ERROR: Could not checkout or pull master branch (%s)" % (max_len, team.team_id, ce))
        except GitCommandError as gce:
            print("%-*s  ERROR: Could not checkout or pull master branch" % (max_len, team.team_id))
            print(gce)
        except InvalidGitRepositoryError as igre:
            print("%-*s  ERROR: Directory %s exists but does not contain a valid git repository"  % (max_len, team.team_id, team_dir))
        except Exception as e:
            print("%-*s  ERROR: Unexpected exception when trying to checkout/pull" % (max_len, team.team_id))
            raise
    
    return CHISUBMIT_SUCCESS