Readme update

This commit is contained in:
Lukas Horst 2024-10-07 14:29:17 +02:00
parent e9c9c6ae49
commit 5497926df1
3 changed files with 135 additions and 97 deletions

View file

@ -4,31 +4,36 @@ Ein Tool, um die Bewertung von EPR-Abgaben (und auch GPR-Abgaben) zu beschleunig
## Installation
1. Legt `eprgrader.py` (das eigentliche Programm) und `eprcheck_2019.py` (das pylint-Plugin für die
Author-Variable) im selben Verzeichnis ab.
1. Legt `eprgrader.py` (das eigentliche Programm), `eprcheck_2019.py` (das pylint-Plugin für die
Author-Variable) und `violation_checker.py` (Klasse um die Stylefehler zusammenzuzählen) im
selben Verzeichnis ab.
2. Wenn ihr den automatischen Style-Check benutzen wollt, installiert `pylint`, `pycodestyle`
und `astroid` via `pip`:
`pip install pylint==2.15.0 pycodestyle==2.8.0 astroid==2.13.5 openpyxl pandas`
## Zu Beginn
Ladet die ZIP-Datei(en) mit den Abgaben für eure Gruppe(n) sowie die Bewertungstabellle herunter.
Ladet die ZIP-Datei(en) mit den Abgaben für eure Gruppe(n), die Gesamtbewertung (.csv Datei) für
eure Gruppe(n) sowie die Bewertungstabelle herunter.
Legt ein Verzeichnis für das Übungsblatt an, und dann einen Unterordner für jedes eurer Tutorien.
Legt die Abgaben-Zips in die jeweiligen Ordner. Das ganze sollte jetzt in etwa so aussehen:
Legt die Abgaben-Zips und die Gesamtbewertungen in die jeweiligen Ordner. Das ganze sollte
jetzt in etwa so aussehen:
```
blatt0
|-- Bewertungstabelle_EPR_0.xlsx
|-- EPR01
| `-- EPR-2021-Abgabe zu EPR_00-EPR 01 - H 7 - Adrian-88422.zip
| `-- Bewertungen-EPR 2021-Abgabe zu EPR_00-EPR 01 - H 7 - Adrian-88422.csv
`-- EPR02
`-- EPR-2021-Abgabe zu EPR_00-EPR 02 - H 6 - Adrian-88422.zip
`-- Bewertungen-EPR 2021-Abgabe zu EPR_00-EPR 02 - H 6 - Adrian-88422.csv
```
Führt jetzt den Startbefehl aus:
```cmd
cd ...\Tutorium\blatt0
python eprgrader.py begin --table Bewertungstabelle_EPR_4.xlsx --no-stylecheck
python eprgrader.py begin --table Bewertungstabelle_EPR_0.xlsx
```
Zusätzliche Optionen:
@ -37,12 +42,26 @@ Zusätzliche Optionen:
* `--no-deduction`: Wenn es noch keinen Abzug für Stylefehler gibt.
Hierdurch werden alle zip-Archive entpackt, die Bewertungstabellen kopiert und für jeden Teilnehmer
entsprechend umbenannt, und ggf. der Stylchecker ausgeführt.
entsprechend umbenannt, und ggf. der Stylechecker ausgeführt.
Wenn der Stylechecker ausgeführt, wird außerdem direkt der Abzug berechnet und in die
Bewertungstabelle eingetragen. Die überprüften Stylefehler werden dabei in Gruppen eingeteilt
und dann innerhalb dieser Gruppen zusammengezählt. Wie die Fehlergruppen eingeteilt sind und wie
viel Abzug es gibt, kann man in der violation_checker.py Datei anpassen.
Damit der Abzug automatisch eingetragen werden kann, muss es folgende Zellen geben:
- `__author__` falsch (Abzug für Fehler bei der author Variable)
- ...alle `o.g. Fehler` sind gleichbedeutend... (Abzug für Stylefehler)
- `Abzug bei` mangelnden Kommentaren... (Abzug für Docstrings)
Markiert sind dabei die Stellen, nach welchen explizit gesucht wird.
## Style-Prüfung erneut ausführen
Bei Bedarf kann die Style-Prüfung erneut ausgeführt werden. Dabei werden alle bestehenden
`stylecheck.txt`-Dateien überschrieben.
Die Punkte werden aber nicht mehr in die Bewertungstabellen eingetragen
```cmd
cd ...\Tutorium\blatt0
@ -51,6 +70,7 @@ python eprgrader.py relint
Zusätzliche Optionen:
* `--pairs`: Überprüft die `__author__`-Variable nach dem Format für Paaraufgaben.
* `--no-deduction`: Wenn es noch keinen Abzug für Stylefehler gibt.
## Abschluss
@ -58,6 +78,9 @@ Am Ende können die Bewertungsdateien (Glob-Pattern `Bewertung *`) sowie die `st
für jeden Teilnehmer zusammengesammelt und für den Upload als Feedback-Datei wieder zusammengepackt
werden.
Wenn die Gesamtbewertungstabellen in den Ordnern sind, wird die Gesamtpunktzahl von allen
Einzelbewertungen ausgelesen und in die csv Datei eingefügt. Dafür muss es die Zelle `Summe` geben.
Achtung: das funktioniert nur für die Einzelabgaben sinnvoll!
```cmd
@ -68,6 +91,9 @@ python eprgrader.py finalise
Nun sollte sich in jedem Tutoriums-Unterordner eine neue Zip-Datei finden, die den Namen
des Tutoriums trägt (z. B. `EPR02.zip`). Diese kann über die Moodle-Option "Mehrere Feedbackdateien
in einer Zip-Datei hochladen" hochgeladen werden.
Die Gesamtbewertungstabelle kann unter "Bewertungstabelle hochladen" hochgeladen werden. Dabei
muss der Haken bei "Update von Datensätzen zulassen, ..." gesetzt werden.
## Änderung der Style-Einstellungen

