So erstellen Sie ein Traceback-Objekt

8

Ich möchte ein Traceback wie das von sys.exc_info () [2] zurückgegebene erstellen. Ich möchte keine Liste von Zeilen, ich möchte ein echtes Traceback-Objekt:

%Vor%

Wie kann ich das tun? Mein Ziel ist es, dass es den aktuellen Stapel minus ein Bild enthält, so dass es aussieht, als wäre der Anrufer der letzte Anruf.

    
Colton Leekly-Winslow 25.11.2014, 23:03
quelle

3 Antworten

10

Es gibt keine dokumentierte Möglichkeit, Traceback-Objekte zu erstellen.

Keine der Funktionen im traceback -Modul erstellt diese. Sie können natürlich auf den Typ als types.TracebackType zugreifen, aber wenn Sie seinen Konstruktor aufrufen Sie erhalten nur ein TypeError: cannot create 'traceback' instances .

Der Grund dafür ist, dass Trace-Backs Verweise auf Interna enthalten, auf die Sie in Python nicht zugreifen oder aus denen Sie nicht herauskommen können.

Sie können jedoch auf Stack-Frames zugreifen, und alles andere, was Sie zum Nachzeichnen einer Trace-Back benötigen, ist trivial. Sie können sogar eine Klasse mit den Attributen tb_frame , tb_lasti , tb_lineno und tb_next schreiben (mit den Informationen, die Sie von traceback.extract_stack und einer der inspect Funktionen), die genau wie eine Rückverfolgung zu jedem reinen Python-Code aussehen wird.

Also, es gibt eine gute Chance, was immer Sie wirklich wollen zu tun ist machbar, obwohl das, was du verlangst, nicht ist.

    
abarnert 25.11.2014, 23:21
quelle
4

Wenn Sie wirklich eine andere Bibliothek täuschen müssen - insbesondere eine, die in C geschrieben ist und die nicht-öffentliche API verwendet -, gibt es zwei Möglichkeiten, ein echtes Traceback-Objekt zu erhalten. Ich habe keines von beiden zuverlässig arbeiten lassen. Beide sind CPython-spezifisch und erfordern nicht nur die Verwendung der C-API-Schicht, sondern auch die Verwendung von nicht dokumentierten Typen und Funktionen, die sich jederzeit ändern können, und bieten das Potenzial für neue und aufregende Möglichkeiten zur Segmentierung Ihres Interpreters. Aber wenn Sie es versuchen möchten, können sie für den Anfang nützlich sein.

Der PyTraceBack -Typ ist nicht Teil der öffentlichen API. Aber (abgesehen davon, dass es im Python-Verzeichnis statt im Object-Verzeichnis definiert ist), ist es als C-API-Typ aufgebaut, nur nicht dokumentiert. Wenn Sie sich also traceback.h und traceback.c für deine Python-Version, du wirst sehen, dass ... naja, es gibt kein PyTraceBack_New , aber dort is a PyTraceBack_Here , das ein neues Traceback erstellt und es in die aktuelle Ausnahmeinfo einfügt. Ich bin mir nicht sicher, ob es gültig ist, das zu nennen, es sei denn, es gibt eine aktuelle Ausnahme, und wenn es eine aktuelle Ausnahme gibt, könntest du es vielleicht durch Mutation so verfälschen, aber mit ein bisschen Versuch und Absturz oder lesen Sie den Code, hoffentlich können Sie dies zum Funktionieren bringen:

%Vor%

Als interessante Alternative können wir versuchen, ein Traceback-Objekt im laufenden Betrieb zu mutieren. Um ein Traceback-Objekt zu erhalten, müssen Sie nur eine Exception auslösen und abfangen:

%Vor%

Das einzige Problem ist, dass es auf Ihren Stack-Frame zeigt, nicht auf Ihren Anrufer, richtig? Wenn Rückverfolgungen änderbar wären, könnten Sie das leicht beheben:

%Vor%

Und es gibt auch keine Methoden, um diese Dinge zu setzen. Beachten Sie, dass es kein setattro hat, und dass getattro funktioniert, indem Sie ein __dict__ on the fly erstellen, also ist die einzige Möglichkeit, die wir in diesem Fall bekommen, die zugrunde liegende Struktur. Was du eigentlich mit ctypes.Structure aufbauen solltest, aber als schnellen Hack:

%Vor%

Nun, für einen normalen 64-Bit-Build von CPython, sind p8[:2] / p4[:4] der normale Objektheader und danach die tracebackspezifischen Felder, also p8[3] ist tb_frame und p4[8] und p4[9] sind die tb_lasti bzw. tb_lineno . Also:

%Vor%

Aber der nächste Teil ist ein bisschen schwieriger, denn tb_frame ist nicht wirklich ein PyObject * , es ist nur ein roher struct _frame * , also gehts zu frameobject.h , wo Sie sehen, dass es wirklich ein PyFrameObject * ist, damit Sie denselben Trick noch einmal verwenden können. Denken Sie daran, dass _ctypes.Py_INCREF das nächste Frame des Frames und Py_DECREF das Frame selbst ist, nachdem Sie p8[3] neu zugeordnet haben, um auf pf8[3] zu zeigen, oder sobald Sie versuchen, das Traceback zu drucken, werden Sie segfault und verlieren Ihre gesamte Arbeit Ich habe das geschrieben. :)

    
abarnert 26.11.2014 22:15
quelle
0

Wie andere hingewiesen haben, ist es nicht möglich, Traceback-Objekte zu erstellen. Sie können jedoch Ihre eigene Klasse mit denselben Eigenschaften schreiben:

%Vor%

Sie können Instanzen dieser Klasse weiterhin an einige Python-Funktionen übergeben. Vor allem traceback.print_exception(...) , das die gleiche Ausgabe erzeugt wie Pythons Standard excepthook.

Wenn Sie (wie ich) auf dieses Problem stoßen, weil Sie an einer PyQt-basierten GUI-App arbeiten, könnten Sie auch an einer umfassenderen Lösung interessiert sein, die in dieser Blogbeitrag .

    
Michael Herrmann 29.03.2018 17:02
quelle

Tags und Links