Seite 1 von 1

Exception Meldung erweitern...

Verfasst: Mittwoch 1. April 2009, 10:50
von jens
EDIT: Lösung zusammengefasst hier: [wiki]try...except[/wiki]

ich möchte einen Fehler (keinen bestimmten, sondern alle) mit einer Meldung erweitern, weiß gerade nicht wie... Also ungefähr so:

Code: Alles auswählen

try:
    ...mach irgendwas...
except Exception, err:
    raise Exception("Fehler bei BlaBlaBla: %s" % err)
Geht aber so nicht so schön, weil nicht der original Traceback angezeigt wird.

Eine andere Lösung kommt dem schon näher:

Code: Alles auswählen

try:
    ...mach irgendwas...
except Exception, err:
    print "Fehler bei BlaBla..."
    raise
Allerdings ist die zusätzliche Information ja nicht direkt im Traceback eingefügt, sondern wird ja nur mit dem print vorher ausgegeben...

Jemand eine Idee?

Verfasst: Mittwoch 1. April 2009, 11:38
von Zap
Was meinst du mit alle Fehler? Also ich hab in einigen meiner
Applikationen schonmal sowas eingebaut:

Code: Alles auswählen

# =========================================
# Exception Handling
def _excepthook(etype, evalue, etb):
    """ Catch all Unhandled Exceptions und report them to the logger """
    trace = traceback.format_exception(etype, evalue, etb)    
    # Do something with trace: "".join(trace))
    sys.__excepthook__(etype, evalue, etb)
   
if not hasattr(sys, "__excepthook__"):
    # python < 2.5
    sys.__excepthook__ = sys.excepthook
sys.excepthook = _excepthook
Das greift aber nur bei unhandled exceptions

Ergänzung: die drei variablen die du brauchst um einen Traceback selber zusammenzubauen bekommst du über sys.exc_info()

Verfasst: Mittwoch 1. April 2009, 11:46
von Zap
Vielleicht noch ergänzend als Beispiel hinterher:

Code: Alles auswählen

In [5]: try: argh
   ...: except Exception:
   ...:     trace = traceback.format_exception(*sys.exc_info())
   ...:     print "Meine Traceback:\n", "".join(trace)
   ...:
   ...:
Meine Traceback:
Traceback (most recent call last):
  File "<ipython console>", line 1, in <module>
NameError: name 'argh' is not defined

Verfasst: Mittwoch 1. April 2009, 11:54
von jens
Also in meinem Falle ist es ein Fehler im unittest. Dort soll schon der traceback "durchschlagen", aber halt mit zusätzlichen Info, ohne die einem der Fehler wenig sagen wird ;)

Verfasst: Mittwoch 1. April 2009, 12:10
von Zap
Ok ein bisschen gehackt, aber so kannst du die Tracceback message manipulieren

Code: Alles auswählen

In [28]: try: argh
   ....: except:
   ....:     etype, evalue, etb = sys.exc_info()
   ....:     evalue.args = ("Test %s" % (evalue.message,) ,)
   ....:     raise
   ....:
---------------------------------------------------------------------------
<type 'exceptions.NameError'>             Traceback (most recent call last)

C:\<ipython console> in <module>()

<type 'exceptions.NameError'>: Test name 'argh' is not defined

Verfasst: Mittwoch 1. April 2009, 12:33
von jens
Geht aber nicht immer. z.Z. bei einem IOError... Probier mal mit file("gibtsnicht", "r")
Außerdem gibt's eine warning, weil ".messages" deprecated ist.

Aber vom Prinzip ist es genau das was ich meinte.

Verfasst: Mittwoch 1. April 2009, 14:20
von HWK
Was spricht gegen Zaps Variante mit format_exc(). Das habe ich z.B. mal verwendet, um Exceptions in eine Messagebox umzuleiten.
MfG
HWK

Verfasst: Mittwoch 1. April 2009, 14:21
von jens
Es soll der normal Traceback ausgelöst werden. Ich will ihn nicht wirklich abfangen, sondern nur den Meldungstext erweitern...

Verfasst: Mittwoch 1. April 2009, 14:44
von str1442
Das sich doch auch nur Objekte, warum so kompliziert?

Code: Alles auswählen

In [1]: try:
   ...:     raise IOError("My Own Message.")
   ...: except BaseException, exception:
   ...:     raise exception.__class__("Old message was: '%s'." % exception.message)
   ...: 
---------------------------------------------------------------------------
IOError                                   Traceback (most recent call last)

/home/str1442/<ipython console> in <module>()

IOError: Old message was: 'My Own Message.'.
Man könnte auch eigene Exceptions definieren, die Zusatzinformationen mittels __init__ aufnehmen oder später setzen lassen und __str__ anpassen, damit das auch gedruckt wird. Man sollte nur Acht geben, das zusätzliche Exception Argumente in __init__ optional sind. Oder man manipuliert direkt <exception>.message und lässt das dann reraisen, müsste auch funktionieren.

