Ich schreibe viel Python-Code, der externe Bibliotheken verwendet. Häufig schreibe ich einen Fehler, und wenn ich den Code ausführe, wird in der Python-Konsole ein großer langer Traceback angezeigt. 99,999999% der Zeit liegt es an einem Codierungsfehler in meinem Code, nicht an einem Fehler im Paket. Der Traceback reicht jedoch bis zur Fehlerzeile im Paketcode. Entweder muss viel durch den Traceback gescrollt werden, um den von mir geschriebenen Code zu finden, oder der Traceback befindet sich so tief im Paket, dass mein eigener Code dies nicht tut. t erscheint sogar im Traceback.

Gibt es eine Möglichkeit, den Paketcode zu "blackboxen" oder irgendwie nur Traceback-Zeilen aus meinem Code anzuzeigen? Ich möchte die Möglichkeit haben, dem System anzugeben, von welchen Verzeichnissen oder Dateien ich Traceback sehen möchte.

39
J-bob 11 Aug. 2015 im 21:52

2 Antworten

Die Datei traceback.extract_tb (tb) würde ein Tupel von Fehlerrahmen im Format (Datei, Zeilennummer, Typ, Fehleranweisung) zurückgeben. Sie können damit spielen, um den Traceback zu formatieren. Siehe auch https://pymotw.com/2/sys/exceptions.html

import sys
import traceback

def handle_exception(ex_type, ex_info, tb):
    print ex_type, ex_info, traceback.extract_tb(tb)

sys.excepthook = handle_exception
2
Sanju 6 Okt. 2015 im 16:25

Wie andere vorgeschlagen haben, können Sie sys.excepthook verwenden:

Diese Funktion druckt einen bestimmten Traceback und eine Ausnahme für sys.stderr aus.

Wenn eine Ausnahme ausgelöst und nicht erfasst wird, ruft der Interpreter sys.excepthook mit drei Argumenten auf: der Ausnahmeklasse, der Ausnahmeinstanz und einem Traceback-Objekt. In einer interaktiven Sitzung geschieht dies unmittelbar bevor die Steuerung an die Eingabeaufforderung zurückgegeben wird. In einem Python-Programm geschieht dies kurz vor dem Beenden des Programms. Die Behandlung solcher Ausnahmen der obersten Ebene kann angepasst werden, indem sys.excepthook eine weitere Funktion mit drei Argumenten zugewiesen wird.

(Hervorhebung von mir)

Es ist möglich, einen von extract_tb (oder ähnlichen Funktionen) aus {{ X1}} Modul) basierend auf angegebenen Verzeichnissen.

Zwei Funktionen, die helfen können:

from os.path import join, abspath
from traceback import extract_tb, format_list, format_exception_only

def spotlight(*show):
    ''' Return a function to be set as new sys.excepthook.
        It will SHOW traceback entries for files from these directories. '''
    show = tuple(join(abspath(p), '') for p in show)

    def _check_file(name):
        return name and name.startswith(show)

    def _print(type, value, tb):
        show = (fs for fs in extract_tb(tb) if _check_file(fs.filename))
        fmt = format_list(show) + format_exception_only(type, value)
        print(''.join(fmt), end='', file=sys.stderr)

    return _print

def shadow(*hide):
    ''' Return a function to be set as new sys.excepthook.
        It will HIDE traceback entries for files from these directories. '''
    hide = tuple(join(abspath(p), '') for p in hide)

    def _check_file(name):
        return name and not name.startswith(hide)

    def _print(type, value, tb):
        show = (fs for fs in extract_tb(tb) if _check_file(fs.filename))
        fmt = format_list(show) + format_exception_only(type, value)
        print(''.join(fmt), end='', file=sys.stderr)

    return _print

Beide verwenden traceback.extract_tb. Es gibt "eine Liste von" vorverarbeiteten "Stack-Trace-Einträgen zurück, die aus dem Traceback-Objekt extrahiert wurden" ; Alle von ihnen sind Instanzen von traceback.FrameSummary (a benanntes Tupel). Jedes traceback.FrameSummary Objekt hat ein filename Feld, in dem der absolute Pfad der entsprechenden Datei gespeichert ist. Wir prüfen, ob es mit einem der Verzeichnispfade beginnt, die als separate Funktionsargumente bereitgestellt werden, um festzustellen, ob der Eintrag ausgeschlossen (oder beibehalten) werden muss.


Hier ist ein Beispiel :

Das enum Modul aus der Standardbibliothek erlaubt keine Wiederverwendung von Schlüsseln.

import enum
enum.Enum('Faulty', 'a a', module=__name__)

Ausbeuten

Traceback (most recent call last):
  File "/home/vaultah/so/shadows/main.py", line 23, in <module>
    enum.Enum('Faulty', 'a a', module=__name__)
  File "/home/vaultah/cpython/Lib/enum.py", line 243, in __call__
    return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
  File "/home/vaultah/cpython/Lib/enum.py", line 342, in _create_
    classdict[member_name] = member_value
  File "/home/vaultah/cpython/Lib/enum.py", line 72, in __setitem__
    raise TypeError('Attempted to reuse key: %r' % key)
TypeError: Attempted to reuse key: 'a'

Wir können Stack-Trace-Einträge auf unseren Code beschränken (in /home/vaultah/so/shadows/main.py ).

import sys, enum
sys.excepthook = spotlight('/home/vaultah/so/shadows')
enum.Enum('Faulty', 'a a', module=__name__)

Und

import sys, enum
sys.excepthook = shadow('/home/vaultah/cpython/Lib')
enum.Enum('Faulty', 'a a', module=__name__)

Geben Sie das gleiche Ergebnis:

  File "/home/vaultah/so/shadows/main.py", line 22, in <module>
    enum.Enum('Faulty', 'a a', module=__name__)
TypeError: Attempted to reuse key: 'a'

Es gibt eine Möglichkeit, alle Site-Verzeichnisse auszuschließen (in denen Pakete von Drittanbietern installiert sind - siehe site.getsitepackages)

import sys, site, jinja2
sys.excepthook = shadow(*site.getsitepackages())
jinja2.Template('{%}')
# jinja2.exceptions.TemplateSyntaxError: unexpected '}'
#     Generates ~30 lines, but will only display 4

Hinweis: Vergessen Sie nicht, sys.excepthook von sys .__ excepthook__ wiederherzustellen. Leider können Sie es nicht mit einem Kontextmanager "patchen" wiederherstellen.

4
vaultah 13 Okt. 2015 im 15:42