Haz que `warnings.warn ()` de Python no se mencione a sí mismo

Mi ejemplo mínimo es

#!/usr/bin/python3 import warnings warnings.warn('Run Forest run!', stacklevel=2) warnings.warn('Run Forest run!') 

y saldrá

 sys:1: UserWarning: Run Forest run! ./file.py:6: UserWarning: Run Forest run! warnings.warn('Run Forest run!') 

La primera línea me da poca información. La segunda línea es perfecta, me da el archivo de origen y el número de línea … pero me gustaría deshacerme de la tercera línea redundante. ¿Es eso posible?

Resulta que es posible dejar que warnings.warn() recopile toda la información y simplemente disfrazar la forma en que se imprime la información:

 #!/usr/bin/python3 import warnings def warning_on_one_line(message, category, filename, lineno, file=None, line=None): return '%s:%s: %s: %s\n' % (filename, lineno, category.__name__, message) warnings.formatwarning = warning_on_one_line warnings.warn('Run Forest run!', stacklevel=2) warnings.warn('Run Forest run!') 

Salida:

 sys:1: UserWarning: Run Forest run! ./file.py:15: UserWarning: Run Forest run! 

Fuente: módulo de Python de la semana.

La razón por la que obtiene la línea “redundante” es porque si no proporciona el parámetro de nivel de stacklevel , el nivel de stacklevel predeterminado es 1, que básicamente le dice al usuario la línea exacta de código de la cual se originó la advertencia, que es su llamada a la función de advertencia warnings.warn('Run Forest Run!') .

Si no está satisfecho con la forma en que funciona, puede usar la función warnings.warn_explicit() para personalizarla.

https://docs.python.org/3.1/library/warnings.html#available-functions

En caso de que esté tratando de detectar una excepción / error, y quiera ver tanto su mensaje de advertencia personalizado como su rastreo, es posible que prefiera usar traceback.print_exc ():

 import traceback import warnings def _formatwarning(msg, *a): try: traceback.print_exc() except: pass return str(msg) warnings.formatwarning = _formatwarning 

lo que hará que advertir (“su mensaje”) imprima el rastreo sin mencionar la llamada a warn ().

ACTUALIZACIÓN: en Python 3.6 necesita cambiar la firma de la función a:

 def _formatwarning(message, category, filename, lineno, line='')