View file

@ -8,11 +8,13 @@ Later on, collecting all the stylecheck files and grading tables into
neat little archives for upload.
"""
__author__ = "Adrian Welcker, Lukas Horst"
__author__ = "Adrian Welcker"
__credits__ = "Adjustments from Lukas Horst"
import argparse
import contextlib
import copy
import csv
import io
import itertools
import os
@ -20,18 +22,19 @@ import pathlib
import platform
import shutil
import sys
from itertools import count
import openpyxl
import pandas as pd
import unicodedata
import zipfile
import re
from openpyxl.styles import Font
from datetime import datetime
from pylint.lint import Run as RunPylint
import pycodestyle
from rating_table_adjuster import update_rating, update_style_deduction
from violation_checker import ViolationChecker
PYLINT_ARGS = [
@ -189,7 +192,10 @@ def lint_files(folders, author_pairs, deduction: bool):
def remove_unnecessary_violations(style_check: str):
"""Function to delete all lines with a violation to ignore"""
"""
Function to delete all lines with a violation to ignore
author: Lukas Horst
"""
lines = style_check.splitlines()
filtered_lines = []
@ -336,6 +342,99 @@ def finalise_grading(folder: pathlib.Path):
outfile.write(file, pathlib.PurePath(person.name) / file.name)
def get_points(file_path: str):
"""
Returns the total points of the given rating table
author: Lukas Horst
"""
data = pd.read_excel(file_path, usecols='A, C')
total_points = 0
for i in range(len(data)):
if data.iat[i, 0] == 'Summe':
break
value = data.iat[i, 1]
if pd.notna(value) and type(value) != str:
total_points += value
return max(0, total_points)
def update_style_deduction(file_path: str, violation_checker: ViolationChecker, student_name: str):
"""
Function to update the deduction for style violations in the given rating table
author: Lukas Horst
"""
wb = openpyxl.load_workbook(file_path, data_only=True)
ws = wb['Sheet1']
# Updating the name
ws[f'A1'].value = student_name
rows = ws.iter_rows(min_row=1, max_row=75, min_col=1, max_col=1)
for i, row in enumerate(rows):
cell = row[0]
if cell.value is not None:
# Updating the deduction for the author variable
if '__author__' in cell.value:
ws[f'C{i+1}'].value = -violation_checker.count_deduction(3)
ws[f'C{i + 1}'].font = Font(color='FF0000')
# All deductions except the author variable and docstrings
elif 'o.g. Fehler' in cell.value:
deduction = 0
for j in range(1, 10):
if j == 3 or j == 5:
continue
deduction -= violation_checker.count_deduction(j)
ws[f'C{i+1}'].value = deduction
ws[f'C{i+1}'].font = Font(color='FF0000')
# Deduction for docstrings
elif 'Abzug bei' in cell.value:
ws[f'C{i+1}'].value = -violation_checker.count_deduction(5)
ws[f'C{i + 1}'].font = Font(color='FF0000')
# Updating the function for the total points
elif 'Summe' in cell.value:
ws[f'C{i+1}'] = f'=MAX(0, SUM(C1:C{i}))'
break
wb.save(file_path)
wb.close()
def read_csv_file(file_path: str):
"""
Function to read a csv file and returns a list with each row in a dic
author: Lukas Horst
"""
with open(file_path, mode='r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
rows = []
for row in reader:
rows.append(row)
return rows
def write_csv_file(file_path: str, data: list[dict[str, str]]):
"""
Function to (over)write a csv file with the given data
author: Lukas Horst
"""
with open(file_path, mode='w', newline='', encoding='utf-8') as file:
fieldnames = list(data[0].keys())
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(data)
def update_rating(overall_rating_path: str, student_rating_path: str, student_name: str):
"""
Function to update the points of the given student
author: Lukas Horst
"""
csv_data = read_csv_file(overall_rating_path)
for row in csv_data:
if row['Vollständiger Name'] == student_name:
points = str(get_points(student_rating_path)).replace('.', ',')
row['Bewertung'] = points
write_csv_file(overall_rating_path, csv_data)
return
def main():
"""The function main is where execution begins."""
print('EPRgrader v3/221031 running on ', datetime.now(), ' [', platform.platform(terse=True), ' ',

View file

@ -1,87 +0,0 @@
__author__ = 'Lukas Horst'
import csv
import openpyxl
import pandas as pd
from openpyxl.styles import Font
from violation_checker import ViolationChecker
def get_points(file_path: str):
"""Returns the total points"""
data = pd.read_excel(file_path, usecols='A, C')
total_points = 0
for i in range(len(data)):
if data.iat[i, 0] == 'Summe':
break
value = data.iat[i, 1]
if pd.notna(value) and type(value) != str:
total_points += value
return max(0, total_points)
def update_style_deduction(file_path: str, violation_checker: ViolationChecker, student_name: str):
"""Function to update the deduction for style violations"""
wb = openpyxl.load_workbook(file_path, data_only=True)
ws = wb['Sheet1']
# Updating the name
ws[f'A1'].value = student_name
rows = ws.iter_rows(min_row=1, max_row=75, min_col=1, max_col=1)
for i, row in enumerate(rows):
cell = row[0]
if cell.value is not None:
# Updating the deduction for the author variable
if '__author__' in cell.value:
ws[f'C{i+1}'].value = -violation_checker.count_deduction(3)
ws[f'C{i + 1}'].font = Font(color='FF0000')
# All deductions except the author variable and docstrings
elif 'alle o.g. Fehler' in cell.value:
deduction = 0
for j in range(1, 10):
if j == 3 or j == 5:
continue
deduction -= violation_checker.count_deduction(j)
ws[f'C{i+1}'].value = deduction
ws[f'C{i+1}'].font = Font(color='FF0000')
# Deduction for docstrings
elif 'Abzug bei mangelden' in cell.value:
ws[f'C{i+1}'].value = -violation_checker.count_deduction(5)
ws[f'C{i + 1}'].font = Font(color='FF0000')
# Updating the function for the total points
elif 'Summe' in cell.value:
ws[f'C{i+1}'] = f'=MAX(0, SUM(C1:C{i}))'
break
wb.save(file_path)
wb.close()
def read_csv_file(file_path: str):
"""Function to read a csv file and returns a list with each row in a dic"""
with open(file_path, mode='r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
rows = []
for row in reader:
rows.append(row)
return rows
def write_csv_file(file_path: str, data: list[dict[str, str]]):
"""Function to (over)write a csv file with the given data"""
with open(file_path, mode='w', newline='', encoding='utf-8') as file:
fieldnames = list(data[0].keys())
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(data)
def update_rating(overall_rating_path: str, student_rating_path: str, student_name: str):
"""Function to update the points of the given student"""
csv_data = read_csv_file(overall_rating_path)
for row in csv_data:
if row['Vollständiger Name'] == student_name:
points = str(get_points(student_rating_path)).replace('.', ',')
row['Bewertung'] = points
write_csv_file(overall_rating_path, csv_data)
return