web-dev-qa-db-fra.com

En Python, comment intercepter les avertissements comme s'il s'agissait d'exceptions?

Une bibliothèque tierce (écrite en C) que j'utilise dans mon code python émet des avertissements. Je veux pouvoir utiliser le tryexcept syntaxe pour gérer correctement ces avertissements. Existe-t-il un moyen de le faire?

79
Boris Gorelik

Pour citer le manuel python ( 27.6.4. Tester les avertissements ):

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)
37
Bobby Powers

Pour gérer les avertissements comme des erreurs, utilisez simplement ceci:

import warnings
warnings.filterwarnings("error")

Après cela, vous pourrez détecter les avertissements comme les erreurs, par exemple cela fonctionnera:

try:
    some_heavy_calculations()
except RuntimeWarning:
    import ipdb; ipdb.set_trace()

P.S. Ajout de cette réponse car la meilleure réponse dans les commentaires contient une faute d'orthographe: filterwarnigns au lieu de filterwarnings.

92
niekas

Si vous voulez simplement que votre script échoue sur les avertissements, vous pouvez utiliser:

python -W error foobar.py
14
azmeuk

Voici une variante qui rend plus clair comment travailler avec uniquement vos avertissements personnalisés.

import warnings
with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")

    # Call some code that triggers a custom warning.
    functionThatRaisesWarning()

    # ignore any non-custom warnings that may be in the list
    w = filter(lambda i: issubclass(i.category, UserWarning), w)

    if len(w):
        # do something with the first warning
        email_admins(w[0].message)
14
mcqwerty

Dans certains cas, vous devez utiliser des ctypes pour transformer les avertissements en erreurs. Par exemple:

str(b'test')  # no error
import warnings
warnings.simplefilter('error', BytesWarning)
str(b'test')  # still no error
import ctypes
ctypes.c_int.in_dll(ctypes.pythonapi, 'Py_BytesWarningFlag').value = 2
str(b'test')  # this raises an error
3
Collin Anderson