It seems that temporarily suppressing warnings makes repeat warnings outside of the context manager display repeatedly.
Example:
import warnings
def f():
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=Warning)
print("A")
print("B")
warnings.warn("My warning")
f()
f()
Output:
A
B
tmp2.py:10: UserWarning: My warning
warnings.warn("My warning")
A
B
tmp2.py:10: UserWarning: My warning
warnings.warn("My warning")
Also, it does not seem to matter what action and category I give to simplefilter.
On the other hand, if I comment out the context catch_warnings block,
then the warning only displays once (as intended).
Why? Is it a bug? What am I missing?
This is a known bug
also asked about here
with a PR that seems pretty stale
Related
I want to raise an error if RuntimeWarning's occurred during pytest call. The problem is, the solutions below are doing nothing - each time I call pytest, RuntimeWarnings are still warnings:
import warnings
warnings.filterwarnings("error", category=RuntimeWarning)
# setup.cfg
filterwarnings =
error::RuntimeWarning
default
pytest -W error::RuntimeWarning
Meanwhile, ignore::RuntimeWarning (and error::DeprecationWorning)works as expected. What's wrong with my code?
Warning example below:
/app/src/pbp_data_platfrom/tests/test_service.py:20: RuntimeWarning: coroutine 'AsyncMock.__call__' was never awaited
assert send_events_mock.called_count == 1
Enable tracemalloc to get traceback where the object was allocated.
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
P.S. I know I can add the error option into filterwarning so it will raise an error each time any warning found (and it will work, I've tested it a couple of times). But this solution looks a bit clunky.
Here's a bit of Python pseudocode to illustrate a problem (I'm working in Python 3.8, although I doubt that matters much):
import warnings
from some_library import function, LibraryWarning # (a library that I do not control)
warning_log = []
with warnings.catch_warnings():
warnings.simplefilter("error")
try:
result = function()
except LibraryWarning as w:
warning_log.append(w)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
result = function()
The main purpose of this code is to produce result without any warnings cluttering up the screen. It accomplishes that. However, I also want to document any warnings that occur for later review. This code accomplishes that too, provided that function() only generates one warning. However, sometimes function() produces TWO warnings. Since I have to switch to ignoring warnings to get result, I never see the second warning and I can't append it to my log.
How can I perform a full accounting of all warnings generated, while still obtaining my final
result?
Thanks for your advice.
def a_warning_function():
warning_log = []
with warnings.catch_warnings():
warnings.simplefilter("error")
try:
result = function()
return result
except LibraryWarning as w:
warning_log.append(w)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
result = function()
return result
I have built a few off-the-shelf classifiers from sklearn and there are some expected scenarios where I know the classifier is bound to perform badly and not predict anything correctly. The sklearn.svm package runs without an error but raises the following warning.
~/anaconda/lib/python3.5/site-packages/sklearn/metrics/classification.py:1074: UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 due to no predicted samples.
'precision', 'predicted', average, warn_for)
I wish to suppress this warning and instead replace with a message to stdout, say for instance, "poor classifier performance".
Is there any way to suppress warnings in general?
Suppressing all warnings is easy with -Wignore (see warning flag docs)
The warnings module can do some finer-tuning with filters (ignore just your warning type).
Capturing just your warning (assuming there isn't some API in the module to tweak it) and doing something special could be done using the warnings.catch_warnings context manager and code adapted from "Testing Warnings":
import warnings
class MyWarning(Warning):
pass
def something():
warnings.warn("magic warning", MyWarning)
with warnings.catch_warnings(record=True) as w:
# Trigger a warning.
something()
# Verify some things
if ((len(w) == 1)
and issubclass(w[0].category, MyWarning)
and "magic" in str(w[-1].message)):
print('something magical')
I was just trying to catch an OptimizeWarning thrown by the scipy.optimize.curve_fit function, but I realized it was not recognized as a valid exception.
This is a non-working simple idea of what I'm doing:
from scipy.optimize import curve_fit
try:
popt, pcov = curve_fit(some parameters)
except OptimizeWarning:
print 'Maxed out calls.'
# do something
I looked around the docs but there was nothing there.
Am I missing something obvious or is it simply not defined for some reason?
BTW, this is the full warning I get and that I want to catch:
/usr/local/lib/python2.7/dist-packages/scipy/optimize/minpack.py:604: OptimizeWarning: Covariance of the parameters could not be estimated
category=OptimizeWarning)
You can require that Python raise this warning as an exception using the following code:
import warnings
from scipy.optimize import OptimizeWarning
warnings.simplefilter("error", OptimizeWarning)
# Your code here
Issues with warnings
Unfortunately, warnings in Python have a few issues you need to be aware of.
Multiple filters
First, there can be multiple filters, so your warning filter can be overridden by something else. This is not too bad and can be worked around with the catch_warnings context manager:
import warnings
from scipy.optimize import OptimizeWarning
with warnings.catch_warnings():
warnings.simplefilter("error", OptimizeWarning)
try:
# Do your thing
except OptimizeWarning:
# Do your other thing
Raised Once
Second, warnings are only raised once by default. If your warning has already been raised before you set the filter, you can change the filter, it won't raise the warning again.
To my knowledge, there unfortunately is not much you can do about this. You'll want to make sure you run the warnings.simplefilter("error", OptimizeWarning) as early as possible.
I am using the parseFile convenience method to read a css file but it is generating a huge amount of warning messages.
I have set validate=False but it is still printing the messages. I have tried to create a CSSParser object and initialising the log object and logging level to none but it is still printing warnings and errors. I looked in the source code and couldn't see where these message are being created so it might be in something that parseFile calls.
Is there any way of stopping the CSSParser.parseFile() from generating message like the ones below?
WARNING CSSStylesheet: Unknown #rule found. [3:43150:#-webkit-keyframes]
WARNING CSSStylesheet: Unknown #rule found. [3:43329: #-moz-keyframes]
WARNING CSSStylesheet: Unknown #rule found. [3:43496: #keyframes]
WARNING CSSStylesheet: Unknown #rule found. [3:43643: #-webkit-keyframes]
WARNING Property: Unknown Property name. [3:79871: min-device-width]
WARNING Property: Unknown Property name. [3:79900: max-device-width]
ERROR MediaQuery: Unexpected syntax, expected "and" but found "(". [3:86572: (]
ERROR MediaQuery: Unexpected syntax, expected "and" but found ":". [3:86582: :]
ERROR MediaQuery: Unexpected syntax. [3:86583: 35em]
ERROR MediaQuery: Unexpected syntax, expected "and" but found ")". [3:86587: )]
Any help would be greatly appreciated!
The logger is a singleton, so, put this line above your instruction
import logging
cssutils.log.setLevel(logging.CRITICAL)
This disables the warning and error logging.