import json
import os
import statistics
from datetime import datetime
from pathlib import Path
# ============================================================
# CONFIGURATION
# ============================================================
DATA_FILE = "students_data.json"
PASSING_MARK = 40 # minimum marks to pass a subject
MAX_MARKS = 100 # maximum marks per subject
# ============================================================
# GRADING SYSTEM
# ============================================================
def get_grade(marks, max_marks=100):
"""Return letter grade, grade point, and remarks."""
pct = (marks / max_marks) * 100
if pct >= 90:
return "A+", 10.0, "Outstanding"
elif pct >= 80:
return "A", 9.0, "Excellent"
elif pct >= 70:
return "B+", 8.0, "Very Good"
elif pct >= 60:
return "B", 7.0, "Good"
elif pct >= 50:
return "C+", 6.0, "Above Average"
elif pct >= 40:
return "C", 5.0, "Average"
elif pct >= 35:
return "D", 4.0, "Pass (Marginal)"
else:
return "F", 0.0, "Fail"
def get_class(percentage):
"""Return division/class based on overall percentage."""
if percentage >= 75:
return "First Class with Distinction"
elif percentage >= 60:
return "First Class"
elif percentage >= 50:
return "Second Class"
elif percentage >= 40:
return "Pass Class"
else:
return "Fail"
def calculate_gpa(subjects):
"""Calculate weighted GPA from a list of subject dicts."""
total_points = 0
total_credits = 0
for sub in subjects:
_, gp, _ = get_grade(sub["marks_obtained"], sub["max_marks"])
credits = sub.get("credits", 1)
total_points += gp * credits
total_credits += credits
if total_credits == 0:
return 0.0
return round(total_points / total_credits, 2)
# ============================================================
# LOAD & SAVE DATA
# ============================================================
def load_data():
if Path(DATA_FILE).exists():
try:
with open(DATA_FILE, "r") as f:
return json.load(f)
except:
pass
return {"students": []}
def save_data(data):
with open(DATA_FILE, "w") as f:
json.dump(data, f, indent=2)
# ============================================================
# ADD STUDENT
# ============================================================
def add_student(data):
print("\n" + "="*50)
print(" ADD NEW STUDENT")
print("="*50)
name = input(" Student Name : ").strip()
roll_no = input(" Roll Number : ").strip()
cls = input(" Class/Semester: ").strip()
section = input(" Section : ").strip() or "A"
if not name or not roll_no:
print(" Name and Roll Number are required.")
return
# Check duplicate roll number
if any(s["roll_no"] == roll_no for s in data["students"]):
print(f" Roll number {roll_no} already exists.")
return
# Input subjects
subjects = []
print(f"\n Enter subjects and marks (type 'done' to finish)")
print(f" Format: Subject Name | Marks Obtained | Max Marks | Credits")
print(f" Example: Mathematics | 85 | 100 | 4\n")
while True:
entry = input(" > ").strip()
if entry.lower() == "done":
if not subjects:
print(" At least one subject is required.")
continue
break
parts = [p.strip() for p in entry.split("|")]
if len(parts) < 2:
print(" Format: Subject | Marks | Max Marks (opt) | Credits (opt)")
continue
sub_name = parts[0]
try:
marks = float(parts[1])
max_m = float(parts[2]) if len(parts) > 2 and parts[2] else MAX_MARKS
credits = float(parts[3]) if len(parts) > 3 and parts[3] else 1
if marks < 0 or marks > max_m:
print(f" Invalid marks. Must be between 0 and {max_m}")
continue
grade, gp, remarks = get_grade(marks, max_m)
subjects.append({
"name": sub_name,
"marks_obtained": marks,
"max_marks": max_m,
"credits": credits,
"grade": grade,
"grade_point": gp,
"remarks": remarks,
"passed": marks >= (max_m * PASSING_MARK / MAX_MARKS)
})
print(f" Added: {sub_name} — {marks}/{max_m} Grade: {grade} ({remarks})")
except ValueError:
print(" Invalid marks value.")
continue
# Calculate overall stats
total_obtained = sum(s["marks_obtained"] for s in subjects)
total_max = sum(s["max_marks"] for s in subjects)
percentage = round((total_obtained / total_max) * 100, 2) if total_max else 0
gpa = calculate_gpa(subjects)
passed_all = all(s["passed"] for s in subjects)
division = get_class(percentage)
failed_subs = [s["name"] for s in subjects if not s["passed"]]
student = {
"id": len(data["students"]) + 1,
"name": name,
"roll_no": roll_no,
"class": cls,
"section": section,
"subjects": subjects,
"total_obtained": total_obtained,
"total_max": total_max,
"percentage": percentage,
"gpa": gpa,
"division": division,
"passed": passed_all,
"failed_subjects": failed_subs,
"added_at": datetime.now().strftime("%d-%m-%Y %H:%M:%S")
}
data["students"].append(student)
save_data(data)
print(f"\n Student saved! Quick summary:")
print(f" Percentage : {percentage}%")
print(f" GPA : {gpa}")
print(f" Result : {'PASS' if passed_all else 'FAIL'}")
print(f" Division : {division}")
if failed_subs:
print(f" Failed in : {', '.join(failed_subs)}")
# ============================================================
# PRINT REPORT CARD
# ============================================================
def print_report_card(student):
w = 58
print("\n" + "=" * w)
print(f" {'REPORT CARD':^{w-4}}")
print("=" * w)
print(f" Name : {student['name']}")
print(f" Roll No : {student['roll_no']}")
print(f" Class : {student['class']} Section: {student['section']}")
print(f" Date : {student['added_at'][:10]}")
print("-" * w)
print(f" {'SUBJECT':<20} {'MAX':>5} {'OBT':>5} {'%':>6} "
f"{'GR':>3} {'GP':>4} REMARKS")
print("-" * w)
for sub in student["subjects"]:
pct = round((sub["marks_obtained"] / sub["max_marks"]) * 100, 1)
pass_marker = " " if sub["passed"] else "*"
print(f" {sub['name']:<20} {sub['max_marks']:>5.0f} "
f"{sub['marks_obtained']:>5.0f} {pct:>5.1f}% "
f"{sub['grade']:>3} {sub['grade_point']:>4.1f} "
f"{sub['remarks']}{pass_marker}")
print("-" * w)
overall_pct = round((student["total_obtained"] / student["total_max"]) * 100, 1)
print(f" {'TOTAL':<20} {student['total_max']:>5.0f} "
f"{student['total_obtained']:>5.0f} {overall_pct:>5.1f}%")
print("=" * w)
print(f" GPA : {student['gpa']} / 10.0")
print(f" Percentage : {student['percentage']}%")
print(f" Division : {student['division']}")
result_str = "PASS" if student["passed"] else "FAIL"
print(f" Result : {result_str}")
if student.get("failed_subjects"):
print(f" Failed in : {', '.join(student['failed_subjects'])}")
print("=" * w)
# Grade scale legend
print(f"\n Grade Scale: A+(90+)=10 | A(80+)=9 | B+(70+)=8 | "
f"B(60+)=7 | C+(50+)=6 | C(40+)=5 | D(35+)=4 | F=0")
print(f" * = Failed subject (below passing marks)\n")
# ============================================================
# SEARCH STUDENT
# ============================================================
def search_student(data):
query = input("\n Search by name or roll number: ").strip().lower()
results = [
s for s in data["students"]
if query in s["name"].lower() or query in s["roll_no"].lower()
]
if not results:
print(f" No students found for: '{query}'")
return None
if len(results) == 1:
return results[0]
print(f"\n Found {len(results)} students:")
for i, s in enumerate(results, 1):
print(f" [{i}] {s['roll_no']} {s['name']} "
f"Class: {s['class']} {s['percentage']}%")
try:
idx = int(input("\n Select number: ").strip()) - 1
if 0 <= idx < len(results):
return results[idx]
except ValueError:
pass
return None
# ============================================================
# CLASS REPORT (ALL STUDENTS)
# ============================================================
def class_report(data):
students = data["students"]
if not students:
print("\n No students added yet.")
return
print("\n" + "="*70)
print(f" CLASS REPORT ({len(students)} students)")
print("="*70)
print(f" {'ROLL':<10} {'NAME':<22} {'%':>6} "
f"{'GPA':>5} {'DIV':<30} RESULT")
print(" " + "-"*65)
sorted_students = sorted(students,
key=lambda x: x["percentage"],
reverse=True)
for rank, s in enumerate(sorted_students, 1):
result = "PASS" if s["passed"] else "FAIL"
print(f" {s['roll_no']:<10} {s['name']:<22} "
f"{s['percentage']:>5.1f}% {s['gpa']:>5.2f} "
f"{s['division']:<30} {result}")
# Class statistics
percentages = [s["percentage"] for s in students]
gpas = [s["gpa"] for s in students]
passed = sum(1 for s in students if s["passed"])
failed = len(students) - passed
print(" " + "-"*65)
print(f"\n CLASS STATISTICS")
print(f" Total Students : {len(students)}")
print(f" Passed : {passed} "
f"({passed/len(students)*100:.1f}%)")
print(f" Failed : {failed} "
f"({failed/len(students)*100:.1f}%)")
print(f" Highest % : {max(percentages):.2f}%")
print(f" Lowest % : {min(percentages):.2f}%")
print(f" Average % : {statistics.mean(percentages):.2f}%")
print(f" Median % : {statistics.median(percentages):.2f}%")
print(f" Average GPA : {statistics.mean(gpas):.2f}")
# Topper
topper = max(students, key=lambda x: x["percentage"])
print(f"\n Class Topper : {topper['name']} "
f"({topper['roll_no']}) — {topper['percentage']}%")
# Grade distribution
grade_dist = {}
for s in students:
g, _, _ = get_grade(s["percentage"])
grade_dist[g] = grade_dist.get(g, 0) + 1
print(f"\n Grade Distribution:")
for grade in ["A+", "A", "B+", "B", "C+", "C", "D", "F"]:
count = grade_dist.get(grade, 0)
bar = "█" * count
print(f" {grade:>3}: {count:>3} {bar}")
print("="*70)
# ============================================================
# SUBJECT-WISE ANALYSIS
# ============================================================
def subject_analysis(data):
students = data["students"]
if not students:
print("\n No data yet.")
return
# Collect all subjects
sub_map = {}
for s in students:
for sub in s["subjects"]:
name = sub["name"]
if name not in sub_map:
sub_map[name] = []
sub_map[name].append(sub["marks_obtained"])
if not sub_map:
return
print("\n" + "="*60)
print(" SUBJECT-WISE ANALYSIS")
print("="*60)
print(f" {'SUBJECT':<22} {'AVG':>6} {'HIGH':>6} "
f"{'LOW':>6} {'PASS%':>6} STUDENTS")
print(" " + "-"*56)
for sub_name, marks_list in sorted(sub_map.items()):
avg = statistics.mean(marks_list)
high = max(marks_list)
low = min(marks_list)
pass_pct = sum(1 for m in marks_list
if m >= PASSING_MARK) / len(marks_list) * 100
print(f" {sub_name:<22} {avg:>6.1f} {high:>6.1f} "
f"{low:>6.1f} {pass_pct:>5.1f}% {len(marks_list)}")
print("="*60)
# ============================================================
# DELETE STUDENT
# ============================================================
def delete_student(data):
student = search_student(data)
if not student:
return
confirm = input(f"\n Delete {student['name']} ({student['roll_no']})? "
f"(yes/no): ").strip().lower()
if confirm == "yes":
data["students"] = [s for s in data["students"]
if s["roll_no"] != student["roll_no"]]
save_data(data)
print(" Student deleted.")
else:
print(" Cancelled.")
# ============================================================
# MAIN MENU
# ============================================================
def print_menu(data):
count = len(data["students"])
print("\n" + "-"*48)
print(f" STUDENT GRADE CALCULATOR [{count} students]")
print("-"*48)
print(" 1. Add new student with marks")
print(" 2. View student report card")
print(" 3. Search student")
print(" 4. Class report (all students)")
print(" 5. Subject-wise analysis")
print(" 6. Delete a student")
print(" 0. Exit")
print("-"*48)
def main():
print("\n" + "="*55)
print(" STUDENT GRADE CALCULATOR")
print("="*55)
print(f"\n Passing Marks : {PASSING_MARK}/{MAX_MARKS}")
print(f" Grading : A+(90+) to F(<35)")
print(f" GPA Scale : 0 - 10")
data = load_data()
if data["students"]:
print(f"\n Loaded {len(data['students'])} student(s) from {DATA_FILE}")
while True:
print_menu(data)
choice = input(" > ").strip()
if choice == "1":
add_student(data)
elif choice == "2":
if not data["students"]:
print("\n No students added yet.")
continue
student = search_student(data)
if student:
print_report_card(student)
elif choice == "3":
if not data["students"]:
print("\n No students added yet.")
continue
student = search_student(data)
if student:
print(f"\n Found: {student['name']} | "
f"Roll: {student['roll_no']} | "
f"Class: {student['class']}")
print(f" Percentage: {student['percentage']}% | "
f"GPA: {student['gpa']} | "
f"Result: {'PASS' if student['passed'] else 'FAIL'}")
show = input("\n Show full report card? (y/n): ").strip().lower()
if show == "y":
print_report_card(student)
elif choice == "4":
class_report(data)
elif choice == "5":
subject_analysis(data)
elif choice == "6":
delete_student(data)
elif choice == "0":
print("\n Goodbye!\n")
break
else:
print(" Invalid choice.")
# ============================================================
# RUN
# ============================================================
if __name__ == "__main__":
main()
No comments:
Post a Comment