In Python, how does one catch warnings as if they were exceptions?

110,280

Solution 1

To handle warnings as errors simply use this:

import warnings
warnings.filterwarnings("error")

After this you will be able to catch warnings same as errors, e.g. this will work:

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

P.S. Added this answer because the best answer in comments contains misspelling: filterwarnigns instead of filterwarnings.

Solution 2

To quote from the python handbook (27.6.4. Testing Warnings):

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)

Solution 3

If you just want your script to fail on warnings you can invoke python with the -W argument:

python -W error foobar.py

Solution 4

Here's a variation that makes it clearer how to work with only your custom warnings.

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)

Solution 5

In some cases, you need use ctypes to turn warnings into errors. For example:

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
Share:
110,280

Related videos on Youtube

Boris Gorelik
Author by

Boris Gorelik

Updated on August 07, 2021

Comments

  • Boris Gorelik
    Boris Gorelik over 2 years

    A third-party library (written in C) that I use in my python code is issuing warnings. I want to be able to use the try except syntax to properly handle these warnings. Is there a way to do this?

    • Fenikso
      Fenikso about 13 years
      Are those warning just text messages written do stderr?
    • Boris Gorelik
      Boris Gorelik about 13 years
      Fenikso: I don't know for sure, seems like real warnings
    • Fenikso
      Fenikso about 13 years
      How do you recognize "real warning"? I thought that in C you get real warning during compile.
    • Rosh Oxymoron
      Rosh Oxymoron about 13 years
      warnings.filterwarnings does exactly what you want, I don't understand what your issue with it is?
    • Boris Gorelik
      Boris Gorelik about 13 years
      @Fenikso, @Rosh Oxymoron you were right. My mistake. warnings.filterwarnigns('error') does the job. I can't find the original answer that proposed this solution
  • Unapiedra
    Unapiedra over 9 years
    Here is an answer, that tells you how to use the try except syntax.
  • z0r
    z0r about 7 years
    And if you just want to see a stack trace, the first two lines are all you need.
  • Praveen
    Praveen almost 7 years
    This is perfect. I just wanted my script to stop execution as soon as the warning was issued, so that I could print relevant debug information and fix the issue.
  • Pietro Battiston
    Pietro Battiston about 5 years
    This has the advantage, over niekas's answer, that if fnx returns something, you keep that result (and still can manage the warning).
  • naught101
    naught101 about 5 years
    You don't need the filterwarnings call in order to catch Warnings, at least in python 3. it just works.
  • AlanSE
    AlanSE about 5 years
    This answer is constructive simply for showing how to error only in certain warning types. For almost any large software project, if you do warnings.simplefilter('error') you won't get the traceback for the warning you saw in the logs, but instead get tracebacks from previously-filtered warnings. Using simplefilter is also the quickest way to arrive at your answer if you have some CLI invocation.
  • Biggsy
    Biggsy about 4 years
    The accepted answer does not answer the OP's question. This answer does. This is the answer I was looking for when my search found this question.
  • Biggsy
    Biggsy about 4 years
    This does not answer the OP's question, which was about handling wanrings, not testing them. However, the answer by niekas below does show how to handle warnings.
  • Steven M. Mortimer
    Steven M. Mortimer almost 4 years
    Just a note that the above function will not work if your function only intermittently returns a warning because in the event that fxn() does not return a warning, then w will be an empty list. If w is an empty list (i.e. []), then running the code will give you the following error: IndexError: list index out of range. If you're just looking to format or check properties of the captured warnings, then it's better to use a for-loop: for x in w: print(f'{x.category.__name__}: {str(x.message)}')
  • Ben Jeffrey
    Ben Jeffrey over 3 years
    Converting all warnings to errors can easily become problematic if you're using this within a larger script or software package. Can make things very hard to debug as well
  • normanius
    normanius about 3 years
    This approach is useful if one wants to handle warnings without interrupting program execution.
  • Paul Price
    Paul Price over 2 years
    To catch a specific warning type, e.g.: python -W error::RuntimeWarning foobar.py