Traceback von Warnungen abrufen

70

In numpy können wir np.seterr(invalid='raise')stattdessen einen Traceback für Warnungen erhalten, die einen Fehler auslösen (siehe diesen Beitrag ).

  • Gibt es eine allgemeine Möglichkeit, Warnungen zu verfolgen?
  • Kann ich Python erstellen, um einen Traceback zu geben, wenn eine Warnung ausgegeben wird?
Embert
quelle
Das Traceback-Modul? docs.python.org/2/library/traceback.html
Jayanth Koushik
Ich denke, keine der Antworten befriedigt Sie vollständig. Könntest du etwas mehr erklären, was du brauchst? :)
Mgab
@mgab Das Problem ist, dass es schwierig sein kann, eine Warnung zu finden, da sie keine Informationen enthält, in denen sie aufgerufen wurde. Wenn alle Warnungen schwerwiegend sind, wird das Programm nach der ersten Warnung beendet, die irgendwo aufgerufen wurde . Ich habe mich gefragt, ob es eine Möglichkeit gibt, Python anzuweisen, einen Traceback zu drucken, wenn eine Warnung ausgelöst wird, oder eine andere Möglichkeit, den Ursprung einer Warnung zu bestimmen.
Embert
Wenn die Warnung als Fehler ausgelöst wird, wird sie zwar beim ersten Mal beendet, aber Sie sollten einen Traceback erhalten, der den gesamten Stapel darüber meldet, wo dieser Fehler (oder die Warnung ursprünglich) ausgelöst wurde. Ich stimme jedoch zu, dass dies nicht optimal ist, insbesondere wenn Ihr Skript eine Weile dauert ... Ich habe meine Antwort mit einer meiner Meinung nach besseren Antwort auf Ihre Frage
aktualisiert

Antworten:

102

Sie können bekommen, was Sie wollen, indem Sie zuweisen warnings.showwarning. In der Dokumentation zum Warnmodul selbst wird empfohlen, dies zu tun, damit Sie nicht von der dunklen Seite der Quelle in Versuchung geführt werden . :) :)

Sie können diese Funktion durch eine alternative Implementierung ersetzen, indem Sie sie zuweisen warnings.showwarning.

Sie können eine neue Funktion definieren, die das tut, was warning.showwarningnormalerweise funktioniert, und zusätzlich den Stapel drucken. Dann platzieren Sie es anstelle des Originals:

import traceback
import warnings
import sys

def warn_with_traceback(message, category, filename, lineno, file=None, line=None):

    log = file if hasattr(file,'write') else sys.stderr
    traceback.print_stack(file=log)
    log.write(warnings.formatwarning(message, category, filename, lineno, line))

warnings.showwarning = warn_with_traceback

Danach druckt jede Warnung den Stack-Trace sowie die Warnmeldung. Beachten Sie jedoch, dass nichts passiert, wenn die Warnung ignoriert wird, weil sie nicht die erste ist. Sie müssen also Folgendes ausführen:

warnings.simplefilter("always")

Sie können eine ähnliche Steuerung erhalten, die Sie numpy.seterrüber die warningFilter des Moduls erhalten

Wenn Python jedes Mal, wenn es ausgelöst wird, und nicht nur beim ersten Mal jede Warnung meldet, können Sie Folgendes einschließen:

import warnings
warnings.simplefilter("always")

Sie können andere Verhaltensweisen erzielen, indem Sie andere Zeichenfolgen als Argumente übergeben. Mit derselben Funktion können Sie auch unterschiedliche Verhaltensweisen für Warnungen angeben, abhängig von dem Modul, das sie ausgelöst hat, der von ihnen bereitgestellten Nachricht, der Warnklasse, der Codezeile, die sie verursacht, usw.

Sie können die Liste in der Moduldokumentation überprüfen

Als Beispiel können Sie alle Warnungen so einstellen, dass Ausnahmen ausgelöst werden, mit Ausnahme DeprecationWarningsderjenigen, die vollständig ignoriert werden sollten:

import warnings
warnings.simplefilter("error")
warnings.simplefilter("ignore", DeprecationWarning)

Auf diese Weise erhalten Sie den vollständigen Traceback für jede Warnung, die als Fehler ausgegeben wird (nur die erste, da die Ausführung stoppt ... Sie können sie jedoch einzeln ansprechen und einen Filter erstellen, um diejenigen zu ignorieren, die Sie nicht hören möchten ungefähr wieder ...

mgab
quelle
3
Eine so nützliche Antwort. @embert sollte es nach all den Jahren wirklich als Antwort markieren.
Beldaz
28

Führen Sie Ihr Programm wie aus

python -W error myprogram.py

Das macht alle Warnungen fatal finden Sie hier für weitere Informationen

Jakob Bowyer
quelle
15
Das funktioniert. Gibt es jedoch eine Möglichkeit, Python zu zwingen, bei jeder Warnung einen Traceback zu drucken? Das Problem ist, dass bei Verwendung dieser Option das Programm bereits fehlschlägt, wenn während des Imports eine Verfallswarnung ausgegeben wird.
Embert
Wenn Sie einen Komponententest (oder ein Modul) benötigen, können Sie dies tun: Python -W Fehler -m Pytest
Omry Yadan
1

Sie können verwenden warnings.filterwarnings() ausgewählte Warnungen wie folgt in Ausnahmen umwandeln und einen Traceback erhalten:

import warnings
warnings.filterwarnings(
    'error', 'DateTimeField .* received a naive datetime',
    RuntimeWarning, 'django.db.models.fields'
)
mrts
quelle