1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
#!/usr/bin/env python3
"""Evaluate grades from a moodle activity grades csv export"""
import argparse
import csv
import locale
# Example: Donnerstag, 16. Oktober 2025
MOODLE_DATE_FORMAT = '%A, %d. %B %Y, %H:%M'
def print_group_means(grades: dict[str, list[str]], groups_csv_path: str):
"""Print the means of groups"""
with open(groups_csv_path, 'r', encoding='utf-8') as groups_csv_file:
# groups_reader = csv.reader(groups_csv_file)
# groups_data = list(groups_reader)
# groups_data = list(groups_reader)
lines = groups_csv_file.readlines()
groups_data = [l.strip().split(',') for l in lines]
groups = {}
for student, group in groups_data:
groups[student] = group
results = {}
for student, grade in grades.items():
group = groups[student]
results[group] = [float(grade[6].replace(',', '.'))] + results.get(
group, [])
for group, results in results.items():
mean = sum(results) / len(results)
print(f'{group}: {mean}')
def main():
"""Entry point loading grades and evaluating them"""
parser = argparse.ArgumentParser()
parser.add_argument("--points",
help="The maximum amount of points for the grades",
type=int,
default=3)
parser.add_argument("--scale",
help="The scale of the grades",
default="0-10")
parser.add_argument("--locale",
help="The locale to use",
default="de_DE.utf8")
parser.add_argument("--teacher",
help="Name of the teacher to exclude their grades.",
default="Florian Fischer")
parser.add_argument(
"--groups-csv",
help="CSV file containing student names and their groups")
parser.add_argument("grades", help="The csv file containing the grades")
args = parser.parse_args()
locale.setlocale(locale.LC_ALL, args.locale)
scale = args.scale.split('-')
scale = (int(scale[0]), int(scale[1]))
with open(args.grades, 'r', encoding='utf-8') as grades_file:
grades_reader = csv.reader(grades_file)
next(grades_reader) # skip headers
grades_data = list(grades_reader)
grades = {}
# Collect all first attempts
for grade in grades_data:
student = grade[1]
# Original grade
if not grade[5] and grade[6] and student != args.teacher:
assert student not in grades
grades[student] = grade
if args.groups_csv:
print_group_means(grades, args.groups_csv)
else:
results = [
float(grade[6].replace(',', '.')) for grade in grades.values()
]
mean = sum(results) / len(results)
print(f'mean: {mean} -> {args.points*(mean-scale[0])/scale[1]}')
if __name__ == '__main__':
main()
|