Levantar advertencia en Python sin interrumpir el programa

4 minutos de lectura

avatar de usuario
Tomás Novotni

Estoy tratando de generar una advertencia en Python sin que el programa se bloquee/detenga/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 normalmente. Debería funcionar como el siguiente código, pero debería usar la clase Warning(), Error() o Exception() en 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 utilizo el siguiente código y paso 0 a la función, el programa falla y nunca se devuelve el valor. En cambio, quiero que el programa continúe normalmente y solo informar 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 assertRaises en unittest.

  • ¿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

    8 oct 2010 a las 15:05

  • ¿Por qué no simplemente print ¿el mensaje?

    – sje397

    8 oct 2010 a las 15:06

  • @ sje397 El punto es que quiero poder probar que unittest ha lanzado una advertencia probándola. Si simplemente imprimo el mensaje, no puedo hacerlo con assertRaises en unittest.

    – Tomás Novotny

    8 oct 2010 a las 15:16

import warnings
warnings.warn("Warning...........Message")

Consulte la documentación de Python: aquí

  • Y warnings.warn("blabla", DeprecationWarning) para agregar una clase al tipo de advertencia que se emite

    – Shadi

    30 de diciembre de 2019 a las 12:04

avatar de usuario
Fantasma silencioso

no deberías raise la advertencia, deberías estar usando warnings módulo. Al elevarlo, está generando un error, en lugar de una advertencia.

  • Muchísimas gracias. ¿Y cómo pruebo entonces que la Advertencia se ha lanzado usando unittest? Ya no puedo usar assertRaises().

    – Tomás Novotny

    8 oct 2010 a las 15:14

  • @Tomas Novotny puede capturar stdout y stderr, luego verifique que las cadenas emitidas por su advertencia se encuentren dentro.

    – trigo

    8 oct 2010 a las 15:33

  • @Tomas: Nunca escuché sobre el deseo de probar la advertencia, pero hay disponible un warnings.catch_warnings administrador de contexto que le permitirá hacer esto.

    – Fantasma silencioso

    8 oct 2010 a las 15:33

  • @SilentGhost Si está en su código, quiere probarlo, ¿no? docs.pytest.org/en/6.2.x/warnings.html#warns (aunque para ser justos, ese comentario tiene más de 10 años)

    -Eric

    2 de diciembre de 2021 a las 17:58


  • Esto no explica qué hacer en realidad. Esta debería ser la respuesta aceptada.

    – Gulzar

    28 abr a las 7:29


avatar de usuario
Asclepio

De forma predeterminada, a diferencia de una excepción, una advertencia no interrumpe.

Después import warningses posible especificar un Advertencias class al generar una advertencia. Si no se especifica uno, es literalmente UserWarning por defecto.

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

Para simplemente usar una clase preexistente en su lugar, 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 assertWarns o assertWarnsRegex.


Como alternativa, especialmente para aplicaciones independientes, considere la logging módulo. Puede registrar mensajes con un nivel de depurar, información, advertencia, erroretc. Registrar mensajes con un nivel de advertencia o superiores se imprimen de forma predeterminada en stderr.

Solo un pequeño fragmento de demostración

Estaba un poco desconcertado sobre cómo usar warnings.warn, por lo que proporciono aquí una breve demostración. Tenga en cuenta cómo se ejecuta / no se ejecuta la impresión (“código que se ejecuta después de la advertencia”) después warnings.warn / raise UserWarning. Además, warnings.warn imprime el mensaje de advertencia solo una vez.

>>> import warnings
>>> 
>>> warnings.warn("test warning"); print("code running after warning")
<stdin>:1: UserWarning: test warning
code running after warning
>>> 
>>> raise UserWarning('test warning'); print("code running after warning")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UserWarning: test warning
>>> 
>>> warnings.warn("test warning"); print("code running after warning")
code running after warning

¿Ha sido útil esta solución?