Holen Sie sich Ausnahmebeschreibung und Stapelverfolgung, was eine Ausnahme verursachte, alles als Zeichenfolge
-
14-10-2019 - |
Frage
Ich habe viele Beiträge über Stack Trace und Ausnahmen in Python gesehen. Aber nicht gefunden, was ich brauche.
Ich habe einen Stück Python 2.7 -Code, der eine Ausnahme hervorrufen kann. Ich würde es gerne fangen und a zuweisen Saite Die vollständige Beschreibung und die Stapelspur, die den Fehler verursachte (einfach alles, was wir auf der Konsole sehen). Ich brauche diese Zeichenfolge, um sie in ein Textfeld in der GUI zu drucken.
Etwas wie das:
try:
method_that_can_raise_an_exception(params)
except Exception as e:
print_to_textbox(complete_exception_description(e))
Das Problem ist: Was ist die Funktion? complete_exception_description
?
Lösung
Siehe das traceback
Modul, insbesondere das format_exc()
Funktion. Hier.
import traceback
try:
raise ValueError
except ValueError:
tb = traceback.format_exc()
else:
tb = "No error"
finally:
print tb
Andere Tipps
Lassen Sie uns einen anständig komplizierten Stacktrace erstellen, um zu demonstrieren, dass wir die vollständige Stacktrace erhalten:
def raise_error():
raise RuntimeError('something bad happened!')
def do_something_that_might_error():
raise_error()
Protokollieren Sie den vollen Stacktrace
Eine beste Praxis ist, dass ein Logger für Ihr Modul eingerichtet ist. Es wird den Namen des Moduls kennen und in der Lage sein, die Ebenen zu ändern (unter anderem Attribute, wie z. B. Handler).
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
Und wir können diesen Logger verwenden, um den Fehler zu erhalten:
try:
do_something_that_might_error()
except Exception as error:
logger.exception(error)
Welche Protokolle:
ERROR:__main__:something bad happened!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
Und so erhalten wir die gleiche Ausgabe wie bei einem Fehler:
>>> do_something_that_might_error()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
Nur die Zeichenfolge bekommen
Wenn Sie wirklich nur die Zeichenfolge wollen, verwenden Sie die traceback.format_exc
Funktion stattdessen und demonstrieren Sie die Protokollierung der Zeichenfolge hier:
import traceback
try:
do_something_that_might_error()
except Exception as error:
just_the_string = traceback.format_exc()
logger.debug(just_the_string)
Welche Protokolle:
DEBUG:__main__:Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
>>> import sys
>>> import traceback
>>> try:
... 5 / 0
... except ZeroDivisionError as e:
... type_, value_, traceback_ = sys.exc_info()
>>> traceback.format_tb(traceback_)
[' File "<stdin>", line 2, in <module>\n']
>>> value_
ZeroDivisionError('integer division or modulo by zero',)
>>> type_
<type 'exceptions.ZeroDivisionError'>
>>>
>>> 5 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
Sie nutzen sys.exc_info () Um die Informationen und Funktionen in der zu sammeln traceback
Modul, um es zu formatieren.Hier sind einige Beispiele für die Formatierung.
Die gesamte Ausnahmezeichenfolge ist bei:
>>> ex = traceback.format_exception(type_, value_, traceback_)
>>> ex
['Traceback (most recent call last):\n', ' File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: integer division or modulo by zero\n']
Mit Python 3 formatiert der folgende Code eine Exception
Objekt genau wie mit Verwendung erhalten würde traceback.format_exc()
:
import traceback
try:
method_that_can_raise_an_exception(params)
except Exception as ex:
print(''.join(traceback.format_exception(etype=type(ex), value=ex, tb=ex.__traceback__)))
Der Vorteil ist, dass nur der Exception
Objekt wird benötigt (dank der aufgezeichneten __traceback__
Attribut) und kann daher leichter als Argument an eine andere Funktion zur weiteren Verarbeitung übergeben werden.
Für diejenigen, die verwenden Python-3
Verwendung traceback
Modul und exception.__traceback__
Man kann die Stapel-Trace wie folgt extrahieren:
- Packe die aktuell Stack-Trace Verwenden
traceback.extract_stack()
- Entfernen Sie die letzten drei Elemente (da dies Einträge im Stapel sind, die mich zu meiner Debug -Funktion gebracht haben)
- append der
__traceback__
Aus dem Ausnahmebobjekt verwendettraceback.extract_tb()
- Formatieren Sie das Ganze mit Verwendung
traceback.format_list()
import traceback
def exception_to_string(excp):
stack = traceback.extract_stack()[:-3] + traceback.extract_tb(excp.__traceback__) # add limit=??
pretty = traceback.format_list(stack)
return ''.join(pretty) + '\n {} {}'.format(excp.__class__,excp)
Eine einfache Demonstration:
def foo():
try:
something_invalid()
except Exception as e:
print(exception_to_string(e))
def bar():
return foo()
Wir erhalten die folgende Ausgabe, wenn wir anrufen bar()
:
File "./test.py", line 57, in <module>
bar()
File "./test.py", line 55, in bar
return foo()
File "./test.py", line 50, in foo
something_invalid()
<class 'NameError'> name 'something_invalid' is not defined
Sie können auch das eingebaute Python-Modul in Betracht ziehen. cgitb, um einige wirklich gute, schön formatierte Ausnahmeinformationen zu erhalten, einschließlich lokaler Variablenwerte, Quellcodekontext, Funktionsparameter usw.
Zum Beispiel für diesen Code ...
import cgitb
cgitb.enable(format='text')
def func2(a, divisor):
return a / divisor
def func1(a, b):
c = b - 5
return func2(a, c)
func1(1, 5)
Wir erhalten diese Ausnahmeausgabe ...
ZeroDivisionError
Python 3.4.2: C:\tools\python\python.exe
Tue Sep 22 15:29:33 2015
A problem occurred in a Python script. Here is the sequence of
function calls leading up to the error, in the order they occurred.
c:\TEMP\cgittest2.py in <module>()
7 def func1(a, b):
8 c = b - 5
9 return func2(a, c)
10
11 func1(1, 5)
func1 = <function func1>
c:\TEMP\cgittest2.py in func1(a=1, b=5)
7 def func1(a, b):
8 c = b - 5
9 return func2(a, c)
10
11 func1(1, 5)
global func2 = <function func2>
a = 1
c = 0
c:\TEMP\cgittest2.py in func2(a=1, divisor=0)
3
4 def func2(a, divisor):
5 return a / divisor
6
7 def func1(a, b):
a = 1
divisor = 0
ZeroDivisionError: division by zero
__cause__ = None
__class__ = <class 'ZeroDivisionError'>
__context__ = None
__delattr__ = <method-wrapper '__delattr__' of ZeroDivisionError object>
__dict__ = {}
__dir__ = <built-in method __dir__ of ZeroDivisionError object>
__doc__ = 'Second argument to a division or modulo operation was zero.'
__eq__ = <method-wrapper '__eq__' of ZeroDivisionError object>
__format__ = <built-in method __format__ of ZeroDivisionError object>
__ge__ = <method-wrapper '__ge__' of ZeroDivisionError object>
__getattribute__ = <method-wrapper '__getattribute__' of ZeroDivisionError object>
__gt__ = <method-wrapper '__gt__' of ZeroDivisionError object>
__hash__ = <method-wrapper '__hash__' of ZeroDivisionError object>
__init__ = <method-wrapper '__init__' of ZeroDivisionError object>
__le__ = <method-wrapper '__le__' of ZeroDivisionError object>
__lt__ = <method-wrapper '__lt__' of ZeroDivisionError object>
__ne__ = <method-wrapper '__ne__' of ZeroDivisionError object>
__new__ = <built-in method __new__ of type object>
__reduce__ = <built-in method __reduce__ of ZeroDivisionError object>
__reduce_ex__ = <built-in method __reduce_ex__ of ZeroDivisionError object>
__repr__ = <method-wrapper '__repr__' of ZeroDivisionError object>
__setattr__ = <method-wrapper '__setattr__' of ZeroDivisionError object>
__setstate__ = <built-in method __setstate__ of ZeroDivisionError object>
__sizeof__ = <built-in method __sizeof__ of ZeroDivisionError object>
__str__ = <method-wrapper '__str__' of ZeroDivisionError object>
__subclasshook__ = <built-in method __subclasshook__ of type object>
__suppress_context__ = False
__traceback__ = <traceback object>
args = ('division by zero',)
with_traceback = <built-in method with_traceback of ZeroDivisionError object>
The above is a description of an error in a Python program. Here is
the original traceback:
Traceback (most recent call last):
File "cgittest2.py", line 11, in <module>
func1(1, 5)
File "cgittest2.py", line 9, in func1
return func2(a, c)
File "cgittest2.py", line 5, in func2
return a / divisor
ZeroDivisionError: division by zero
Wenn Sie dieselben Informationen erhalten möchten, wenn eine Ausnahme nicht behandelt wird, können Sie so etwas tun. Tun import traceback
und dann:
try:
...
except Exception as e:
print(traceback.print_tb(e.__traceback__))
Ich benutze Python 3.7.
meine 2 Cents:
import sys, traceback
try:
...
except Exception, e:
T, V, TB = sys.exc_info()
print ''.join(traceback.format_exception(T,V,TB))
Ich habe die folgende Helferklasse definiert:
import traceback
class TracedExeptions(object):
def __init__(self):
pass
def __enter__(self):
pass
def __exit__(self, etype, value, tb):
if value :
if not hasattr(value, 'traceString'):
value.traceString = "\n".join(traceback.format_exception(etype, value, tb))
return False
return True
Was ich später so verwenden kann:
with TracedExeptions():
#some-code-which-might-throw-any-exception
Und später kann es so konsumieren:
def log_err(ex):
if hasattr(ex, 'traceString'):
print("ERROR:{}".format(ex.traceString));
else:
print("ERROR:{}".format(ex));
(Hintergrund: Ich war wegen der Verwendung frustriert Promise
s zusammen mit Exception
s, was leider an einem Ort an einem Ort an einen Ort an einem anderen Ort an einem Ort angehoben wird, und daher ist es schwierig, das Traceback vom ursprünglichen Standort aus zu erhalten.