Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > de.comp.lang.python > #5505 > unrolled thread

Exception erneut werfen (re-raise)

Started byChristian Barthel <bch@online.de>
First post2019-06-23 13:04 +0200
Last post2019-06-23 17:42 +0200
Articles 3 — 2 participants

Back to article view | Back to de.comp.lang.python


Contents

  Exception erneut werfen (re-raise) Christian Barthel <bch@online.de> - 2019-06-23 13:04 +0200
    Re: [Python-de] Exception erneut werfen (re-raise) Peter Otten <__peter__@web.de> - 2019-06-23 15:24 +0200
      Re: [Python-de] Exception erneut werfen (re-raise) Christian Barthel <bch@online.de> - 2019-06-23 17:42 +0200

#5505 — Exception erneut werfen (re-raise)

FromChristian Barthel <bch@online.de>
Date2019-06-23 13:04 +0200
SubjectException erneut werfen (re-raise)
Message-ID<87blyo5zqn.fsf@x230.onfire.org>
Ich habe einen Code-Auszug der eine HTTP Bibliothek (requests
Modul) nutzt.  Diese wirft unterschiedliche Exceptions die ich
auffange.  Ich würde aber gerne die Exception an dieser Stelle
noch nicht fangen, sondern im Prinzip an den Aufrufer weitergeben
damit ich dann alle Exceptions in der Hauptschleife zentral
fangen kann und Loggen kann.

Dies geht; allerdings verliere ich dann die Möglichkeit auf die
lokalen Variablen der innersten Funktion (dort wo der Request
erzeugt und konstruiert wird) zuzugreifen.

Meine Idee im Moment wäre mittels "raise .. from.." eine neue
Exception zu generieren und die zusätzlichen Parameter als
Argumente mitzugeben.  Illustrativ und vereinfacht würde das in
etwa so aussehen:
 
   def foo():
       assert 0 == 1
   
   def bar():
       someVar = .. 
       try:
           foo()
       except AssertionError as e:
           raise AssertionError('foo ' + str(foo)) from e
   
Somit kann ein Aufrufer von bar() die Belegung von foo in einer
Fehlermeldung einbauen und die Daten der Ursprünglichen Exception
sind weiter vorhanden.   Mich würde interessieren ob es eine
Alternative oder einfachere Möglichkeit dazu geben würde und wie
(erfahrenere) Python Programmierer das lösen würden?

-- 
Christian Barthel <bch@online.de>

[toc] | [next] | [standalone]


#5506 — Re: [Python-de] Exception erneut werfen (re-raise)

FromPeter Otten <__peter__@web.de>
Date2019-06-23 15:24 +0200
SubjectRe: [Python-de] Exception erneut werfen (re-raise)
Message-ID<mailman.5.1561296279.29664.python-de@python.org>
In reply to#5505
Christian Barthel wrote:

> Ich habe einen Code-Auszug der eine HTTP Bibliothek (requests
> Modul) nutzt.  Diese wirft unterschiedliche Exceptions die ich
> auffange.  Ich würde aber gerne die Exception an dieser Stelle
> noch nicht fangen, sondern im Prinzip an den Aufrufer weitergeben
> damit ich dann alle Exceptions in der Hauptschleife zentral
> fangen kann und Loggen kann.
> 
> Dies geht; allerdings verliere ich dann die Möglichkeit auf die
> lokalen Variablen der innersten Funktion (dort wo der Request
> erzeugt und konstruiert wird) zuzugreifen.
> 
> Meine Idee im Moment wäre mittels "raise .. from.." eine neue
> Exception zu generieren und die zusätzlichen Parameter als
> Argumente mitzugeben.  Illustrativ und vereinfacht würde das in
> etwa so aussehen:
>  
>    def foo():
>        assert 0 == 1
>    
>    def bar():
>        someVar = ..
>        try:
>            foo()
>        except AssertionError as e:
>            raise AssertionError('foo ' + str(foo)) from e
>    
> Somit kann ein Aufrufer von bar() die Belegung von foo in einer
> Fehlermeldung einbauen und die Daten der Ursprünglichen Exception
> sind weiter vorhanden.   Mich würde interessieren ob es eine
> Alternative oder einfachere Möglichkeit dazu geben würde und wie
> (erfahrenere) Python Programmierer das lösen würden?

foo in deinem Beispiel ist allerdings eine globale Variable.

Wenn es nur darum geht, lokale Variablen im Callstack zu inspizieren, kommst 
du auch ohne erneutes try...except aus:

$ cat traceback_locals.py
import sys

