Mon expérience est en C # et je viens de commencer à programmer en Python. Lorsqu'une exception est levée, je souhaite généralement l'envelopper dans une autre exception qui ajoute plus d'informations, tout en affichant la trace complète de la pile. C'est assez simple en C #, mais comment faire en Python?
Par exemple. en C # je ferais quelque chose comme ceci:
try
{
ProcessFile(filePath);
}
catch (Exception ex)
{
throw new ApplicationException("Failed to process file " + filePath, ex);
}
En Python, je peux faire quelque chose de similaire:
try:
ProcessFile(filePath)
except Exception as e:
raise Exception('Failed to process file ' + filePath, e)
... mais cela perd le traçage de l'exception interne!
Edit: Je voudrais voir les deux messages d'exception et les deux traces de pile et corréler les deux. Autrement dit, je veux voir dans la sortie que l'exception X s'est produite ici, puis l'exception Y là - comme je le ferais en C #. Est-ce possible dans Python 2.6? Il semble que le mieux que je puisse faire jusqu'à présent (d'après la réponse de Glenn Maynard) est:
try:
ProcessFile(filePath)
except Exception as e:
raise Exception('Failed to process file' + filePath, e), None, sys.exc_info()[2]
Cela inclut à la fois les messages et les deux retraits, mais cela ne montre pas quelle exception s'est produite où dans le retraçage.
Réponses:
Python 2
C'est simple; transmettez le retraçage comme troisième argument à lever.
Faites toujours cela lorsque vous interceptez une exception et en relancez une autre.
la source
raise MyException(str(e)), ...
, etc.raise E() from tb
et.with_traceback(...)
raise
est la valeur à passer à l'exception (au cas où le premier argument serait une classe d'exception et non une instance). Donc , si vous voulez des exceptions d'échange, au lieu de le faireraise MyException(str(e)), None, sys.exc_info()[2]
, il est préférable d'utiliser:raise MyException, e.args, sys.exc_info()[2]
.from future.utils import raise_
etraise_(ValueError, None, sys.exc_info()[2])
.Python 3
En python 3, vous pouvez effectuer les opérations suivantes:
Cela produira quelque chose comme ceci:
la source
raise ... from ...
est en effet la bonne façon de faire cela en Python 3. Cela nécessite plus de votes positifs.Nakedible
Je pense que c'est parce que, malheureusement, la plupart des gens n'utilisent toujours pas Python 3.future
package pour y parvenir: python-future.org/compatible_idioms.html#raising-exceptions Par exemplefrom future.utils import raise_
etraise_(ValueError, None, sys.exc_info()[2])
.Python 3 a la clause
raise
...from
pour enchaîner les exceptions. La réponse de Glenn est excellente pour Python 2.7, mais elle n'utilise que le traçage de l'exception d'origine et supprime le message d'erreur et d'autres détails. Voici quelques exemples en Python 2.7 qui ajoutent des informations de contexte de la portée actuelle dans le message d'erreur de l'exception d'origine, mais gardent les autres détails intacts.Type d'exception connu
Cette variante d'
raise
instruction prend le type d'exception comme première expression, les arguments du constructeur de classe d'exception dans un tuple comme deuxième expression et le retraçage comme troisième expression. Si vous exécutez une version antérieure à Python 2.2, consultez les avertissements sursys.exc_info()
.Tout type d'exception
Voici un autre exemple plus général si vous ne savez pas quel type d'exceptions votre code pourrait avoir à détecter. L'inconvénient est qu'il perd le type d'exception et déclenche simplement une erreur RuntimeError. Vous devez importer le
traceback
module.Modifier le message
Voici une autre option si le type d'exception vous permet d'y ajouter du contexte. Vous pouvez modifier le message de l'exception, puis le relancer.
Cela génère la trace de pile suivante:
Vous pouvez voir qu'il montre la ligne où a
check_output()
été appelé, mais le message d'exception inclut maintenant la ligne de commande.la source
ex.strerror
vient-il? Je ne trouve aucun hit pertinent pour cela dans la documentation Python. Cela ne devrait-il pas être le casstr(ex)
?IOError
est dérivé deEnvironmentError
@hheimbuerger, qui fournit les attributserrorno
etstrerror
.Error
, par exemple ValueError, dans unRuntimeError
by catchException
? Si je reproduis votre réponse pour ce cas, le stacktrace est perdu.Dans Python 3.x :
ou simplement
qui se propagera
MyException
mais affichera les deux exceptions si elle ne sera pas gérée.Dans Python 2.x :
Vous pouvez empêcher l'impression des deux exceptions en supprimant l'
__context__
attribut. Ici, j'écris un gestionnaire de contexte qui l'utilise pour attraper et modifier votre exception à la volée: (voir http://docs.python.org/3.1/library/stdtypes.html pour une explication de leur fonctionnement)la source
e.__traceback__
attribut!Je ne pense pas que vous puissiez faire cela dans Python 2.x, mais quelque chose de similaire à cette fonctionnalité fait partie de Python 3. De PEP 3134 :
Comparaison avec C #:
Notez également que Java, Ruby et Perl 5 ne supportent pas non plus ce type de chose. Citant à nouveau:
la source
Pour une compatibilité maximale entre Python 2 et 3, vous pouvez utiliser
raise_from
dans lasix
bibliothèque. https://six.readthedocs.io/#six.raise_from . Voici votre exemple (légèrement modifié pour plus de clarté):la source
Vous pouvez utiliser ma classe CausedException pour enchaîner les exceptions dans Python 2.x (et même dans Python 3, cela peut être utile si vous souhaitez donner plus d'une exception interceptée comme cause d'une exception nouvellement levée). Peut-être que cela peut vous aider.
la source
Peut-être pourriez-vous saisir les informations pertinentes et les transmettre? Je pense à quelque chose comme:
la source
En supposant:
raise ... from
solution)vous pouvez utiliser une solution simple de la documentation https://docs.python.org/3/tutorial/errors.html#raising-exceptions :
Le résultat:
Il semble que l'élément clé soit le mot-clé simplifié «augmenter» qui est autonome. Cela relèvera l'exception dans le bloc except.
la source