/** * 🩺 PYTHON TRACEBACK & FEHLER-DOLMETSCHER 🩺 * ============================================ * Basiert auf der didaktischen Fehlerforschung (Brett Becker et al., SIGCSE). * Übersetzt kryptische Python-Fehlermeldungen in einfühlsames, klares Deutsch * mit konkreten Handlungsanweisungen für Schülerinnen und Schüler. */ (function () { const ERROR_RULES = [ { type: "SyntaxError", pattern: /SyntaxError: (invalid syntax|expected ':'|was never closed|cannot assign to expression)/i, title: "✍️ Schreibweise- & Grammatikfehler (SyntaxError)", explanation: "Python versteht den Aufbau deines Codes an dieser Stelle nicht. Meist fehlt ein Satzzeichen oder eine Klammer.", causes: [ "Fehlender Doppelpunkt : am Ende von def, if, elif, else, for oder while.", "Eine geöffnete Klammer ( oder ein Anführungszeichen \" wurde nicht geschlossen.", "Verwechslung von Zuweisung = und Vergleich == in einer if-Bedingung." ], fix: "Prüfe die Zeile ganz genau: Steht am Zeilenende ein Doppelpunkt? Sind alle Klammern und Anführungszeichen paarweise geschlossen? Nutze if a == b: zum Vergleichen!" }, { type: "IndentationError", pattern: /IndentationError: (expected an indented block|unindent does not match)/i, title: "📐 Einrückungsfehler (IndentationError)", explanation: "Python nutzt Einrückungen (Standard: genau 4 Leerzeichen), um zu erkennen, welcher Code zu einer Funktion, `if`-Bedingung oder Schleife gehört.", causes: [ "Nach einem Doppelpunkt (def ...:, if ...:, for ...:) fehlt die Einrückung.", "Leerzeichen und Tabulatoren wurden versehentlich gemischt." ], fix: "Drücke nach dem Doppelpunkt Enter und rücke die Zeile mit Tab oder 4 Leerzeichen ein. Mit Umschalt + Tab kannst du Zeilen wieder nach links rücken." }, { type: "TypeError String Concatenation", pattern: /TypeError: can only concatenate str \(not "(int|float)"\) to str/i, title: "🔤 Text und Zahl vermischt (TypeError)", explanation: "Du versuchst einen Text (str) und eine Zahl (int/float) mit + zusammenzufügen.", causes: [ "In Python kann man Text und Zahlen nicht einfach addieren (z.B. \"Alter: \" + 16 schlägt fehl)." ], fix: "Nutze einen modernen f-String: f\"Alter: {alter}\" oder wandle die Zahl mit str(zahl) um." }, { type: "TypeError NoneType", pattern: /TypeError: 'NoneType' object is not (subscriptable|iterable|callable)/i, title: "🕳️ Zugriff auf 'None' (TypeError)", explanation: "Du versuchst auf ein Objekt zuzugreifen, das gar nicht existiert oder den Wert None hat.", causes: [ "Eine aufgerufene Funktion hat vergessen, ihr Ergebnis mit return zurückzugeben.", "Eine Listen-Methode wie liste.sort() oder liste.append() gibt immer None zurück (sie verändert die Liste direkt!)." ], fix: "Prüfe in deinen Funktionen, ob am Ende ein return ergebnis steht. Schreibe niemals x = liste.sort(), sondern nur liste.sort()." }, { type: "AttributeError", pattern: /AttributeError: '([^']+)' object has no attribute '([^']+)'/i, title: "🔍 Unbekanntes Attribut oder Methode (AttributeError)", explanation: "Python konnte an dem Objekt die gewünschte Methode oder Eigenschaft nicht finden.", causes: [ "Tippfehler im Namen der Methode oder Variable (z.B. anhängen statt append).", "Groß- und Kleinschreibung nicht beachtet (z.B. .Name statt .name).", "In der Klassen-Methode wurde self. vergessen (z.B. alter statt self.alter)." ], fix: "Überprüfe die Schreibweise des Attributs exakt Buchstabe für Buchstabe. Nutze in Klassen immer self.attributname." }, { type: "TypeError self missing", pattern: /TypeError: ([^\(]+)\(\) takes \d+ positional arguments? but \d+ were given/i, title: "🧩 Fehlendes 'self' in Methoden-Definition (TypeError)", explanation: "Eine Methode in einer Klasse erwartet weniger oder mehr Parameter als übergeben wurden.", causes: [ "Der klassische Anfängerfehler: Du hast im Methodenkopf das self als ersten Parameter vergessen! (z.B. def fahren(): statt def fahren(self):)." ], fix: "Schreibe in jeder Methode deiner Klasse als allerersten Parameter immer self: z.B. def beschleunigen(self, kmh):." }, { type: "IndexError", pattern: /IndexError: (list index out of range|string index out of range)/i, title: "🎯 Index außerhalb des gültigen Bereichs (IndexError)", explanation: "Du greifst auf eine Position (Index) in einer Liste oder einem String zu, die gar nicht existiert.", causes: [ "Off-by-One Fehler: In Python beginnt die Zählung bei 0! Eine Liste mit 3 Elementen hat nur die Indizes 0, 1, 2 (nicht 3).", "Die Liste ist noch leer." ], fix: "Prüfe die Länge der Liste mit len(liste). Das letzte Element erreichst du immer sicher mit liste[-1]." }, { type: "KeyError", pattern: /KeyError: (.+)/i, title: "🔑 Schlüssel nicht im Dictionary gefunden (KeyError)", explanation: "Du hast versucht, aus einem Dictionary dict[schluessel] einen Eintrag abzufragen, der nicht existiert.", causes: [ "Der gesuchte Key ist nicht im Dictionary vorhanden oder falsch geschrieben." ], fix: "Nutze die sichere Abfrage mit dict.get(key, standardwert) statt der eckigen Klammern, um Abstürze zu vermeiden!" }, { type: "NameError", pattern: /NameError: name '([^']+)' is not defined/i, title: "❓ Name nicht definiert (NameError)", explanation: "Python kennt das Wort oder die Variable an dieser Stelle nicht.", causes: [ "Die Variable wurde weiter unten oder in einer anderen Funktion definiert (Gültigkeitsbereich/Scope).", "Ein Tippfehler im Variablennamen.", "Ein Modul wie import math wurde noch nicht importiert." ], fix: "Prüfe, ob du die Variable vor ihrer Benutzung angelegt hast und ob alle benötigten Module oben mit import ... eingebunden sind." }, { type: "ValueError", pattern: /ValueError: (invalid literal for int\(\)|math domain error)/i, title: "⚠️ Ungültiger Wert (ValueError)", explanation: "Der Datentyp war zwar richtig, aber der übergebene Wert macht für diesen Befehl keinen Sinn.", causes: [ "Umwandlung von Text mit Buchstaben in eine Zahl (z.B. int(\"hallo\")).", "Mathematisch unzulässige Werte (z.B. Wurzel aus einer negativen Zahl)." ], fix: "Prüfe vorher mit text.isdigit(), ob der Text nur aus Ziffern besteht, oder sichere die Umwandlung mit try-except ValueError: ab." }, { type: "AssertionError", pattern: /AssertionError: (.+)/i, title: "🧪 Unittest fehlgeschlagen (AssertionError)", explanation: "Dein Programmcode läuft zwar ohne Absturz durch, liefert aber noch nicht das von der Aufgabe erwartete Ergebnis.", causes: [ "Ein Rechenfehler oder eine falsche Formel in der Funktion.", "Rückgabewert vergessen (return fehlt).", "Grenzfall nicht beachtet (z.B. 0 oder leere Liste)." ], fix: "Vergleiche die Rückgabe deiner Funktion mit dem in der Testmeldung geforderten Soll-Wert. Lies die Aufgabenbeschreibung noch einmal aufmerksam durch!" }, { type: "ZeroDivisionError", pattern: /ZeroDivisionError: division by zero/i, title: "➗ Division durch Null (ZeroDivisionError)", explanation: "In der Mathematik und in Python ist das Teilen durch 0 nicht erlaubt.", causes: [ "Der Nenner / Teiler hat den Wert 0." ], fix: "Sichere die Division mit einer if teiler != 0: Bedingung oder fange sie mit try-except ZeroDivisionError: ab." } ]; window.interpretiereTraceback = function (errorText) { if (!errorText || !errorText.trim()) { return { matched: false, name: "💡 Bitte füge eine Fehlermeldung ein", title: "💡 Bitte füge eine Fehlermeldung ein", explanation: "Kopiere deinen Traceback aus dem Terminal und füge ihn hier ein.", causes: ["Noch keine Fehlermeldung eingegeben."], fixes: ["Starte deinen Code oder Unittests, um eventuelle Fehler zu sehen."], fix: "Starte deinen Code oder Unittests, um eventuelle Fehler zu sehen." }; } for (let rule of ERROR_RULES) { if (rule.pattern.test(errorText)) { return { matched: true, type: rule.type, name: rule.title, title: rule.title, explanation: rule.explanation, causes: rule.causes, fixes: [rule.fix], fix: rule.fix }; } } return { matched: false, name: "🔍 Allgemeiner Python-Fehler", title: "🔍 Allgemeiner Python-Fehler", explanation: "Lies den Traceback immer von ganz unten nach oben: In der allerletzten Zeile nennt Python die genaue Fehlerart und Zeilennummer.", causes: ["Syntax- oder Logikfehler in deinem Code."], fixes: ["Überprüfe die in der letzten Zeile genannte Zeilennummer in deiner aufgabe.py Datei."], fix: "Überprüfe die in der letzten Zeile genannte Zeilennummer in deiner aufgabe.py Datei." }; }; // Exportiertes Objekt für Workspace & Widgets window.INTERPRETER = { translate: window.interpretiereTraceback }; // Widget rendern, falls Container vorhanden document.addEventListener("DOMContentLoaded", () => { const interpreterEl = document.getElementById("error-interpreter-widget"); if (!interpreterEl) return; const input = document.getElementById("error-input"); const btn = document.getElementById("btn-interpret-error"); const result = document.getElementById("error-result"); if (btn && input && result) { btn.addEventListener("click", () => { const res = window.interpretiereTraceback(input.value); document.getElementById("error-name").innerText = res.title; document.getElementById("error-explanation").innerHTML = res.explanation; const fixList = document.getElementById("error-fixes"); if (fixList) { fixList.innerHTML = (res.causes || []).map(c => `
  • ${c}
  • `).join("") + `
  • Lösung: ${res.fix}
  • `; } result.style.display = "block"; }); } }); })();