Changed: Projects

This commit is contained in:
DerGrumpf 2025-02-07 14:44:03 +01:00
parent 5d7b1d59c5
commit c320b27664
7 changed files with 361 additions and 176 deletions

View File

@ -1,6 +1,7 @@
# Custom
from model import *
from appstate import AppState
from grader.valuation import *
# External
from imgui_bundle import (
@ -22,129 +23,56 @@ from numpy.typing import NDArray
# Built In
from typing import List, Any
def student_list(app_state: AppState) -> None:
statics = student_list
if not app_state.current_class_id:
imgui.text("No Class found in Database")
return
@immapp.static(inited=False)
def select_class(app_state: AppState) -> None:
statics = select_class
if not hasattr(statics, "select"):
statics.select = 0
statics.students = Student.select().where(Student.class_id == app_state.current_class_id)
statics.students = statics.students if statics.students else None
if not statics.students:
imgui.text(f"No Stundents found in {Class.get_by_id(app_state.current_class_id).name}")
if not app_state.current_class_id:
imgui.text("No class found in Database")
return
if not statics.inited:
statics.select = 0
statics.classes = Class.select()
statics.labels = [c.name for c in statics.classes]
statics.inited = True
changed, statics.select = imgui.combo("Classes", statics.select, statics.labels)
if changed:
app_state.current_class_id = statics.classes[statics.select].id
@immapp.static(inited=False)
def select_student(app_state: AppState) -> None:
statics = select_student
if not app_state.current_class_id:
return
if not statics.inited:
statics.select = 0
statics.students = Student.select().where(Student.class_id == app_state.current_class_id)
statics.inited = True
if not statics.students:
imgui.text("No Studends found")
return
for n, student in enumerate(statics.students, start=1):
display = f"{n}. {student.prename} {student.surname}"
_, clicked = imgui.selectable(display, statics.select == n-1)
if clicked:
statics.select = n-1
app_state.current_student_id = statics.students[statics.select].id
app_state.current_student_id = statics.students[statics.select].id
def group_list(app_state: AppState) -> None:
statics = group_list
if not app_state.current_class_id:
imgui.text("No Class found in Database")
return
@immapp.static(inited=False)
def student_list(app_state: AppState) -> None:
statics = student_list
if not hasattr(statics, "select"):
statics.select = 0
select_class(app_state)
imgui.separator()
select_student(app_state)
statics.groups = Group.select().where(Group.class_id == app_state.current_class_id)
statics.groups = statics.groups if statics.groups else None
if not statics.groups:
imgui.text("No Group found")
return
for n, group in enumerate(statics.groups, start=1):
display = f"{n}. {group.name}"
_, clicked = imgui.selectable(display, statics.select == n-1)
if clicked:
statics.select = n-1
def lecture_list(app_state: AppState) -> None:
statics = lecture_list
if not app_state.current_class_id:
imgui.text("No class found in Database")
return
lectures = Lecture.select().where(Lecture.class_id == app_state.current_class_id)
if not lectures:
imgui.text(f"No Lectures found for {Class.get_by_id(app_state.current_class_id).name}")
return
if not hasattr(statics, "select"):
statics.select = 0
for n, lecture in enumerate(lectures, start=1):
display = f"{n}. {lecture.title}"
_, clicked = imgui.selectable(display, statics.select == n-1)
if clicked:
statics.select = n-1
app_state.current_lecture_id = lectures[statics.select].id
def class_list(app_state: AppState) -> None:
statics = class_list
if db.is_closed():
imgui.text("No Database loaded")
return
classes = Class.select() if db else None
if not classes:
imgui.text("No Classes currently in Database")
return
if not hasattr(statics, "select"):
statics.select = 0
for n, clas in enumerate(classes, start=1):
display = f"{n}. {clas.name}"
_, clicked = imgui.selectable(display, statics.select == n-1)
if clicked:
statics.select = n-1
app_state.current_class_id = classes[statics.select].id
def submissions_list(app_state: AppState) -> None:
statics = submissions_list
if not app_state.current_lecture_id:
imgui.text("No Lecture found")
return
if not app_state.current_student_id:
imgui.text("No Student found")
return
submissions = Submission.select().where(Submission.lecture_id == app_state.current_lecture_id and Submission.student_id == app_state.current_student_id)
if not submissions:
student = Student.get_by_id(app_state.current_student_id)
lecture = Lecture.get_by_id(app_state.current_lecture_id)
imgui.text(f"{student.prename} {student.surname} didn't submitted for {lecture.title}")
return
if not hasattr(statics, "select"):
statics.select = 0
for n, sub in enumerate(submissions, start=1):
lecture = Lecture.get_by_id(sub.lecture_id)
points = sub.points
if points.is_integer():
points = int(points)
display = f"{n}. {lecture.title} {points}/{lecture.points}"
_, clicked = imgui.selectable(display, statics.select == n-1)
if clicked:
statics.select = n-1
app_state.current_submission_id = submissions[statics.select].id
def plot_bar_line_percentage(data: np.array, labels: list, avg: float) -> None:
if not data.size > 0:
@ -212,6 +140,8 @@ def student_graph(app_state: AppState) -> None:
statics.points = np.sum(statics.sub_points)
if statics.points.is_integer():
statics.points = int(statics.points)
statics.grader = get_grader("Oberstufe")
#statics.grader = get_grader(statics.student.grader)
statics.subs_data = np.array([p/mp.points for p, mp in zip(statics.sub_points, statics.lectures)], dtype=np.float32)*100
statics.subs_labels = [f"{l.title} {int(points) if points.is_integer() else points}/{l.points}" for l, points in zip(statics.lectures, statics.sub_points)]
@ -219,7 +149,7 @@ def student_graph(app_state: AppState) -> None:
w, h = imgui.get_window_size()
imgui_md.render(f"# {statics.student.prename} {statics.student.surname} ({statics.group.name})")
imgui_md.render(f"### {statics.points}/{statics.max_points}")
imgui_md.render(f"### {statics.points}/{statics.max_points} ({statics.student.grader})")
imgui.text(" ")
imgui.progress_bar(statics.points/statics.max_points, ImVec2(w*0.9, h*0.05), f"{statics.points}/{statics.max_points} {statics.points/statics.max_points:.1%}")
plot_bar_line_percentage(statics.subs_data, statics.subs_labels, statics.avg)
@ -227,8 +157,8 @@ def student_graph(app_state: AppState) -> None:
imgui.text_colored(COLOR_TEXT_PROJECT, f"{statics.group.name}: {statics.group.project}")
for n, data in enumerate(zip(statics.lectures, statics.sub_points), start=1):
lecture, points = data
COLOR = COLOR_TEXT_PASSED if points >= lecture.points*0.3 else COLOR_TEXT_FAILED
imgui.text_colored(COLOR, f"{n}. {lecture.title}")
COLOR = statics.grader.get_grade_color(points, lecture.points)
imgui.text_colored(COLOR, f"{n}. {lecture.title} {points}/{lecture.points} ({statics.grader.get_grade(points, lecture.points)}) ")
@immapp.static(inited=False)
def sex_graph(app_state: AppState) -> None:
@ -415,26 +345,6 @@ def set_analyzer_layout(app_state: AppState) -> List[hello_imgui.DockableWindow]
student_selector.label = "Students"
student_selector.dock_space_name = "CommandSpace"
student_selector.gui_function = lambda: student_list(app_state)
group_selector = hello_imgui.DockableWindow()
group_selector.label = "Groups"
group_selector.dock_space_name = "CommandSpace"
group_selector.gui_function = lambda: group_list(app_state)
lecture_selector = hello_imgui.DockableWindow()
lecture_selector.label = "Lectures"
lecture_selector.dock_space_name = "CommandSpace2"
lecture_selector.gui_function = lambda: lecture_list(app_state)
class_selector = hello_imgui.DockableWindow()
class_selector.label = "Classes"
class_selector.dock_space_name = "CommandSpace2"
class_selector.gui_function = lambda: class_list(app_state)
submission_selector = hello_imgui.DockableWindow()
submission_selector.label = "Submissions"
submission_selector.dock_space_name = "CommandSpace"
submission_selector.gui_function = lambda: submissions_list(app_state)
student_info = hello_imgui.DockableWindow()
student_info.label = "Student Analyzer"
@ -452,10 +362,9 @@ def set_analyzer_layout(app_state: AppState) -> List[hello_imgui.DockableWindow]
student_ranking.gui_function = lambda: ranking(app_state)
return [
class_selector, student_selector,
lecture_selector, submission_selector,
student_selector,
student_info, sex_info,
student_ranking, group_selector
student_ranking,
]
def analyzer_layout(app_state: AppState) -> hello_imgui.DockingParams:

View File

@ -1,37 +1,38 @@
First Name,Last Name,Sex,Group,Tutorial 1,Tutorial 2,Extended Applications,Numpy & MatPlotLib,SciPy,Monte Carlo,Pandas & Seaborn,Folium,Statistical Test Methods,Data Analysis
Abdalaziz,Abunjaila,Male,DiKum,30.5,15,18,28,17,17,17,22,0,18
Marleen,Adolphi,Female,MeWi6,29.5,15,18,32,19,20,17,24,23,0
Sarina,Apel,Female,MeWi1,28.5,15,18,32,20,20,21,24,20,0
Skofiare,Berisha,Female,DiKum,29.5,13,18,34,20,17,20,26,16,0
Aurela,Brahimi,Female,MeWi2,17.5,15,15.5,26,16,17,19,16,0,0
Cam Thu,Do,Female,MeWi3,31,15,18,34,19,20,21.5,22,12,0
Nova,Eib,Female,MeWi4,31,15,15,34,20,20,21,27,19,21
Lena,Fricke,Female,MeWi4,0,0,0,0,0,0,0,0,0,0
Nele,Grundke,Female,MeWi6,23.5,13,16,28,20,17,21,18,22,0
Anna,Grünewald,Female,MeWi3,12,14,16,29,16,15,19,9,0,0
Yannik,Haupt,Male,NoGroup,18,6,14,21,13,2,9,0,0,0
Janna,Heiny,Female,MeWi1,30,15,18,33,18,20,22,25,24,30
Milena,Krieger,Female,MeWi1,30,15,18,33,20,20,21.5,26,20,0
Julia,Limbach,Female,MeWi6,27.5,12,18,29,11,19,17.5,26,24,0
Viktoria,Litza,Female,MeWi5,21.5,15,18,27,13,20,22,21,21,0
Leonie,Manthey,Female,MeWi1,28.5,14,18,29,20,10,18,23,16,28
Izabel,Mike,Female,MeWi2,29.5,15,15,35,11,15,19,21,21,27
Lea,Noglik,Female,MeWi5,22.5,15,17,34,13,10,20,21,19,0
Donika,Nuhiu,Female,MeWi5,31,13.5,18,35,14,10,17,18,19,6
Julia,Renner,Female,MeWi4,27.5,10,14,32,20,17,11,20,24,0
Fabian,Rothberger,Male,MeWi3,30.5,15,18,34,17,17,19,22,18,0
Natascha,Rott,Female,MeWi1,29.5,12,18,32,19,20,21,26,23,0
Isabel,Rudolf,Female,MeWi4,27.5,9,17,34,16,19,19,21,16,0
Melina,Sablotny,Female,MeWi6,31,15,18,33,20,20,21,19,11,0
Alea,Schleier,Female,DiKum,27,14,18,34,16,18,21.5,22,15,22
Flemming,Schur,Male,MeWi3,29.5,15,17,34,19,20,19,22,18,0
Marie,Seeger,Female,DiKum,27.5,15,18,32,14,9,17,22,9,0
Lucy,Thiele,Female,MeWi6,27.5,15,18,27,20,17,19,18,22,0
Lara,Troschke,Female,MeWi2,28.5,14,17,28,13,19,21,25,12,0
Inga-Brit,Turschner,Female,MeWi2,25.5,14,18,34,20,16,19,22,17,0
Alea,Unger,Female,MeWi5,30,12,18,31,20,20,21,22,15,21.5
Marie,Wallbaum,Female,MeWi5,28.5,14,18,34,17,20,19,24,12,0
Katharina,Walz,Female,MeWi4,31,15,18,31,19,19,17,24,17,14.5
Xiaowei,Wang,Male,NoGroup,30.5,14,18,26,19,17,0,0,0,0
Lilly-Lu,Warnken,Female,DiKum,30,15,18,30,14,17,19,14,16,0
First Name,Last Name,Sex,Group,Grader,Tutorial 1,Tutorial 2,Extended Applications,Numpy & MatPlotLib,SciPy,Monte Carlo,Pandas & Seaborn,Folium,Statistical Test Methods,Data Analysis
Abdalaziz,Abunjaila,Male,DiKum,30 Percent,30.5,15,18,28,17,17,17,22,0,18
Marleen,Adolphi,Female,MeWi6,30 Percent,29.5,15,18,32,19,20,17,24,23,0
Sarina,Apel,Female,MeWi1,30 Percent,28.5,15,18,32,20,20,21,24,20,23
Skofiare,Berisha,Female,DiKum,30 Percent,29.5,13,18,34,20,17,20,26,16,0
Aurela,Brahimi,Female,MeWi2,30 Percent,17.5,15,15.5,26,16,17,19,16,0,0
Cam Thu,Do,Female,MeWi3,30 Percent,31,15,18,34,19,20,21.5,22,12,0
Nova,Eib,Female,MeWi4,30 Percent,31,15,15,34,20,20,21,27,19,21
Lena,Fricke,Female,MeWi4,30 Percent,0,0,0,0,0,0,0,0,0,0
Nele,Grundke,Female,MeWi6,30 Percent,23.5,13,16,28,20,17,21,18,22,11
Anna,Grünewald,Female,MeWi3,30 Percent,12,14,16,29,16,15,19,9,0,0
Yannik,Haupt,Male,NoGroup,30 Percent,18,6,14,21,13,2,9,0,0,0
Janna,Heiny,Female,MeWi1,30 Percent,30,15,18,33,18,20,22,25,24,30
Milena,Krieger,Female,MeWi1,30 Percent,30,15,18,33,20,20,21.5,26,20,22
Julia,Limbach,Female,MeWi6,30 Percent,27.5,12,18,29,11,19,17.5,26,24,28
Viktoria,Litza,Female,MeWi5,30 Percent,21.5,15,18,27,13,20,22,21,21,30
Leonie,Manthey,Female,MeWi1,30 Percent,28.5,14,18,29,20,10,18,23,16,28
Izabel,Mike,Female,MeWi2,30 Percent,29.5,15,15,35,11,15,19,21,21,27
Lea,Noglik,Female,MeWi5,30 Percent,22.5,15,17,34,13,10,20,21,19,6
Donika,Nuhiu,Female,MeWi5,30 Percent,31,13.5,18,35,14,10,17,18,19,8
Julia,Renner,Female,MeWi4,30 Percent,27.5,10,14,32,20,17,11,20,24,14
Fabian,Rothberger,Male,MeWi3,30 Percent,30.5,15,18,34,17,17,19,22,18,30
Natascha,Rott,Female,MeWi1,30 Percent,29.5,12,18,32,19,20,21,26,23,26
Isabel,Rudolf,Female,MeWi4,30 Percent,27.5,9,17,34,16,19,19,21,16,14
Melina,Sablotny,Female,MeWi6,30 Percent,31,15,18,33,20,20,21,19,11,28
Alea,Schleier,Female,DiKum,30 Percent,27,14,18,34,16,18,21.5,22,15,22
Flemming,Schur,Male,MeWi3,30 Percent,29.5,15,17,34,19,20,19,22,18,27
Marie,Seeger,Female,DiKum,30 Percent,27.5,15,18,32,14,9,17,22,9,25
Lucy,Thiele,Female,MeWi6,30 Percent,27.5,15,18,27,20,17,19,18,22,25
Lara,Troschke,Female,MeWi2,30 Percent,28.5,14,17,28,13,19,21,25,12,24
Inga-Brit,Turschner,Female,MeWi2,30 Percent,25.5,14,18,34,20,16,19,22,17,30
Alea,Unger,Female,MeWi5,30 Percent,30,12,18,31,20,20,21,22,15,21.5
Marie,Wallbaum,Female,MeWi5,30 Percent,28.5,14,18,34,17,20,19,24,12,22
Katharina,Walz,Female,MeWi4,30 Percent,31,15,18,31,19,19,17,24,17,14.5
Xiaowei,Wang,Male,NoGroup,30 Percent,30.5,14,18,26,19,17,0,0,0,0
Lilly-Lu,Warnken,Female,DiKum,30 Percent,30,15,18,30,14,17,19,14,16,24
,,,,,,,,,,,,,,

1 First Name Last Name Sex Group Grader Tutorial 1 Tutorial 2 Extended Applications Numpy & MatPlotLib SciPy Monte Carlo Pandas & Seaborn Folium Statistical Test Methods Data Analysis
2 Abdalaziz Abunjaila Male DiKum 30 Percent 30.5 15 18 28 17 17 17 22 0 18
3 Marleen Adolphi Female MeWi6 30 Percent 29.5 15 18 32 19 20 17 24 23 0
4 Sarina Apel Female MeWi1 30 Percent 28.5 15 18 32 20 20 21 24 20 0 23
5 Skofiare Berisha Female DiKum 30 Percent 29.5 13 18 34 20 17 20 26 16 0
6 Aurela Brahimi Female MeWi2 30 Percent 17.5 15 15.5 26 16 17 19 16 0 0
7 Cam Thu Do Female MeWi3 30 Percent 31 15 18 34 19 20 21.5 22 12 0
8 Nova Eib Female MeWi4 30 Percent 31 15 15 34 20 20 21 27 19 21
9 Lena Fricke Female MeWi4 30 Percent 0 0 0 0 0 0 0 0 0 0
10 Nele Grundke Female MeWi6 30 Percent 23.5 13 16 28 20 17 21 18 22 0 11
11 Anna Grünewald Female MeWi3 30 Percent 12 14 16 29 16 15 19 9 0 0
12 Yannik Haupt Male NoGroup 30 Percent 18 6 14 21 13 2 9 0 0 0
13 Janna Heiny Female MeWi1 30 Percent 30 15 18 33 18 20 22 25 24 30
14 Milena Krieger Female MeWi1 30 Percent 30 15 18 33 20 20 21.5 26 20 0 22
15 Julia Limbach Female MeWi6 30 Percent 27.5 12 18 29 11 19 17.5 26 24 0 28
16 Viktoria Litza Female MeWi5 30 Percent 21.5 15 18 27 13 20 22 21 21 0 30
17 Leonie Manthey Female MeWi1 30 Percent 28.5 14 18 29 20 10 18 23 16 28
18 Izabel Mike Female MeWi2 30 Percent 29.5 15 15 35 11 15 19 21 21 27
19 Lea Noglik Female MeWi5 30 Percent 22.5 15 17 34 13 10 20 21 19 0 6
20 Donika Nuhiu Female MeWi5 30 Percent 31 13.5 18 35 14 10 17 18 19 6 8
21 Julia Renner Female MeWi4 30 Percent 27.5 10 14 32 20 17 11 20 24 0 14
22 Fabian Rothberger Male MeWi3 30 Percent 30.5 15 18 34 17 17 19 22 18 0 30
23 Natascha Rott Female MeWi1 30 Percent 29.5 12 18 32 19 20 21 26 23 0 26
24 Isabel Rudolf Female MeWi4 30 Percent 27.5 9 17 34 16 19 19 21 16 0 14
25 Melina Sablotny Female MeWi6 30 Percent 31 15 18 33 20 20 21 19 11 0 28
26 Alea Schleier Female DiKum 30 Percent 27 14 18 34 16 18 21.5 22 15 22
27 Flemming Schur Male MeWi3 30 Percent 29.5 15 17 34 19 20 19 22 18 0 27
28 Marie Seeger Female DiKum 30 Percent 27.5 15 18 32 14 9 17 22 9 0 25
29 Lucy Thiele Female MeWi6 30 Percent 27.5 15 18 27 20 17 19 18 22 0 25
30 Lara Troschke Female MeWi2 30 Percent 28.5 14 17 28 13 19 21 25 12 0 24
31 Inga-Brit Turschner Female MeWi2 30 Percent 25.5 14 18 34 20 16 19 22 17 0 30
32 Alea Unger Female MeWi5 30 Percent 30 12 18 31 20 20 21 22 15 21.5
33 Marie Wallbaum Female MeWi5 30 Percent 28.5 14 18 34 17 20 19 24 12 0 22
34 Katharina Walz Female MeWi4 30 Percent 31 15 18 31 19 19 17 24 17 14.5
35 Xiaowei Wang Male NoGroup 30 Percent 30.5 14 18 26 19 17 0 0 0 0
36 Lilly-Lu Warnken Female DiKum 30 Percent 30 15 18 30 14 17 19 14 16 0 24
37
38

Binary file not shown.

View File

@ -54,10 +54,11 @@ for index, row in df.iterrows():
surname=row["Last Name"],
sex=row["Sex"],
class_id=clas.id,
group_id=Group.select().where(Group.name == row["Group"])
group_id=Group.select().where(Group.name == row["Group"]),
grader=row["Grader"]
)
for title, points in list(row.to_dict().items())[4:]:
for title, points in list(row.to_dict().items())[5:]:
Submission.create(
student_id=s.id,
lecture_id=Lecture.select().where(Lecture.title == title),

View File

@ -0,0 +1,76 @@
import sys
sys.path.append("..")
from valuation import BaseGrading
# Testing
import unittest
from unittest.mock import patch
class TestBaseGrading(unittest.TestCase):
test_schema = {"Grade1": 0.1, "Grade2": 0.3}
@patch.multiple(BaseGrading, __abstractmethods__=set())
def get_base_grader(self):
return BaseGrading(self.test_schema, "TestGrader")
def test_getter(self):
grader = self.get_base_grader()
self.assertEqual(grader.get("Grade1"), self.test_schema["Grade1"])
self.assertEqual(grader.get("grade1"), self.test_schema["Grade1"])
def test_len(self):
grader = self.get_base_grader()
self.assertEqual(len(grader), len(self.test_schema))
def test_contains(self):
grader = self.get_base_grader()
self.assertTrue(0.1 in grader)
self.assertTrue(0.9 in grader)
self.assertFalse(100 in grader)
self.assertFalse(None in grader)
self.assertTrue("Grade1" in grader)
self.assertTrue("gRADE2" in grader)
def test_iter(self):
grader = self.get_base_grader()
for grade, test in zip(grader, self.test_schema):
self.assertEqual(grade, test)
def test_reversed(self):
grader = self.get_base_grader()
for grade, test in zip(reversed(grader), reversed(self.test_schema)):
self.assertEqual(grade, test)
def test_str(self):
grader = self.get_base_grader()
self.assertEqual(str(grader), "TestGrader")
def test_repr(self):
grader = self.get_base_grader()
self.assertEqual(repr(grader), f"<TestGrader: ({str(self.test_schema)})>")
def test_eq(self):
grader = self.get_base_grader()
self.assertTrue(grader == grader)
self.assertTrue(grader != grader)
def test_keys(self):
grader = self.get_base_grader()
for k1, t1 in zip(grader.keys(), self.test_schema.keys()):
self.assertEqual(k1, t1)
def test_items(self):
grader = self.get_base_grader()
for v1, t1 in zip(grader.values(), self.test_schema.values()):
self.assertEqual(v1, t1)
def test_items(self):
grader = self.get_base_grader()
for g1, t1 in zip(grader.items(), self.test_schema.items()):
k, v = g1
tk, tv = t1
self.assertEqual(k, tk)
self.assertEqual(v, tv)
if __name__ == "__main__":
unittest.main()

197
grader/valuation.py Normal file
View File

@ -0,0 +1,197 @@
from collections.abc import Sequence, Iterable, Mapping
from typing import Any
import inspect
from abc import ABC, abstractmethod
import weakref
from PIL import ImageColor
from colour import Color
PASSED: str = "#1AFE49"
FAILED: str = "#FF124F"
def hex_to_rgba(color: str) -> tuple:
return tuple([e/255 for e in ImageColor.getcolor(color, "RGBA")])
def gradient(color1: str, color2: str, num: int) -> list[tuple]:
c1, c2 = Color(color1), Color(color2)
colors = list(c2.range_to(c1, num))
colors = [hex_to_rgba(str(c)) for c in colors]
return colors
class BaseGrading(Mapping, ABC):
__instances: list[Mapping] = list()
def __init__(self, schema: dict[str, int | float], name=None, alt_name=None):
all_str = all(isinstance(k, str) for k in schema.keys())
assert all_str or all(isinstance(k, int) for k in schema.keys()), "Keys must be all of type (str, int)"
assert all(isinstance(v, float) for v in schema.values()), "All values must be floats in range(0,1)"
assert all(v <= 1 and v >= 0 for v in schema.values()), "All values must be floats in range(0,1)"
if all_str:
self.schema = dict()
for k, v in schema.items():
self.schema[k.title()] = v
else:
self.schema = schema
self.__class__.__instances.append(weakref.proxy(self))
self.name = name
self.alt_name = alt_name
def __getitem__(self, index):
if index >= len(self):
raise IndexError
return self.schema[index]
def __len__(self) -> int:
return len(self.schema)
def __contains__(self, item: int | str | float) -> bool:
if isinstance(item, (int, str)):
if isinstance(item, str):
item = item.title()
return item in self.schema
if isinstance(item, float):
return item <= 1 and item >= 0
return False
def __iter__(self) -> Iterable:
yield from self.schema
def __reversed__(self) -> Iterable:
yield from reversed(self.schema)
def __str__(self) -> str:
return self.name
def __repr__(self) -> str:
return f"<{self.name}: ({str(self.schema)})>"
def __eq__(self, other) -> bool:
if other == self:
return True
if isinstance(other, BaseEval):
return self.schema == other.schema
return NotImplemented
def __ne__(self, other) -> bool:
return not self.__eq__(other)
def get(self, key: int | str) -> float | None:
if isinstance(key, str):
key = key.title()
if key in self:
return self.schema[key]
return None
def keys(self) -> tuple:
return list(self.schema.keys())
def values(self) -> tuple:
return list(self.schema.values())
def items(self) -> list[tuple]:
return list(self.schema.items())
@abstractmethod
def has_passed(self, value: int | float, max: int | float) -> bool:
pass
@abstractmethod
def get_grade(self, value: int | float, max: int | float) -> str | int:
pass
@abstractmethod
def get_grade_color(self, value: int | float, max: int | float) -> tuple:
pass
@classmethod
def get_instances(cls):
yield from cls.__instances
@classmethod
def get_instance(cls, name: str):
for instance in cls.__instances:
if instance.alt_name == name:
return instance
get_gradings = lambda: BaseGrading.get_instances()
get_grader = lambda name: BaseGrading.get_instance(name)
class StdPercentRule(BaseGrading):
def has_passed(self, value: int | float, max: int | float) -> bool:
return value >= max * self.schema["Passed"]
def get_grade(self, value: int | float, max: int | float) -> str:
return "Passed" if self.has_passed(value, max) else "Not Passed"
def get_grade_color(self, value: int | float, max: int | float) -> tuple:
if self.has_passed(value, max):
return hex_to_rgba(PASSED)
return hex_to_rgba(FAILED)
class StdGermanGrading(BaseGrading):
def has_passed(self, value: int | float, max: int | float) -> bool:
return value/max >= 0.45
def search_grade(self, value: float) -> int:
if value <= 0:
return min(self.schema.keys())
searched = max(self.schema.keys())
found = False
while not found:
if self.schema[searched] <= value:
found = True
else:
searched -= 1
return searched
def get_grade(self, value: int | float, max: int | float) -> int:
return self.search_grade(value/max)
def get_grade_color(self, value: float, max: int | float) -> tuple:
grade = self.get_grade(value, max)
colors = gradient(PASSED, FAILED, len(self.schema))
return colors[grade]
# Definitions
Std30PercentRule = StdPercentRule({
"pAssed": 0.3,
"Failed": 0.0
}, "Std30PercentRule", "30 Percent")
Std50PercentRule = StdPercentRule({
"Passed": 0.5,
"Failed": 0.0
}, "Std50PercentRule", "50 Percent")
StdGermanGradingMiddleSchool = StdGermanGrading({
1: 0.96,
2: 0.80,
3: 0.60,
4: 0.45,
5: 0.16,
6: 0.00
}, "StdGermanGradingMiddleSchool", "Secondary School")
StdGermanGradingHighSchool = StdGermanGrading({
15: 0.95,
14: 0.90,
13: 0.85,
12: 0.80,
11: 0.75,
10: 0.70,
9: 0.65,
8: 0.60,
7: 0.55,
6: 0.50,
5: 0.45,
4: 0.40,
3: 0.33,
2: 0.27,
1: 0.20,
0: 0.00
}, "StdGermanGradingHighSchool", "Oberstufe")
#print(StdGermanGradingHighSchool.get_grade(0.0, 24))

View File

@ -27,6 +27,7 @@ class Student(BaseModel):
sex = CharField()
class_id = ForeignKeyField(Class, backref='class')
group_id = ForeignKeyField(Group, backref='group')
grader = CharField()
created_at = DateTimeField(default=datetime.now)
class Lecture(BaseModel):