162

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?

Mark Amery
  • 127,031
  • 74
  • 384
  • 431
Boris Gorelik
  • 27,385
  • 36
  • 123
  • 169

7 Answers7

195

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.

Asclepius
  • 49,954
  • 14
  • 144
  • 128
niekas
  • 6,999
  • 5
  • 37
  • 52
  • 8
    And if you just want to see a stack trace, the first two lines are all you need. – z0r Feb 23 '17 at 00:59
  • 5
    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. – Praveen Apr 26 '17 at 15:53
  • 2
    You don't need the `filterwarnings` call in order to catch `Warnings`, at least in python 3. it just works. – naught101 Apr 03 '19 at 06:37
  • 1
    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 Jan 24 '20 at 10:39
  • 1
    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 – Ben Jeffrey Nov 02 '20 at 14:35
66

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)
Asclepius
  • 49,954
  • 14
  • 144
  • 128
Bobby Powers
  • 2,695
  • 21
  • 15
  • 9
    [Here](http://stackoverflow.com/a/15934081/461597) is an answer, that tells you how to use the `try` `except` syntax. – Unapiedra Oct 10 '14 at 13:12
  • 1
    This has the advantage, over niekas's answer, that if ``fnx`` returns something, you keep that result (and still can manage the warning). – Pietro Battiston Mar 22 '19 at 18:22
  • 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. – Biggsy Jan 24 '20 at 10:42
  • 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)}')` – Steven M. Mortimer Jun 14 '20 at 21:29
  • This approach is useful if one wants to handle warnings without interrupting program execution. – normanius Mar 23 '21 at 12:01
30

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

python -W error foobar.py
azmeuk
  • 3,346
  • 3
  • 29
  • 56
19

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)
mcqwerty
  • 3,336
  • 2
  • 23
  • 24
6

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
Collin Anderson
  • 13,599
  • 6
  • 60
  • 53
  • 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. – AlanSE Apr 12 '19 at 14:08
4

Expanding on niekas answer, but using the catch_warnings context manager that resets the warnings behavior to default after context exit:

import warnings

with warnings.catch_warnings():
     warnings.simplefilter("error")
     # Code in this block will raise exception for a warning
# Code in this block will have default warning behaviour
CharlesB
  • 80,832
  • 27
  • 184
  • 208
0

Just for completeness, you can also export an env variable:

PYTHONWARNINGS=error /usr/bin/run_my_python_utility
pmav99
  • 1,822
  • 1
  • 20
  • 26