def f(n):
    if n: return f(n-1)
    assert False

try:
    f(3)
except:
   etype, exc, tb = sys.exc_info()
   while True:
       tb = tb.tb_next
       if tb is None:
           break
       print(tb.tb_frame.f_locals)
 
$ python3 traceback_locals.py 
{'n': 3}
{'n': 2}
{'n': 1}
{'n': 0}

Das ist nur zur Demonstration, Editoren/IDEs mit Python-Support sollten den 
Zugriff auf den Callstack bieten, ohne dass du eine Zeile extra schreiben 
musst.

Oft will man allerdings gezielt zusätzliche Informationen übermitteln oder 
Lowlevel-Exceptions in anwendungsspezifische Ausnahmen "übersetzen". Dann 
ist dein Vorgehen das Mittel der Wahl. Ich ziehe jedoch unbearbeitete 
Werte vor, die man bei Bedarf nicht mühsam aus einem String herausoperieren 
muss, also in etwa

class MyAssertionError(AssertionError):
    def __init__(self, message, foo=None):
        super().__init__(message, foo) 
        self.foo = foo

[toc] | [prev] | [next] | [standalone]


#5508 — Re: [Python-de] Exception erneut werfen (re-raise)

FromChristian Barthel <bch@online.de>
Date2019-06-23 17:42 +0200
SubjectRe: [Python-de] Exception erneut werfen (re-raise)
Message-ID<875zow5mv8.fsf@x230.onfire.org>
In reply to#5506
Peter Otten <__peter__@web.de> writes:

> Christian Barthel wrote:
>
[..]
>>  
>>    def foo():
>>        assert 0 == 1
>>    
>>    def bar():
>>        someVar = ..
>>        try:
>>            foo()
>>        except AssertionError as e:
>>            raise AssertionError('foo ' + str(foo)) from e
>>    
>> Somit kann ein Aufrufer von bar() die Belegung von foo in einer
>> Fehlermeldung einbauen und die Daten der Ursprünglichen Exception
>> sind weiter vorhanden.   Mich würde interessieren ob es eine
>> Alternative oder einfachere Möglichkeit dazu geben würde und wie
>> (erfahrenere) Python Programmierer das lösen würden?
>
> foo in deinem Beispiel ist allerdings eine globale Variable.

Tut mir Leid, ich meinte nicht `foo` in dem Fall sondern
`someVar`.  Hatte ich mich beim aufbauen des Beispiels
verschaut.

> Wenn es nur darum geht, lokale Variablen im Callstack zu inspizieren, kommst 
> du auch ohne erneutes try...except aus:
>
> $ cat traceback_locals.py
> import sys
>
> def f(n):
>     if n: return f(n-1)
>     assert False
>
> try:
>     f(3)
> except:
>    etype, exc, tb = sys.exc_info()
>    while True:
>        tb = tb.tb_next
>        if tb is None:
>            break
>        print(tb.tb_frame.f_locals)
>  
> $ python3 traceback_locals.py 
> {'n': 3}
> {'n': 2}
> {'n': 1}
> {'n': 0}

Ok, das ist sicherlich auch ein interessanter Weg der mir so noch
nicht bekannt war.  Danke!

Was ich in meinem Beispiel nicht erwähnt habe ist, dass einige
Informationen auch als Instanzvariablen der Klasse existieren.
Diese müssten dann aus f_globals entnommen werden.

[..]
> Oft will man allerdings gezielt zusätzliche Informationen übermitteln oder 
> Lowlevel-Exceptions in anwendungsspezifische Ausnahmen "übersetzen". Dann 
> ist dein Vorgehen das Mittel der Wahl. 

Genau, das ist eigenlich das Hauptziel der Sache: zusätzliche
Informationen gezielt noch aufzubereiten und für den Aufrufer
zugänglich zu machen um erweiterte Diagnosen zu ermöglichen.


> Ich ziehe jedoch unbearbeitete Werte vor, die man bei Bedarf
> nicht mühsam aus einem String herausoperieren  muss, also in
> etwa [..] 

Das ich hier in dem Fall einen String verwendete war ebenso nur
illustrativ:  Ich habe mir dazu ebenfalls eigene Exception
Klassen gebaut die z.B. den HTTP Status Code beinhalten und
weitere Parameter wie etwa Proxy Einstellungen und tatsächlich
ausgeführter HTTP Befehl.

Danke für die Antwort! 
-- 
Christian Barthel <bch@online.de>

[toc] | [prev] | [standalone]


Back to top | Article view | de.comp.lang.python


csiph-web