diff --git a/analyze_grades.py b/analyze_grades.py index aa2e9e20f3d40d550e6de94ec531d6ccd03fc324..3eaa57fb576d85c5b53b45f6a823968b2c550974 100755 --- a/analyze_grades.py +++ b/analyze_grades.py @@ -49,7 +49,9 @@ def create_semester_filter() -> str: return f'1{str(year)[-2:]}{month}' # introducing a y2.1k problem -def select_students_for_material_collection(assignment, student_subset) -> Tuple[CanvasUser, CanvasUser, CanvasUser]: +def select_students_for_material_collection(assignment, + scores: Dict[CanvasUser, Optional[float]], + student_subset) -> Tuple[CanvasUser, CanvasUser, CanvasUser]: points_possible: float = assignment.get_points_possible() grade_thresholds: Dict[str, float] = { 'A': 0.93 * points_possible, @@ -66,37 +68,39 @@ def select_students_for_material_collection(assignment, student_subset) -> Tuple c_student: Optional[CanvasUser] = None candidates_for_material_collection: Set[CanvasUser] = \ {student for student in student_subset - if assignment.get_score(student) is not None - and assignment.get_score(student) >= grade_thresholds['A']} + if scores[student] is not None + and scores[student] >= grade_thresholds['A']} if len(candidates_for_material_collection) == 0: candidates_for_material_collection = \ {student for student in student_subset - if assignment.get_score(student) is not None - and assignment.get_score(student) >= grade_thresholds['A-']} + if scores[student] is not None + and scores[student] >= grade_thresholds['A-']} if len(candidates_for_material_collection) > 0: a_student = candidates_for_material_collection.pop() candidates_for_material_collection = \ - {student for student in student_subset if assignment.get_score(student) is not None - and grade_thresholds['B'] <= assignment.get_score(student) < grade_thresholds['B+']} + {student for student in student_subset if scores[student] is not None + and grade_thresholds['B'] <= scores[student] < grade_thresholds['B+']} if len(candidates_for_material_collection) == 0: candidates_for_material_collection = \ - {student for student in student_subset if assignment.get_score(student) is not None - and grade_thresholds['B-'] <= assignment.get_score(student) < grade_thresholds['A-']} + {student for student in student_subset if scores[student] is not None + and grade_thresholds['B-'] <= scores[student] < grade_thresholds['A-']} if len(candidates_for_material_collection) > 0: b_student = candidates_for_material_collection.pop() candidates_for_material_collection = \ - {student for student in student_subset if assignment.get_score(student) is not None - and grade_thresholds['C'] <= assignment.get_score(student) < grade_thresholds['C+']} + {student for student in student_subset if scores[student] is not None + and grade_thresholds['C'] <= scores[student] < grade_thresholds['C+']} if len(candidates_for_material_collection) == 0: candidates_for_material_collection = \ - {student for student in student_subset if assignment.get_score(student) is not None - and grade_thresholds['C-'] <= assignment.get_score(student) < grade_thresholds['B-']} + {student for student in student_subset if scores[student] is not None + and grade_thresholds['C-'] <= scores[student] < grade_thresholds['B-']} if len(candidates_for_material_collection) > 0: c_student = candidates_for_material_collection.pop() return a_student, b_student, c_student -def print_sample_scores(assignment: CanvasAssignment, majors: Set[Major], +def print_sample_scores(assignment: CanvasAssignment, + scores: Dict[CanvasUser, Optional[float]], + majors: Set[Major], major_partitions: Dict[Major, Set[CanvasUser]], students: Optional[List[CanvasUser]] = None) -> None: points_possible: float = assignment.get_points_possible() @@ -104,7 +108,7 @@ def print_sample_scores(assignment: CanvasAssignment, majors: Set[Major], b_student: Optional[CanvasUser] = None c_student: Optional[CanvasUser] = None for major in majors: - student_subset: Set[CanvasUser] = major_partitions[major] if students is None \ + student_subset: Set[CanvasUser] = major_partitions[major].copy() if students is None \ else major_partitions[major].intersection(students) selected_students: Set[CanvasUser] = set() if len(student_subset) == 0: @@ -112,12 +116,14 @@ def print_sample_scores(assignment: CanvasAssignment, majors: Set[Major], elif len(student_subset) <= 30: print(f'{major.name} has {len(student_subset)} students: reporting scores for all students.') selected_students = student_subset - a_student, b_student, c_student = select_students_for_material_collection(assignment, student_subset) + a_student, b_student, c_student = select_students_for_material_collection(assignment, scores, + student_subset) else: print( f'{major.name} has {len(student_subset)} students: reporting scores for 30 randomly-selected students.') # let's make sure there are an 'A', a 'B', and a 'C' student in the mix - a_student, b_student, c_student = select_students_for_material_collection(assignment, student_subset) + a_student, b_student, c_student = select_students_for_material_collection(assignment, scores, + student_subset) for student in (a_student, b_student, c_student): if student is not None: student_subset.remove(student) @@ -127,27 +133,29 @@ def print_sample_scores(assignment: CanvasAssignment, majors: Set[Major], selected_students.add(student) i = 1 for student in selected_students: - print(f'Student {i:>2} -- raw score: {assignment.get_score(student)}' - f'\tscaled score: {100 * assignment.get_score(student) / points_possible}') + print(f'Student {i:>2} -- raw score: {scores[student]}' + f'\tscaled score: {100 * scores[student] / points_possible}') + i += 1 print('Collect sample materials --') - print(f'"A" student: {a_student.get_name()}') - print(f'"B" student: {b_student.get_name()}') - print(f'"C" student: {c_student.get_name()}') - i += 1 + print(f'"A" student: {a_student.get_name() if a_student is not None else a_student}') + print(f'"B" student: {b_student.get_name() if b_student is not None else b_student}') + print(f'"C" student: {c_student.get_name() if c_student is not None else c_student}') print() -def print_statistics_for_some_majors(assignment: CanvasAssignment, majors: Set[Major], +def print_statistics_for_some_majors(assignment: CanvasAssignment, + scores: Dict[CanvasUser, Optional[float]], + majors: Set[Major], major_partitions: Dict[Major, Set[CanvasUser]], students: Optional[List[CanvasUser]] = None) -> None: points_possible: float = assignment.get_points_possible() for major in majors: student_subset: Set[CanvasUser] = major_partitions[major] if students is None \ else major_partitions[major].intersection(students) - scores: List[float] = [assignment.get_score(student) for student in student_subset - if assignment.get_score(student) is not None] + valued_scores: List[float] = [scores[student] for student in student_subset + if scores[student] is not None] try: - average_score: float = statistics.mean(scores) + average_score: float = statistics.mean(valued_scores) scaled_average_score: float = 100 * average_score / points_possible print(f'{major.name:27}students:{len(major_partitions[major]):>3} ' f'scaled mean score: {scaled_average_score:.2f}%') @@ -155,20 +163,24 @@ def print_statistics_for_some_majors(assignment: CanvasAssignment, majors: Set[M print(f'{major.name:27}students:{len(major_partitions[major]):>3} no mean score computed: {exception}') -def print_statistics(assignment: CanvasAssignment, major_partitions: Dict[Major, Set[CanvasUser]]) -> None: +def print_statistics(assignment: CanvasAssignment, + scores: Dict[CanvasUser, Optional[float]], + major_partitions: Dict[Major, Set[CanvasUser]]) -> None: if assignment.get_points_possible() == 0: print(f'WARNING: {assignment} is a 0-point assignment; cannot compute scaled mean score.') else: print(f'Statistics for {assignment}:') computing_majors: Set[Major] = {major for major in Major.majors if major.is_computing_major} non_computing_majors: Set[Major] = {major for major in major_partitions.keys() if not major.is_computing_major} - print_statistics_for_some_majors(assignment, computing_majors, major_partitions) - print_statistics_for_some_majors(assignment, non_computing_majors, major_partitions) + print_statistics_for_some_majors(assignment, scores, computing_majors, major_partitions) + print_statistics_for_some_majors(assignment, scores, non_computing_majors, major_partitions) print() - print_sample_scores(assignment, computing_majors, major_partitions) + print_sample_scores(assignment, scores, computing_majors, major_partitions) -def print_statistics_by_section(course: CanvasCourse, assignment: CanvasAssignment, +def print_statistics_by_section(course: CanvasCourse, + assignment: CanvasAssignment, + scores: Dict[CanvasUser, Optional[float]], major_partitions: Dict[Major, Set[CanvasUser]]) -> None: print(f'Statistics for {assignment}:') computing_majors: Set[Major] = {major for major in Major.majors if major.is_computing_major} @@ -182,10 +194,10 @@ def print_statistics_by_section(course: CanvasCourse, assignment: CanvasAssignme for student in students: non_computing_majors.update({major for major in all_non_computing_majors if student in major_partitions[major]}) - print_statistics_for_some_majors(assignment, computing_majors, major_partitions, students) - print_statistics_for_some_majors(assignment, non_computing_majors, major_partitions, students) + print_statistics_for_some_majors(assignment, scores, computing_majors, major_partitions, students) + print_statistics_for_some_majors(assignment, scores, non_computing_majors, major_partitions, students) print() - print_sample_scores(assignment, computing_majors, major_partitions, students) + print_sample_scores(assignment, scores, computing_majors, major_partitions, students) print() @@ -197,10 +209,18 @@ def assess_assignments(course: CanvasCourse, major_partitions: Dict[Major, Set[C assignment_group: CanvasAssignmentGroup = \ select_from_list(course.get_assignment_groups(), 'assignment group') oat_assignment: CanvasAssignment = select_from_list(assignment_group.get_assignments(), 'assignment') + assignment_scores: Dict[CanvasUser, Optional[float]] = {} + print('Retrieving scores ', end='') + sys.stdout.flush() + for student in course.get_students(): + print('.', end='') + sys.stdout.flush() + assignment_scores[student] = oat_assignment.get_score(student) + print() if not print_section_statistics: - print_statistics(oat_assignment, major_partitions) + print_statistics(oat_assignment, assignment_scores, major_partitions) else: - print_statistics_by_section(course, oat_assignment, major_partitions) + print_statistics_by_section(course, oat_assignment, assignment_scores, major_partitions) print() answer = input('Assess additional assignments? [Y/n] ')