Die Bewertung macht pygrader50 — pytest für die Funktion, pylint für den Stil. Beides zählt zur Note.
Format wie bisher in den BZZ-Templates, es ändert sich nichts am Inhalt:
| Datei | Inhalt |
|---|---|
unittests.json | welche Tests laufen, mit Timeout und Punkten |
lint.json | welche Dateien gelintet werden und wie viele Punkte das gibt |
pylintrc | pylint-Konfiguration |
[ { "name": "test_ggt", "function": "test_ggt", "timeout": 10, "points": 2 } ]
{ "files": ["main.py"], "ignore": [], "max": 5 }
Vorlage: examples/bundle im pygrader50-Repository.
Pro Datei, in dieser Reihenfolge:
<CLASSROOM>/autograders/<SLUG>/ im Config-Repo (das Bundle). Von der Lehrperson kontrolliert, für Lernende nicht editierbar..github/autograding/ im Studi-Repo. Der bisherige Ort, bleibt als Fallback.$PYGRADER50_CONFIG_DIR — nur für lokale Entwicklung.Fehlt beides, wird eine 0/0-Abgabe aufgezeichnet und im Log gewarnt. Der Job wird dabei absichtlich nicht rot: Eine Aufgabe ohne hinterlegte Bewertung ist ein Konfigurationsstand, kein Infrastrukturfehler.
Der Fallback auf .github/autograding/ erlaubt einen Rollout in Ruhe: Die
Templates funktionieren unverändert weiter, während die Bundles nach und nach
ins Config-Repo wandern.
classroom50/
└── <CLASSROOM>/
└── autograders/
└── <SLUG>/
├── unittests.json
├── lint.json
└── pylintrc
Nach dem Push bündelt der Workflow publish-pages den Ordner zu
autograders/<SLUG>.tar.gz; der Runner entpackt ihn und pygrader50 liest von
dort.
Kein autograder.py und keine tests.json in diesen Ordner legen.
Beides hat Vorrang vor dem Klassen-Default und würde damit die BZZ-Bewertung —
und insbesondere das Linting — für diese Aufgabe abschalten.
Ein Eintrag pro Testfall. passed heisst: volle Punktzahl erreicht. Jeder
Fall läuft als eigener pytest-Aufruf mit eigenem Timeout, damit ein
hängender Test die übrigen nicht mitreisst.
Ein einziger Eintrag Linting:
Punkte = pylint-Note / 10 * max passed = Punkte > 0
Eine Konventionsmeldung kostet also Punkte, färbt den Commit-Status aber nicht rot. Ohne diese Regel wäre praktisch jeder Commit rot.
Bei wenigen Statements und einem E…-Fehler wird die pylint-Note negativ und
auf 0 geklemmt. Linting: 0 ist in dem Fall korrekt, kein Defekt.
result.json verlangt ganze Zahlen, es wird gerundet. Der exakte Wert
steht im Feedback-Text.
### classroom50 autograde: 0/7 ## Unittests | name | feedback | expected | actual | points | max | | -------- | --------------- | -------- | ------ | ------ | --- | | test_ggt | Assertion Error | 8 | None | 0 | 2 | **0.00/2.00 Points (0.00%)**
Die Spalten expected und actual stammen aus dem pytest-Hook
pytest_assertrepr_compare, der vor dem Lauf ins Checkout kopiert wird.
Classroom 50 bringt mit tests.json einen deklarativen Weg mit. Die BZZ
benutzt ihn bewusst nicht:
tests.json vor dem Klassen-Default auf. Eine Aufgabe mit deklarativen Tests bekommt also kein Linting mehr.success nur, wenn alle Zeilen passed sind, und vergibt das Flag selbst.
Pro Aufgabe lässt sich beides nicht mischen — pro Klasse schon. Deshalb stehen
alle Aufgaben auf „autograder“: „default“.
result.json. CLI und Dashboard von Classroom 50 parsen strikt; alles Menschenlesbare gehört in den Release-Text.$GITHUB_OUTPUT. Status und Zusammenfassung leitet der Runner selbst aus result.json ab — ein Kanal weniger, der auseinanderlaufen kann.pip install -r requirements.txt aus dem Studi-Repo. pygrader50 bringt eigene, gepinnte Abhängigkeiten mit; das hält die Bewertung reproduzierbar. Ausserdem sind die alten Template-Pins auf Python 3.14 nicht lauffähig.cd /pfad/zum/studi-repo CLASSROOM=<CLASSROOM> \ ASSIGNMENT=<SLUG> \ SUBMISSION_TAG=submit/2026-08-13T12-00-00Z-abc1234 \ OWNER=anna \ python -m pygrader50 cat release-body.md
Ohne RUNNER_TEMP entfällt die Bundle-Suche, es zählt also
.github/autograding/ im Checkout. Details: CLI-Referenz.