Lever un avertissement en Python sans interrompre le programme

189

J'essaye de déclencher un avertissement en Python sans faire planter / arrêter / interrompre le programme.

J'utilise la fonction simple suivante pour vérifier si l'utilisateur lui a passé un nombre non nul. Si tel est le cas, le programme devrait les avertir, mais continuer comme d'habitude. Cela devrait fonctionner comme le code ci-dessous, mais devrait utiliser la classe Warning(), Error()ou Exception()au lieu d'imprimer l'avertissement manuellement.

def is_zero(i):
   if i != 0:
     print "OK"
   else:
     print "WARNING: the input is 0!"
   return i

Si j'utilise le code ci-dessous et que je passe 0 à la fonction, le programme plante et la valeur n'est jamais retournée. Au lieu de cela, je veux que le programme continue normalement et informe simplement l'utilisateur qu'il a passé 0 à la fonction.

def is_zero(i):
   if i != 0:
     print "OK"
   else:
     raise Warning("the input is 0!")
   return i

Je veux pouvoir tester qu'un avertissement a été émis en le testant par unittest. Si j'imprime simplement le message, je ne peux pas le tester avec assertRaises in unittest.

Tomas Novotny
la source
Comment voulez-vous informer l'utilisateur exactement? par e-mail ou SMS? car cela peut être lié mais vous devez être précis.
aaronasterling
2
Pourquoi n'as-tu pas juste printle message?
sje397
1
@ sje397 Le fait est que je veux pouvoir tester qu'un avertissement a été émis en le testant par unittest. Si j'imprime simplement le message, je ne peux pas le faire avec assertRaises in unittest.
Tomas Novotny

Réponses:

157

Vous ne devriez pas raisel'avertissement, vous devriez utiliser warningsmodule. En le soulevant, vous générez une erreur plutôt qu'un avertissement.

SilentGhost
la source
1
Merci beaucoup. Et comment puis-je tester que l'avertissement a été lancé en utilisant unittest? Je ne peux plus utiliser assertRaises ().
Tomas Novotny
@Tomas Novotny vous pouvez capturer stdout et stderr, puis vérifier que les chaînes émises par votre avertissement se trouvent à l'intérieur.
Wheaties
15
@Tomas: Je n'ai jamais entendu parler du désir de tester l'avertissement, mais il existe un warnings.catch_warningsgestionnaire de contexte qui vous permettra de le faire.
SilentGhost
290
import warnings
warnings.warn("Warning...........Message")

Voir la documentation python: ici

nécromancien
la source
6
Et warnings.warn("blabla", DeprecationWarning)pour avoir ajouté une classe au type d'avertissement émis
shadi
52

Par défaut, contrairement à une exception, un avertissement ne s'interrompt pas.

Ensuite import warnings, il est possible de spécifier une classe Warnings lors de la génération d'un avertissement. Si l'un n'est pas spécifié, c'est littéralement UserWarningpar défaut.

>>> warnings.warn('This is a default warning.')
<string>:1: UserWarning: This is a default warning.

Pour utiliser simplement une classe préexistante à la place, par exemple DeprecationWarning:

>>> warnings.warn('This is a particular warning.', DeprecationWarning)
<string>:1: DeprecationWarning: This is a particular warning.

La création d'une classe d'avertissement personnalisée est similaire à la création d'une classe d'exception personnalisée:

>>> class MyCustomWarning(UserWarning):
...     pass
... 
... warnings.warn('This is my custom warning.', MyCustomWarning)

<string>:1: MyCustomWarning: This is my custom warning.

Pour les tests, considérez assertWarnsou assertWarnsRegex.


Comme alternative, en particulier pour les applications autonomes, considérez le loggingmodule. Il peut enregistrer les messages ayant un niveau de débogage , d' informations , d' avertissement , d' erreur , etc. Les messages de journal ayant un niveau d' avertissement ou supérieur sont par défaut imprimés sur stderr.

Acumenus
la source