Verfasst: Mittwoch 1. April 2009, 14:46
von Pekh
Ich weiß nicht, ob das jetzt das ist, was du willst, aber logging.exception verlangt einen String, der zusätzlich zum Traceback geloggt wird. Wenn du einen Handler dazupackst, der auf die Konsole loggt, könnte das dann was für dich sein?

Edit: Den obenstehenden Vorschlag mit den eigenen Ausnahmen finde ich allerdings noch eleganter. Verwende ich so an vielen Stellen - weiß nicht, warum ich bei deiner Problembeschreibung nicht darauf gekommen bin :?

Verfasst: Mittwoch 1. April 2009, 14:52
von jens
Nein so einfach ist das nicht... Also nochmal ein Beispiel:

Code: Alles auswählen

def test2():
    f = file("gibtsnicht", "r")

def test():
    test2()

test()
Ergibt diesen Traceback:

Code: Alles auswählen

Traceback (most recent call last):
  File "test.py", line 10, in <module>
    test()
  File "test.py", line 8, in test
    test2()
  File "test.py", line 5, in test2
    f = file("gibtsnicht", "r")
IOError: [Errno 2] No such file or directory: 'gibtsnicht'
Mit der Lösung:

Code: Alles auswählen

try:
    test()
except Exception, exception:
    raise exception.__class__("Old message was: %r" % repr(exception.args))
kommt aber nur:

Code: Alles auswählen

Traceback (most recent call last):
  File "test.py", line 15, in <module>
    raise exception.__class__("Old message was: %r" % repr(exception.args))
IOError: Old message was: "(2, 'No such file or directory')"
Die Stackliste ist also nicht so wirklich brauchbar...

Ich hätte eigentlich gern sowas:

Code: Alles auswählen

Traceback (most recent call last):
  File "test.py", line 10, in <module>
    test()
  File "test.py", line 8, in test
    test2()
  File "test.py", line 5, in test2
    f = file("gibtsnicht", "r")
IOError: ***Mein Info Text *** [Errno 2] No such file or directory: 'gibtsnicht'

Verfasst: Mittwoch 1. April 2009, 14:54
von EyDu
Ich würde einfach das gute alte Dekorator-Muster benutzen, dann kann man die verschiedenen Ebenen auch noch auseinander nehmen. Die Ausgabe kannst du darauf komfortabel zusammenbasteln.

Verfasst: Mittwoch 1. April 2009, 15:02
von str1442
Hm, ich hätte jetzt auf sowas getippt:

Code: Alles auswählen

In [1]: try:
   ...:     raise IOError("Text")
   ...: except IOError, exception:
   ...:     exception.message = "My New Message"
   ...:     raise exception
   ...: 
---------------------------------------------------------------------------
IOError                                   Traceback (most recent call last)

/media/Daten/bla/<ipython console> in <module>()

IOError: Text
Aber das funktioniert komischerweise nicht... Da müsste also der Traceback neu generiert werden. Kann das mal wer in Python 3 testen? Hätte man ja mit zb. einer Property für alle wichtigen Attribute einer Exception regeln können.

Ansonsten ist vielleicht noch das hier zu Exceptions und 3.0 interessant:

http://www.python.org/dev/peps/pep-3134/

Da gehts aber darum, verschiedene Exceptions zu "verbinden".

Verfasst: Donnerstag 2. April 2009, 10:55
von Zap
Ok ich geb auch noch einen zum Besten:

Code: Alles auswählen

In [1]: import sys

In [2]:

In [2]: try: open("doesnotexist")
   ...: except:
   ...:         etype, evalue, etb = sys.exc_info()
   ...:     evalue = etype("Additional Info\n%s" % evalue)
   ...:     raise etype, evalue, etb
   ...:
---------------------------------------------------------------------------
<type 'exceptions.IOError'>               Traceback (most recent call last)

c:\<ipython console> in <module>()

<type 'exceptions.IOError'>: Additional Info
[Errno 2] No such file or directory: 'doesnotexist'

Mich wundert sehr das .message deprecated ist. Muss ich mal nachschauen was die Alternative ist

Verfasst: Donnerstag 2. April 2009, 13:56
von jens
@Zap: Ja, das macht genau das was ich suche ;)

Verfasst: Freitag 3. April 2009, 14:31
von jerch
Zur Info:
Auf Ian Bickings Blog gibts eine schöne Übersicht und Diskussion zu verschiedensten Problemkonstellationen rum um Exceptions und mögliche Lösungen:
http://blog.ianbicking.org/2007/09/12/r ... xceptions/

Verfasst: Freitag 19. Juni 2009, 08:32
von jens
Nochmal zusammen gefasst hier: [wiki]try...except[/wiki]

Verfasst: Freitag 19. Juni 2009, 22:06
von str1442
Mit python 3.0 gibt es auch ein paar neue Felder auf Exceptions wie in etwa "__cause__". Man kann dann mit "raise MyException() from old_exception" diese Funktionalität nutzen. Näheres kann ich dazu aber nicht sagen, da ich mich damit noch nicht beschäftigt habe.