Search code examples
pythonloggingwarningspython-logging

Capturing a warning sent using logging.warning() from a library function, python


I call the Qsc function with various values, but for some values I receive the following warning:

Newton solve did not get close to desired tolerance. Final residual: 1.7380027083030736e-09

When this happens I want to capture the warning, so I can deal with these results differently.

I would like to solve the problem without changing the library.

This is the where the warning is sent from: logger.warning('Newton solve did not get close to desired tolerance. 'f'Final residual: {last_residual_norm}'), https://github.com/landreman/pyQSC/blob/1cb01ee6202144f3263150154164e72e74f7082c/qsc/newton.py#L59

I tried this:

import logging
import warnings
from qsc import Qsc

logging.captureWarnings(True)

with warnings.catch_warnings(record=True) as w:
    stel = Qsc(rc=[1, 0.20990165844612937], zs=[0, -0.008780473233288922], nfp=2, etabar=-1.699682124042855)
    warnings.warn("warn from warning")
    logging.warn("warn from logging")
    logging.warning("warning from logging")
    if w:
        for warning in w:
            logging.warning(str(warning.message))
            print("warning was captured\n")

And obtained this, meaning that I am only capturing the warning from warning.warn()

Newton solve did not get close to desired tolerance. Final residual: 1.7380027083030736e-09
WARNING:root:warning from logging
WARNING:root:warn from warning
warning was captured

Solution

  • You may be confusing a logging event at WARNING level (often emitted using the warning method of a logger) with the warnings module, which is a different thing. Hence, your catch_warnings() will not have the desired effect.

    To capture the warning: Add a filter to the logger which logs that message or handler which emits the message, which leads to the custom processing you want, and return False from that filter. For example:

    def newton_solution_fail_filter(record):
        if not is_newton_failed_message(record):  # e.g. by examing record.msg
            return True
        custom_function_to_solve_the_problem()  # do your thing to solve it
        return False  # prevent the message appearing
    
    logger_or_handler.addFilter(newton_solution_fail_filter)