Skip to content

Instantly share code, notes, and snippets.

@Steven24K
Last active June 1, 2026 12:14
Show Gist options
  • Select an option

  • Save Steven24K/589cf661039af4606feb223fd655598f to your computer and use it in GitHub Desktop.

Select an option

Save Steven24K/589cf661039af4606feb223fd655598f to your computer and use it in GitHub Desktop.
import csv
import math
def safe_float(x):
try:
return float(x)
except (ValueError, TypeError):
return None
def safe_div(x, y):
if y == 0: return 0
return x / y
class Student:
def __init__(self, _id, _name, _assignments):
self.id = _id
self.name = _name
self.assignments = _assignments
def total(self):
return len(self.assignments)
def completed_list(self):
return [a for a in self.assignments if a[1] is not None]
def total_completed(self):
return len(self.completed_list())
def avg_grade(self):
grades = [a[1] for a in self.completed_list()]
return round(safe_div(sum(grades), self.total_completed()), 2)
def completion_percentage(self):
if self.total() == 0: return 0
return math.floor((self.total_completed() / self.total()) * 100)
def count_by_kind(self, kind):
return len([a for a in self.completed_list() if a[0][1] == kind and "A1W3A1" not in a[0][0]])
def total_by_kind(self, kind):
return len([a for a in self.assignments if a[0][1] == kind and "A1W3A1" not in a[0][0]])
def is_assessment_ready(self):
# 1. Filter out the Flowchart (A1W3A1) from the required list
required_assignments = [
a for a in self.assignments
if a[0][1] == 'A' and "A1W3A1" not in a[0][0]
]
# Check if all remaining [A] assignments are done
all_a_done = all(a[1] is not None for a in required_assignments)
# 2. Check Master project (M)
master_done = self.count_by_kind('M') > 0
return all_a_done and master_done
def show_detailed_grades(self):
print(f"\n--- Detailed Grades for {self.name} ---")
for (header, kind), grade in self.assignments:
status = f"{grade:>5}" if grade is not None else " MISSING"
# Flag the "OP" confusion in the detailed view
label = f"[{kind}]"
if "OP" in header:
label = f"[{kind} - OOP?]"
print(f"{label} {header[:45]:<45} : {status}")
def __str__(self):
status = "READY" if self.is_assessment_ready() else "NOT ELIGIBLE"
return f"""
=== STUDENT SUMMARY ===
Name: {self.name}
ID: {self.id}
Status: {status}
Progress: {self.completion_percentage()}% ({self.total_completed()}/{self.total()})
Avg Grade: {self.avg_grade()}
-----------------------
Problems: {self.count_by_kind('P')}/{self.total_by_kind('P')}
Assignments: {self.count_by_kind('A')}/{self.total_by_kind('A')}
Master Task: {"[DONE]" if self.count_by_kind('M') > 0 else "[PENDING]"}
(Note: Flowchart A1W3A1 is excluded from requirements)
======================="""
def get_category(h):
part = h.split(' - ')[0]
if 'A' in part[-2:]: return 'A'
if 'P' in part[-2:]: return 'P'
if 'M' in part[-2:]: return 'M'
return '?'
def index_header(header):
return [(h, get_category(h)) for h in header[2:]]
students = []
try:
csvfile = open('gradebook.csv', mode='r', encoding='utf-8')
gradebook = csv.reader(csvfile, delimiter=',', quotechar='"')
header = next(gradebook)
header_cat = index_header(header)
for row in gradebook:
if not row: continue
student_name = row[0]
student_number = row[1]
all_assignments = list(map(safe_float, row[2:]))
students.append(Student(student_number, student_name, list(zip(header_cat, all_assignments))))
csvfile.close()
except FileNotFoundError:
print("Error: 'gradebook.csv' not found.")
exit()
students.sort(key=lambda s: s.completion_percentage(), reverse=True)
while True:
print(f"\n{'Student Name':<25} | {'ID':<10} | {'P-Done':<7} | {'A-Done':<7} | {'Ready?':<8} | {'Avg'}")
print("-" * 85)
for s in students:
ready_status = "YES" if s.is_assessment_ready() else "NO"
# Adjust P-count/A-count for the overview table display
p_count = f"{s.count_by_kind('P')}/{s.total_by_kind('P')}"
# Subtract 1 from total A because we skipped the flowchart
a_count = f"{s.count_by_kind('A')}/{s.total_by_kind('A')}"
print(f"{s.name[:25]:<25} | {s.id:<10} | {p_count:<7} | {a_count:<7} | {ready_status:<8} | {s.avg_grade():>5}")
print(f"\n{len(students)} students loaded.\n")
search = input("Enter Student Number for details (or 'exit'): ")
if search.lower() == 'exit': break
match = next((s for s in students if s.id == search), None)
if match:
print(match)
match.show_detailed_grades()
input("Press enter to continue")
else:
print("Student not found.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment