La réponse à cette question dépend de la version de Python que vous utilisez.
En Python 3
C'est simple : les exceptions sont dotées d'une __traceback__
qui contient le retour de trace. Cet attribut est également accessible en écriture, et peut être défini de manière pratique à l'aide de la commande with_traceback
méthode des exceptions :
raise Exception("foo occurred").with_traceback(tracebackobj)
Ces caractéristiques sont décrites de façon minimale dans le cadre de la raise
documentation.
Tout le mérite pour cette partie de la réponse revient à Vyctor, qui a d'abord publié cette information . Je l'inclus ici uniquement parce que cette réponse est bloquée au sommet, et que Python 3 devient plus courant.
En Python 2
C'est ennuyeusement complexe. Le problème avec les tracebacks, c'est qu'ils ont des références aux frames de la pile, et les frames de la pile ont des références aux tracebacks qui ont des références aux frames de la pile qui ont des références à... vous voyez le genre. Cela pose des problèmes au ramasseur d'ordures. (Merci à ecatmur pour avoir été le premier à le signaler).
La bonne façon de résoudre ce problème serait d'opérer chirurgicalement briser le cycle après avoir quitté le except
ce que fait Python 3. La solution de Python 2 est beaucoup plus laide : on vous fournit une fonction ad-hoc, sys.exc_info()
qui ne fonctionne qu'à l'intérieur de la except
clause . Il renvoie un tuple contenant l'exception, le type d'exception et la trace de l'exception en cours de traitement.
Donc si vous êtes à l'intérieur du except
vous pouvez utiliser la sortie de la clause sys.exc_info()
ainsi que le traceback
pour faire diverses choses utiles :
>>> import sys, traceback
>>> def raise_exception():
... try:
... raise Exception
... except Exception:
... ex_type, ex, tb = sys.exc_info()
... traceback.print_tb(tb)
... finally:
... del tb
...
>>> raise_exception()
File "<stdin>", line 3, in raise_exception
Mais comme votre édition l'indique, vous essayez d'obtenir le retour de trace qui serait ont été imprimés si votre exception n'avait pas été traitée, après qu'elle ait été déjà ont été traitées. C'est une question beaucoup plus difficile. Malheureusement, sys.exc_info
renvoie à (None, None, None)
lorsqu'aucune exception n'est traitée. Autres éléments liés sys
Les attributs n'aident pas non plus. sys.exc_traceback
est déprécié et non défini lorsqu'aucune exception n'est gérée ; sys.last_traceback
semble parfaite, mais elle ne semble être définie que lors des sessions interactives.
Si vous pouvez contrôler la façon dont l'exception est levée, vous pouvez utiliser la fonction inspect
et un exception personnalisée pour stocker certaines des informations. Mais je ne suis pas tout à fait sûr de la façon dont cela fonctionnerait.
À vrai dire, attraper et renvoyer une exception est une chose plutôt inhabituelle à faire. C'est peut-être le signe que vous devez quand même procéder à un remaniement.