def main(): setup_logging() args, parser = parse_args() if "none" == args.which: parser.print_help() elif "ungraded" == args.which: submissions_status = submissions_statistics( args.course_id, is_verbose=args.verbose, download_folder=args.download_folder, ) print("Total ungraded: {}".format( submissions_status["total_ungraded"])) elif args.which == "list_students": pprint(get_students(args.course_id)) elif "feedbacks" == args.which: export_feedbacks(args.course_id, Path(args.download_folder)) elif "export" == args.which: export_all(args.course_id, Path(args.download_folder)) elif "student_report" == args.which: student_statuses = status_report(args.course_id) headers = ("Student", "Submissions", "Last Submission") print(tabulate(student_statuses, headers, tablefmt="pretty"))
def status_report(course_id): """ Generates a short report of the students for a specific course. Returns a list of StudentStatus tuples. """ assignments = get_assignments(course_id) users_map = get_students(course_id) submissions_by_user = Counter() last_submission_by_user = defaultdict( lambda: SubmissionTuple(name="Nothing", timestamp=0)) for assignment in assignments: for submission in assignment.submissions: user_name = users_map[submission.user_id] submissions_by_user[user_name] += 1 if (last_submission_by_user[user_name].timestamp < submission.timestamp): last_submission_by_user[user_name] = SubmissionTuple( name=assignment.name, timestamp=submission.timestamp) student_statuses = [] for user, submission_count in submissions_by_user.items(): student_statuses.append( StudentStatus(user, submission_count, last_submission_by_user[user].name)) student_statuses = sorted( student_statuses, key=lambda student_status: student_status.total_submissions, ) return student_statuses
def export_submissions(course_id, download_folder): """ Downloads all submissions from a given course """ assignments = get_assignments(course_id) users_map = get_students(course_id) for assignment in assignments: for submission in assignment.submissions: download_submission( assignment.name, users_map[submission.user_id], submission, download_folder, )
def lock_submissions(self, course_id, students_names=None): """ Locking submissions for this specific assignment. """ if students_names is None: students_ids = list(get_students(course_id).keys()) else: students_ids = get_students_ids_by_name(course_id, students_names) if not students_ids: logger.warning("No student was found! Aborting...") else: mod_assign_lock_submissions(self.uid, students_ids) logger.info( "Locked submissions for assignment '%s' for %s", self.name, students_names if students_names is not None else "all students.", )
def submissions_statistics(course_id, is_verbose=False, download_folder=None): """ Returns a dictionary describing the status of ungraded exercises in the course. The dictionary looks like this: ``` { 'total_submissions': 10, 'total_ungraded': 5, 'total_resubmissions': 2, 'exercises': { 'assign1': { 'submissions': 2, 'ungraded': 2, 'resubmissions': 0} }, ... } } ``` If download_folder is set, downloads the ungraded exercises """ logger.info("Showing ungraded submissions for course %s", course_id) total_submissions = 0 total_ungraded = 0 total_resubmissions = 0 assignments_statistics = {} assignments = get_assignments(course_id) users_map = get_students(course_id) for assignment in assignments: current_assignment_submissions_amount = len(assignment.submissions) current_assignment_ungraded = assignment.ungraded() current_assignment_ungraded_amount = len(current_assignment_ungraded) current_assignment_resubmissions_amount = 0 ungraded_ignored = [] for submission in current_assignment_ungraded: if submission.resubmitted: current_assignment_resubmissions_amount += 1 if submission.user_id in STUDENTS_TO_IGNORE.keys(): ungraded_ignored.append(STUDENTS_TO_IGNORE[submission.user_id]) if download_folder is not None: download_submission( assignment.name, users_map[submission.user_id], submission, download_folder, ) total_submissions += current_assignment_submissions_amount total_ungraded += current_assignment_ungraded_amount total_resubmissions += current_assignment_resubmissions_amount # Print total stats about this assignment if is_verbose and len(ungraded_ignored) != 0: logger.info( "Ignored %s submissions for assignment '%s' (CMID %s, ID %s): %s", len(ungraded_ignored), assignment.name, assignment.cmid, assignment.uid, ungraded_ignored, ) amount_ungraded_not_ignored = current_assignment_ungraded_amount - len( ungraded_ignored) if amount_ungraded_not_ignored != 0: logger.info( "Total ungraded for assignment [%s] (CMID %s, ID %s): %s/%s", assignment.name, assignment.cmid, assignment.uid, amount_ungraded_not_ignored, len(assignment.submissions), ) assignments_statistics[assignment.name] = { "submissions": current_assignment_submissions_amount, "ungraded": amount_ungraded_not_ignored, "resubmissions": current_assignment_resubmissions_amount, } return { "total_submissions": total_submissions, "total_ungraded": total_ungraded, "total_resubmissions": total_resubmissions, "exercises": assignments_statistics, }