Elevar advertencia en Python sin interrumpir el programa

189

Estoy tratando de generar una Advertencia en Python sin hacer que el programa se bloquee / pare / interrumpa.

Utilizo la siguiente función simple para verificar si el usuario le pasó un número distinto de cero. Si es así, el programa debería advertirles, pero continuar según lo normal. Debería funcionar como el código a continuación, pero debería usar class Warning(), Error()o en Exception()lugar de imprimir la advertencia manualmente.

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

Si uso el siguiente código y paso 0 a la función, el programa se bloquea y el valor nunca se devuelve. En cambio, quiero que el programa continúe normalmente y solo informe al usuario que pasó 0 a la función.

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

Quiero poder probar que se ha lanzado una advertencia probándola por unittest. Si simplemente imprimo el mensaje, no puedo probarlo con afirmarRaises en unittest.

Tomás Novotny
fuente
¿Cómo exactamente quieres notificar al usuario? a través de correo electrónico o SMS? porque eso se puede conectar pero debes ser específico.
aaronasterling
2
¿Por qué no solo printel mensaje?
sje397
1
@ sje397 El punto es que quiero poder probar que se ha lanzado una advertencia probándola por unittest. Si simplemente imprimo el mensaje, no puedo hacerlo con afirmarRaises en unittest.
Tomás Novotny

Respuestas:

157

No debería raisela advertencia, debería estar utilizando el warningsmódulo. Al aumentarlo, estás generando un error, en lugar de una advertencia.

SilentGhost
fuente
1
Muchas gracias. ¿Y cómo pruebo que la advertencia se ha lanzado usando unittest? Ya no puedo usar afirmarRaises ().
Tomás Novotny
@Tomas Novotny puede capturar stdout y stderr, luego verifique que las cadenas emitidas por su advertencia se encuentren dentro.
wheaties
15
@Tomas: Nunca escuché sobre el deseo de probar la advertencia, pero hay disponible un warnings.catch_warningsadministrador de contexto que te permitirá hacer esto.
SilentGhost
290
import warnings
warnings.warn("Warning...........Message")

Vea la documentación de Python: aquí

nigromante
fuente
66
Y warnings.warn("blabla", DeprecationWarning)por agregar una clase al tipo de advertencia emitida
shadi
52

Por defecto, a diferencia de una excepción, una advertencia no interrumpe.

Después import warnings, es posible especificar una clase de Advertencias al generar una advertencia. Si no se especifica uno, es literalmente UserWarningpor defecto.

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

Para usar simplemente una clase preexistente, por ejemplo DeprecationWarning:

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

Crear una clase de advertencia personalizada es similar a crear una clase de excepción personalizada:

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

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

Para la prueba, considere assertWarnso assertWarnsRegex.


Como alternativa, especialmente para aplicaciones independientes, considere el loggingmódulo. Puede registrar mensajes que tienen un nivel de depuración , información , advertencia , error , etc. Los mensajes de registro que tienen un nivel de advertencia o superior se imprimen por defecto en stderr.

Acumenus
fuente