warnings
— Control de advertencias¶
Código fuente: Lib/warnings.py
Los mensajes de advertencia suelen emitirse en situaciones en las que es útil alertar al usuario de alguna condición en un programa, cuando esa condición (normalmente) no justifica que se haga una excepción y se termine el programa. Por ejemplo, se puede emitir una advertencia cuando un programa utiliza un módulo obsoleto.
Los programadores de Python emiten advertencias llamando a la función warn()
definida en este módulo. (Los programadores de C usan PyErr_WarnEx()
; ver Manejo de excepciones para más detalles)
Los mensajes de advertencia se escriben normalmente en sys.stderr
, pero su disposición puede cambiarse de manera flexible, desde ignorar todas las advertencias hasta convertirlas en excepciones. La disposición de las advertencias puede variar en función de la warning category, el texto del mensaje de advertencia y la ubicación de la fuente donde se emite. Las repeticiones de una advertencia particular para la misma ubicación de la fuente son típicamente suprimidas.
El control de las advertencias consta de dos etapas: en primer lugar, cada vez que se emite una advertencia, se determina si se debe emitir un mensaje o no; en segundo lugar, si se debe emitir un mensaje, se le da formato y se imprime utilizando un gancho establecido por el usuario.
La determinación de si se debe emitir un mensaje de advertencia está controlada por el warning filter, que es una secuencia de reglas y acciones que coinciden. Se pueden añadir reglas al filtro llamando a filterwarnings()
y restablecer su estado por defecto llamando a resetwarnings()
.
La impresión de los mensajes de advertencia se realiza llamando a showwarning()
, que puede ser anulado; la implementación por defecto de esta función da formato al mensaje llamando a formatwarning()
, que también está disponible para su uso en implementaciones personalizadas.
Ver también
logging.captureWarnings()
permite manejar todas las advertencias con la infraestructura de registro estándar.
Categorías de advertencia¶
Hay una serie de excepciones incorporadas que representan categorías de advertencia. Esta categorización es útil para poder filtrar grupos de advertencias.
Aunque técnicamente se trata de built-in exceptions, están documentadas aquí, porque pertenecen al mecanismo de advertencias.
El código de usuario puede definir categorías de advertencia adicionales mediante la subclasificación de una de las categorías de advertencia estándar. Una categoría de advertencia siempre debe ser una subclase de la clase Warning
class.
Actualmente están definidas las siguientes clases de categorías de advertencias:
Clase |
Descripción |
---|---|
Esta es la clase principal para todas las clases que pertenecen a la categoría de advertencia. Es una subclase de |
|
La categoría por defecto para |
|
Categoría principal para advertencias sobre características obsoletas cuando esas advertencias están destinadas a otros desarrolladores de Python (ignoradas por defecto, a menos que sean activadas por el código en |
|
Categoría principal para las advertencias sobre características sintácticas dudosas. |
|
Categoría principal para las advertencias sobre características dudosas de tiempo de ejecución. |
|
Categoría principal para las advertencias sobre características obsoletas cuando esas advertencias están destinadas a los usuarios finales de aplicaciones escritas en Python. |
|
Categoría principal para las advertencias sobre las características que serán desaprobadas en el futuro (ignoradas por defecto). |
|
Categoría principal para las advertencias que se activan durante el proceso de importación de un módulo (se ignoran por defecto). |
|
Categoría principal para las advertencias relacionadas con Unicode. |
|
Categoría principal para las advertencias relacionadas con |
|
Base category for warnings related to resource usage (ignored by default). |
Distinto en la versión 3.7: Anteriormente DeprecationWarning
y FutureWarning
se distinguían en función de si una característica se eliminaba por completo o se cambiaba su comportamiento. Ahora se distinguen en función de su público objetivo y de la forma en que son manejados por los filtros de advertencia predeterminados.
El filtro de advertencias¶
El filtro de advertencias controla si las advertencias se ignoran, se muestran o se convierten en errores (planteando una excepción).
Conceptualmente, el filtro de advertencias mantiene una lista ordenada de especificaciones de filtros; cualquier advertencia específica se compara con cada especificación de filtro de la lista por turno hasta que se encuentra una coincidencia; el filtro determina la disposición de la coincidencia. Cada entrada es una tupla de la forma (action, message, category, module, lineno), donde:
action es una de las siguientes cadenas:
Valor
Disposición
"default"
imprime la primera ocurrencia de advertencias coincidentes para cada lugar (módulo + número de línea) donde se emite la advertencia
"error"
convertir las advertencias de coincidencia en excepciones
"ignore"
nunca imprime advertencias que coincidan
"always"
siempre imprime advertencias que coinciden
"module"
imprime la primera ocurrencia de advertencias coincidentes para cada módulo en el que se emite la advertencia (independientemente del número de línea)
"once"
imprime sólo la primera aparición de advertencias coincidentes, independientemente de la ubicación
message esa cadena de caracteres que contiene una expresión regular que debería coincidir con el inicio del mensaje de advertencia, sin discriminar mayúsculas ni minúsculas. En
-W
yPYTHONWARNINGS
, message es una cadena de caracteres literal que debería coincidir con el inicio del mensaje de advertencia discriminando mayúsculas y/o minúsculas, pero ignorando cualquier espacio en blanco al inicio de message.category es una clase (una subclase de
Warning
) de la cual la categoría de advertencia debe ser una subclase para poder coincidir.module es un cadena de caracteres que contiene una expresión regular, la cual debe coincidir exactamente (con mayúsculas y minúsculas) al nombre completo del módulo. En
-W
yPYTHONWARNINGS
, module es string literal que debe ser igual (con mayúsculas y minúsculas) al nombre completo del módulo, ignorando cualquier espacio en blanco al inicio o final de module.lineno es un número entero que el número de línea donde ocurrió la advertencia debe coincidir, o
0
para coincidir con todos los números de línea.
Como la clase Warning
se deriva de la clase Excepción
incorporada, para convertir una advertencia en un error simplemente lanzamos category(message)
.
Si se informa de una advertencia y no coincide con ningún filtro registrado, se aplica la acción «por defecto» (de ahí su nombre).
Descripción de los filtros de advertencia¶
El filtro de advertencias se inicializa con -W
options pasado a la línea de comandos del intérprete de Python y la variable de entorno PYTHONWARNINGS
. El intérprete guarda los argumentos de todas las entradas suministradas sin interpretación en sys.warnoptions
; el módulo warnings
los analiza cuando se importa por primera vez (las opciones no válidas se ignoran, después de imprimir un mensaje a sys.stderr
).
Los filtros de advertencia individuales se especifican como una secuencia de campos separados por dos puntos:
action:message:category:module:line
El significado de cada uno de estos campos es como se describe en El filtro de advertencias. Cuando se enumeran varios filtros en una sola línea (como en PYTHONWARNINGS
), los filtros individuales se separan por comas y los filtros que se enumeran más tarde tienen prioridad sobre los que se enumeran antes de ellos (ya que se aplican de izquierda a derecha, y los filtros aplicados más recientemente tienen prioridad sobre los anteriores).
Los filtros de advertencia comúnmente utilizados se aplican a todas las advertencias, a las advertencias de una categoría particular o a las advertencias planteadas por módulos o paquetes particulares. Algunos ejemplos:
default # Show all warnings (even those ignored by default)
ignore # Ignore all warnings
error # Convert all warnings to errors
error::ResourceWarning # Treat ResourceWarning messages as errors
default::DeprecationWarning # Show DeprecationWarning messages
ignore,default:::mymodule # Only report warnings triggered by "mymodule"
error:::mymodule # Convert warnings to errors in "mymodule"
Filtro de advertencia predeterminado¶
Por defecto, Python instala varios filtros de advertencia, que pueden ser anulados por la opción de línea de comandos -W
, la variable de entorno PYTHONWARNINGS
y llamadas a filterwarnings()
.
En versiones regulares, el filtro de advertencia por defecto tiene las siguientes entradas (en orden de precedencia):
default::DeprecationWarning:__main__
ignore::DeprecationWarning
ignore::PendingDeprecationWarning
ignore::ImportWarning
ignore::ResourceWarning
En una compilación de depuración, la lista de filtros de advertencia predeterminados está vacía.
Distinto en la versión 3.2: DeprecationWarning
es ahora ignorado por defecto además de PendingDeprecationWarning
.
Distinto en la versión 3.7: DeprecationWarning
se muestra de nuevo por defecto cuando se activa directamente por código en __main__
.
Distinto en la versión 3.7: BytesWarning
ya no aparece en la lista de filtros por defecto y en su lugar se configura a través de sys.warnoptions
cuando -b
se especifica dos veces.
Anulando el filtro por defecto¶
Los desarrolladores de aplicaciones escritas en Python pueden desear ocultar todas las advertencias de nivel de Python a sus usuarios por defecto, y sólo mostrarlas cuando se realizan pruebas o se trabaja de otra manera en la aplicación. El atributo sys.warnoptions
utilizado para pasar las configuraciones de los filtros al intérprete puede utilizarse como marcador para indicar si las advertencias deben ser desactivadas o no:
import sys
if not sys.warnoptions:
import warnings
warnings.simplefilter("ignore")
Se aconseja a los desarrolladores de pruebas de código Python que se aseguren de que todas las advertencias se muestren por defecto para el código que se está probando, usando un código como:
import sys
if not sys.warnoptions:
import os, warnings
warnings.simplefilter("default") # Change the filter in this process
os.environ["PYTHONWARNINGS"] = "default" # Also affect subprocesses
Por último, se aconseja a los desarrolladores de shells interactivos que ejecuten el código de usuario en un espacio de nombres distinto de __main__
que se aseguren de que los mensajes DeprecationWarning
se hagan visibles por defecto, utilizando un código como el siguiente (donde user_ns
es el módulo utilizado para ejecutar el código introducido interactivamente):
import warnings
warnings.filterwarnings("default", category=DeprecationWarning,
module=user_ns.get("__name__"))
Eliminación temporal de las advertencias¶
Si está utilizando un código que sabe que va a provocar una advertencia, como una función obsoleta, pero no quiere ver la advertencia (incluso cuando las advertencias se han configurado explícitamente a través de la línea de comandos), entonces es posible suprimir la advertencia utilizando el gestor de contexto catch_warnings
:
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
fxn()
Mientras que dentro del gestor de contexto todas las advertencias serán simplemente ignoradas. Esto le permite utilizar el código conocido como obsoleto sin tener que ver la advertencia, mientras que no suprime la advertencia para otro código que podría no ser consciente de su uso de código obsoleto. Nota: esto sólo puede garantizarse en una aplicación de un solo hilo. Si dos o más hilos utilizan el gestor de contexto catch_warnings
al mismo tiempo, el comportamiento es indefinido.
Advertencias de prueba¶
Para probar las advertencias planteadas por el código, use el administrador de contexto catch_warnings
. Con él puedes mutar temporalmente el filtro de advertencias para facilitar tus pruebas. Por ejemplo, haz lo siguiente para capturar todas las advertencias levantadas para comprobar:
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings(record=True) as w:
# Cause all warnings to always be triggered.
warnings.simplefilter("always")
# Trigger a warning.
fxn()
# Verify some things
assert len(w) == 1
assert issubclass(w[-1].category, DeprecationWarning)
assert "deprecated" in str(w[-1].message)
También se puede hacer que todas las advertencias sean excepciones usando error
en lugar de always
. Una cosa que hay que tener en cuenta es que si una advertencia ya se ha planteado debido a una regla de once
o default
, entonces no importa qué filtros estén establecidos, la advertencia no se verá de nuevo a menos que el registro de advertencias relacionadas con la advertencia se haya borrado.
Una vez que se cierra el gestor de contexto, el filtro de advertencias se restablece al estado en que se encontraba al entrar en el contexto. Esto evita que las pruebas cambien el filtro de advertencias de forma inesperada entre una prueba y otra, y que se produzcan resultados indeterminados en las pruebas. La función showwarning()
del módulo también se restaura a su valor original. Nota: esto sólo puede garantizarse en una aplicación de un solo hilo. Si dos o más hilos utilizan el gestor de contexto catch_warnings
al mismo tiempo, el comportamiento es indefinido.
Cuando se prueban múltiples operaciones que plantean el mismo tipo de advertencia, es importante probarlas de manera que se confirme que cada operación plantea una nueva advertencia (por ejemplo, establecer advertencias que se planteen como excepciones y comprobar que las operaciones plantean excepciones, comprobar que la longitud de la lista de advertencias siga aumentando después de cada operación, o bien suprimir las entradas anteriores de la lista de advertencias antes de cada nueva operación).
Actualización del código para las nuevas versiones de las dependencias¶
Las categorías de advertencia que interesan principalmente a los desarrolladores de Python (más que a los usuarios finales de aplicaciones escritas en Python) se ignoran por defecto.
En particular, esta lista de «ignorados por defecto» incluye DeprecationWarning
(para cada módulo excepto __main__
), lo que significa que los desarrolladores deben asegurarse de probar su código con advertencias típicamente ignoradas hechas visibles para recibir notificaciones oportunas de futuros cambios del API a última hora(ya sea en la biblioteca estándar o en paquetes de terceros).
En el caso ideal, el código tendrá un conjunto de pruebas adecuado, y el corredor de pruebas se encargará de habilitar implícitamente todas las advertencias cuando se ejecuten las pruebas (el corredor de pruebas proporcionado por el módulo unittest
hace esto).
En casos menos ideales, las aplicaciones pueden ser revisadas por el uso de interfaces desaprobadas pasando -Wd
al intérprete de Python (esto es la abreviatura de -W default
) o ajustando PYTHONWARNINGS=default
en el entorno. Esto permite el manejo por defecto de todas las advertencias, incluyendo aquellas que son ignoradas por defecto. Para cambiar la acción que se lleva a cabo para las advertencias encontradas puede cambiar el argumento que se pasa a -W
(por ejemplo -W error
). Consulte el indicador -W
para obtener más detalles sobre lo que es posible.
Funciones disponibles¶
- warnings.warn(message, category=None, stacklevel=1, source=None)¶
Emite una advertencia, o tal vez la ignorar o lanza una excepción. El argumento category, si se da, debe ser un warning category class; por defecto es
UserWarning
. Alternativamente, message puede ser una instanciaWarning
, en cuyo caso category será ignorada y se usarámessage.__class__
. En este caso, el texto del mensaje serástr(message)
. Esta función hace una excepción si la advertencia particular emitida es convertida en un error por el warnings filter. El argumento stacklevel puede ser usado por funciones de envoltura escritas en Python, como esta:def deprecation(message): warnings.warn(message, DeprecationWarning, stacklevel=2)
Esto hace que la advertencia se refiera al invocador de
deprecation()
, en lugar de a la fuente dedeprecation()
en sí (ya que esta última perdería el propósito del mensaje de advertencia).source, si se suministra, es el objeto destruido que emitió un
ResourceWarning
.Distinto en la versión 3.6: Añadido parámetro source.
- warnings.warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None)¶
Se trata de una interfaz de bajo nivel para la funcionalidad de
warn()
, pasando explícitamente el mensaje, la categoría, el nombre de archivo y el número de línea, y opcionalmente el nombre del módulo y el registro (que debería ser el diccionario__warningregistry__
del módulo). El nombre del módulo por defecto es el nombre de archivo con .py desmembrado; si no se pasa el registro, la advertencia nunca se suprime. message debe ser una cadena y category una subclase deWarning
o message puede ser una instanciaWarning
, en cuyo caso category será ignorada.module_globals, si se suministra, debe ser el espacio de nombres global en uso por el código para el que se emite la advertencia. (Este argumento se utiliza para apoyar la visualización de la fuente de los módulos que se encuentran en los archivos zip o en otras fuentes de importación que no son del sistema de archivos).
source, si se suministra, es el objeto destruido que emitió un
ResourceWarning
.Distinto en la versión 3.6: Añade el parámetro source.
- warnings.showwarning(message, category, filename, lineno, file=None, line=None)¶
Escriba una advertencia en un archivo. La implementación por defecto llama
formatwarning(message, category, filename, lineno, line)
y escribe la cadena resultante a file, que por defecto essys.stderr
. Puede reemplazar esta función con cualquier interlocutor asignando awarnings.showwarning
. line es una línea de código fuente que se incluirá en el mensaje de advertencia; si no se proporciona line,showwarning()
intentará leer la línea especificada por nombre de archivo y lineno.
- warnings.formatwarning(message, category, filename, lineno, line=None)¶
Formatea una advertencia de la manera estándar. Esto retorna una cadena que puede contener nuevas líneas incrustadas y termina en una nueva línea. line es una línea de código fuente a incluir en el mensaje de advertencia; si line no se suministra,
formatwarning()
intentará leer la línea especificada por el nombre de fichero filename y lineno.
- warnings.filterwarnings(action, message='', category=Warning, module='', lineno=0, append=False)¶
Inserta una entrada en la lista de warnings filter specifications. La entrada se inserta por defecto en el frente; si append es verdadero, se inserta al final. Esto comprueba los tipos de los argumentos, compila las expresiones regulares message y module, y las inserta como una tupla en la lista de filtros de aviso. Las entradas más cercanas al principio de la lista anulan las entradas posteriores de la lista, si ambas coinciden con una advertencia en particular. Los argumentos omitidos predeterminan un valor que coincide con todo.
- warnings.simplefilter(action, category=Warning, lineno=0, append=False)¶
Inserte una simple entrada en la lista de warnings filter specifications. El significado de los parámetros de la función es el mismo que el de
filterwarnings()
, pero no se necesitan expresiones regulares ya que el filtro insertado siempre coincide con cualquier mensaje de cualquier módulo siempre que la categoría y el número de línea coincidan.
- warnings.resetwarnings()¶
Reajusta el filtro de advertencias. Esto descarta el efecto de todas las llamadas previas a
filterwarnings()
, incluyendo la de las opciones de línea de comandos de-W
y las llamadas asimplefilter()
.
Gestores de contexto disponibles¶
- class warnings.catch_warnings(*, record=False, module=None, action=None, category=Warning, lineno=0, append=False)¶
Un gestor de contexto que copia y, al salir, restaura el filtro de advertencias y la función
showwarning()
. Si el argumento record esFalse
(por defecto) el gestor de contextos retornaNone
al entrar. Si record esTrue
, se retorna una lista que se va poblando progresivamente de objetos como se ve por una función personalizada deshowwarning()
(que también suprime la salida asys.stdout
). Cada objeto de la lista tiene atributos con los mismos nombres que los argumentos deshowwarning()
.El argumento module toma un módulo que será usado en lugar del módulo retornado cuando se importa
warnings
cuyo filtro será protegido. Este argumento existe principalmente para probar el propio módulowarnings
.Si el argumento action es diferente a
None
, los demás argumentos serán enviados a la funciónsimplefilter()
como si fueran invocados inmediatamente al entrar al contexto.Nota
El gestor
catch_warnings
funciona reemplazando y luego restaurando la funciónshowwarning()
del módulo y la lista interna de especificaciones del filtro. Esto significa que el gestor de contexto está modificando el estado global y por lo tanto no es seguro para los hilos.Distinto en la versión 3.11: Agrega los parámetros action, category, lineno y append.