J'ai un morceau de code similaire à ceci:
import sys
def func1():
func2()
def func2():
raise Exception('test error')
def main():
err = None
try:
func1()
except:
err = sys.exc_info()[1]
pass
# some extra processing, involving checking err details (if err is not None)
# need to re-raise err so caller can do its own handling
if err:
raise err
if __== '__main__':
main()
Quand func2
lève une exception Je reçois le retraçage suivant:
Traceback (most recent call last):
File "err_test.py", line 25, in <module>
main()
File "err_test.py", line 22, in main
raise err
Exception: test error
De là, je ne vois pas d'où vient l'exception. Le retraçage d'origine est perdu.
Comment puis-je conserver le retraçage d'origine et le ré-augmenter? Je veux voir quelque chose de similaire à ceci:
Traceback (most recent call last):
File "err_test.py", line 26, in <module>
main()
File "err_test.py", line 13, in main
func1()
File "err_test.py", line 4, in func1
func2()
File "err_test.py", line 7, in func2
raise Exception('test error')
Exception: test error
Un raise
vide déclenche la dernière exception.
# need to re-raise err so caller can do its own handling
if err:
raise
Si tu utilises raise something
Python n'a aucun moyen de savoir si something
était une exception qui vient d'être interceptée auparavant, ou une nouvelle exception avec une nouvelle trace de pile. C'est pourquoi il y a raise
qui préserve la trace de la pile.
Il est possible de modifier et relancer une exception:
Si aucune expression n'est présente,
raise
relance la dernière exception qui était active dans la portée actuelle. Si aucune exception n'est active dans la portée actuelle, une exceptionTypeError
est levée indiquant qu'il s'agit d'une erreur (si elle s'exécute sous IDLE, uneQueue.Empty
l'exception est levée à la place).Sinon,
raise
évalue les expressions pour obtenir trois objets, en utilisantNone
comme valeur des expressions omises. Les deux premiers objets sont utilisés pour déterminer le type et la valeur de l'exception.Si un troisième objet est présent et non
None
, il doit s'agir d'un objet traceback (voir la section La hiérarchie de types standard) et il est substitué à la place de l'emplacement actuel comme lieu où l'exception s'est produite. Si le troisième objet est présent et non un objet traceback ouNone
, une exceptionTypeError
est levée.La forme à trois expressions de
raise
est utile pour sur-lever une exception de manière transparente dans une clauseexcept
, maisraise
sans expression doit être préféré si l'exception doit être re -raisé était la dernière exception active dans le champ d'application actuel.
Donc, si vous souhaitez modifier l'exception et la renvoyer, vous pouvez le faire:
try:
buggy_code_which_throws_exception()
except Exception as e:
raise Exception, "The code is buggy: %s" % e, sys.exc_info()[2]
Vous pouvez obtenir beaucoup d'informations sur l'exception via la sys.exc_info()
avec le module traceback
essayez l'extension suivante de votre code.
import sys
import traceback
def func1():
func2()
def func2():
raise Exception('test error')
def main():
try:
func1()
except:
exc_type, exc_value, exc_traceback = sys.exc_info()
# Do your verification using exc_value and exc_traceback
print "*** print_exception:"
traceback.print_exception(exc_type, exc_value, exc_traceback,
limit=3, file=sys.stdout)
if __== '__main__':
main()
Cela s'imprimerait, semblable à ce que vous vouliez.
*** print_exception:
Traceback (most recent call last):
File "err_test.py", line 14, in main
func1()
File "err_test.py", line 5, in func1
func2()
File "err_test.py", line 8, in func2
raise Exception('test error')
Exception: test error
Bien que la réponse de @ Jochen fonctionne bien dans le cas simple, elle n'est pas capable de gérer des cas plus complexes, où vous n'attrapez et ne relancez pas directement, mais vous êtes pour une raison donnée l'exception en tant qu'objet et souhaitez réinjecter complètement nouveau contexte (c'est-à-dire si vous devez le gérer dans un processus différent).
Dans ce cas, je propose ce qui suit:
Avant de faire cela, définissez un nouveau type d'exception que vous renverrez plus tard ...
class ChildTaskException(Exception):
pass
Dans le code incriminé ...
import sys
import traceback
try:
# do something dangerous
except:
error_type, error, tb = sys.exc_info()
error_lines = traceback.format_exception(error_type, error, tb)
error_msg = ''.join(error_lines)
# for example, if you are doing multiprocessing, you might want to send this to another process via a pipe
connection.send(error_msg)
Renouveler ...
# again, a multiprocessing example of receiving that message through a pipe
error_msg = pcon.recv()
raise ChildTaskException(error_msg)
Votre fonction principale doit ressembler à ceci:
def main():
try:
func1()
except Exception, err:
# error processing
raise
Il s'agit de la méthode standard de traitement (et de ré-augmentation) des erreurs. Voici une démonstration du codepad.