Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Catching (and then re-throw) warnings from my code

I want to catch and then re-throw warnings from my Python code, similarly to try/except clause. My purpose is to catch the warning and then re-throw it using my logger.

The warnings are issued from whatever packages I'm using, I would like something that is totally generic, exactly like the try/except clause.

How can I do that in Python >= v3.8?

like image 859
Xxxo Avatar asked Mar 25 '26 15:03

Xxxo


1 Answers

There are at least two ways to tackle this:

  1. Record the warnings and replay them
  2. Make warnings to behave like exceptions and break the control flow

Option 1: Record warnings and replay them

You could use warnings.catch_warnings with record=True to record the Warning objects. This way all your application code will get executed regardless of any warnings.

import warnings
import logging

logger = logging.getLogger(__name__)


class NotImportantWarning(UserWarning):
    ...


def do_something():
    warnings.warn("doing something", UserWarning)
    warnings.warn("This is not important", NotImportantWarning)


# Executing our main function and recording warnings
with warnings.catch_warnings(record=True) as recorded_warnings:
    do_something()

print("done")

# Handling warnings. You may log it here.
for w in recorded_warnings:
    if isinstance(w.message, NotImportantWarning):
        continue

    # re-issue warning
    warnings.warn_explicit(
        message=w.message,
        category=w.category,
        filename=w.filename,
        lineno=w.lineno,
        source=w.source,
    )
    # or use a logger
    logger.warning(str(w.message))

This will print then something like

done
<ipython-input-6-cc898056d044>:12: UserWarning: doing something
  warnings.warn("doing something", UserWarning)
doing something

Notes

  • Using the lower level warnings.warn_explicit to re-issue the warnings. The denefit over warnings.warn is that with the warn_explicit it is possible to retain the original filename and line number information.

Option 2: Make warnings to behave like exceptions

If you really want to break the control flow right at the warning, like with exceptions, it is possible with warnings.filterwarnings("error"):

import warnings

warnings.filterwarnings('error')


try:
    do_something()
except UserWarning as w:
    print(w)

Note: The code execution stops at the first warning. No code inside do_something after that warning will ever get executed.

like image 132
np8 Avatar answered Mar 28 '26 05:03

np8



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!