Eine Ausnahme von einer höheren Ebene auslösen, a la Warnungen

8

In den Modulwarnungen ( Ссылка ) gibt es die Möglichkeit, eine Warnung zu erzeugen, die scheinbar erscheint von irgendwo früher im Stapel:

%Vor%

Gibt es ein Äquivalent für die Erhöhung von Fehlern? Ich weiß, dass ich einen Fehler mit einer alternativen Rückverfolgung auslösen kann, aber ich kann diese Rückverfolgung innerhalb des Moduls nicht schaffen, da es von früher kommen muss. Ich stelle mir etwas vor wie:

%Vor%

Der Grund ist, dass ich ein Modul mit der Funktion module.check_raise entwickle, das einen Fehler auslösen soll, der scheinbar von der Stelle kommt, an der die Funktion aufgerufen wird. Wenn ich einen Fehler innerhalb der Funktion module.check_raise erstelle, scheint er aus module.check_raise zu stammen, was unerwünscht ist.

Außerdem habe ich versucht, eine Dummy-Exception zu erzeugen, sie einzufangen und das Traceback weiterzuleiten, aber irgendwie wird tb_next None . Ich habe keine Ideen mehr.

Bearbeiten:

Ich möchte die Ausgabe dieses minimalen Beispiels (namens tb2.py):

%Vor%

um nur das zu sein:

%Vor%     
Joel 09.12.2015, 09:28
quelle

3 Antworten

2

Wenn ich richtig verstehe, möchten Sie die Ausgabe dieses minimalen Beispiels:

%Vor%

um nur das zu sein:

%Vor%

Tatsächlich ist es viel mehr Ausgang; Es gibt eine Ausnahmeverkettung, die behandelt werden kann, indem RuntimeError sofort behandelt wird, ihre __context__ entfernt und erneut erhöht wird, und es gibt eine weitere Rückverfolgungslinie für die RuntimeError selbst:

%Vor%

Soweit ich das beurteilen kann, ist es für reinen Python-Code nicht möglich, das Traceback einer Ausnahme zu ersetzen, nachdem es ausgelöst wurde. Der Interpreter hat die Kontrolle über das Hinzufügen, stellt jedoch nur dann den aktuellen Traceback zur Verfügung, wenn die Ausnahme behandelt wird. Es gibt keine API (nicht einmal bei der Verwendung von Tracing-Funktionen), um ein eigenes Traceback an den Interpreter zu übergeben, und Traceback-Objekte sind unveränderlich (dies wird von diesem Jinja-Hack mit C-Level-Problemen angegangen).

Wenn Sie also davon ausgehen, dass Sie an dem verkürzten Traceback interessiert sind, nicht für weitere programmatische Verwendung, sondern nur für benutzerfreundliche Ausgabe, ist Ihre beste Wette ein excepthook , das steuert, wie das Traceback auf die Konsole gedruckt wird. Um zu bestimmen, wo der Druckvorgang gestoppt werden soll, kann eine spezielle lokale Variable verwendet werden (dies ist etwas robuster als die Begrenzung des Tracebacks auf seine Länge minus 1 oder so). Dieses Beispiel benötigt Python 3.5 (für traceback.walk_tb ):

%Vor%

Dies ist die Ausgabe jetzt:

%Vor%     
Thomas Lotze 21.02.2016 14:55
quelle
1

Ich kann nicht glauben, dass ich dies posten

Wenn Sie das tun, gehen Sie gegen den Zen .

  

Sonderfälle sind nicht speziell genug, um die Regeln zu brechen.

Aber wenn du darauf bestehst, ist dein magischer Code.

check_raise.py

%Vor%

Dies ist reines Python, interferiert nicht mit sys.excepthook und selbst in einem try-Block wird es nicht mit except Exception: abgefangen, obwohl es mit except:

abgefangen wird

test.py

%Vor%

gibt Ihnen die (entsetzlich uninformative und extrem gefälschte) Rückverfolgungsnachricht, die Sie wünschen.

%Vor%     
Tadhg McDonald-Jensen 26.03.2016 03:12
quelle
0

BEARBEITEN: Die vorherige Version lieferte keine Zitate oder Erklärungen.

Ich schlage vor, PEP 3134 zu erwähnen, was in der Motivation steht :

  

Manchmal kann es für einen Ausnahmebehandler absichtlich nützlich sein       Raise eine Ausnahme, entweder um zusätzliche Informationen oder zu liefern       eine Ausnahme in einen anderen Typ übersetzen Das Attribut __cause__       bietet eine explizite Möglichkeit, die direkte Ursache einer Ausnahme aufzuzeichnen.

Wenn eine Exception mit einem Attribut __cause__ ausgelöst wird, hat die Traceback-Nachricht folgende Form:

%Vor%

Nach meinem Verständnis ist das genau das, was Sie zu erreichen versuchen; deutlich anzeigen, dass der Grund für den Fehler nicht Ihr Modul, sondern irgendwo anders ist. Wenn Sie stattdessen versuchen, Informationen zum Traceback wegzulassen, wie es Ihre Bearbeitung vorschlägt, wird Ihnen der Rest dieser Antwort nichts nützen.

Nur eine Anmerkung zur Syntax:

  

Das Attribut __cause__ für Ausnahmeobjekte wird immer initialisiert       Zu keiner. Es wird durch eine neue Form der 'raise' Anweisung gesetzt:

%Vor%      

entspricht:

%Vor%

Also wäre das einfachste Beispiel wie folgt:

%Vor%

Das gibt eine Fehlermeldung wie folgt:

%Vor%

Die erste Zeile der Ursache ist jedoch die Anweisung im try -Block von check_raise :

%Vor%

vor dem Erhöhen von err kann es (oder auch nicht) wünschenswert sein, den äußersten Rückverfolgungsrahmen von original_error zu entfernen:

%Vor%

Auf diese Weise ist die einzige Zeile im Traceback, die von check_raise zu kommen scheint, die letzte raise -Anweisung, die nicht mit reinem Python-Code weggelassen werden kann. Je nachdem, wie informativ die Nachricht ist, können Sie dies sehr deutlich machen Ihr Modul war nicht die Ursache des Problems:

%Vor%

Der Vorteil des Auslösens einer Ausnahme ist, dass die ursprüngliche Traceback-Nachricht nicht verloren geht, wenn der neue Fehler auftritt, was bedeutet, dass eine sehr komplexe Reihe von Ausnahmen ausgelöst werden kann und Python weiterhin alle relevanten Informationen korrekt anzeigt:

%Vor%

gibt mir die folgende Fehlermeldung:

%Vor%

Ja, es ist lang, aber es ist wesentlich informativer als:

%Vor%

Nicht zu erwähnen, dass der ursprüngliche Fehler auch dann noch verwendbar ist, wenn das Programm nicht endet:

%Vor%     
Tadhg McDonald-Jensen 24.01.2016 22:32
quelle

Tags und Links