In addition to pre-existing warning categories, users can define their own warning classes, such as in the code below:
$ cat mwe.py
#!/usr/bin/env python3.5
import warnings
import pprint
class ObnoxiousWarning(UserWarning):
pass
for i in range(3):
print(i)
warnings.warn("I don't like this.", ObnoxiousWarning)
When invoking Python, the -W
flag controls how to filter warnings. But when I try to get it to ignore my freshly minted warning category, I'm told the filter is ignored:
$ python3.5 -W ignore::ObnoxiousWarning ./mwe.py
Invalid -W option ignored: unknown warning category: 'ObnoxiousWarning'
0
./mwe.py:11: ObnoxiousWarning: I don't like this.
warnings.warn("I don't like this.", ObnoxiousWarning)
1
2
How can I use the commandline to insert a filter for custom warning categories (as opposed to all UserWarnings or filtering based on the warning message, which I can do)?
Edit 2018-11-29: See Issue 66733: -W option cannot use nonstandard categories, still open as of 2025-08-18.
Some of the answers lie in python source code. Look at the _getcategory function: https://github.com/python/cpython/blob/3.5/Lib/warnings.py#L147
def _getcategory(category):
import re
if not category:
return Warning
if re.match("^[a-zA-Z0-9_]+$", category):
try:
cat = eval(category)
except NameError:
raise _OptionError("unknown warning category: %r" % (category,))
else:
i = category.rfind(".")
module = category[:i]
klass = category[i+1:]
try:
m = __import__(module, None, None, [klass])
except ImportError:
raise _OptionError("invalid module name: %r" % (module,))
try:
cat = getattr(m, klass)
except AttributeError:
raise _OptionError("unknown warning category: %r" % (category,))
if not issubclass(cat, Warning):
raise _OptionError("invalid warning category: %r" % (category,))
return cat
Python tries to eval your category or to import it from module you specify in filter. And that will fail, unless you have your module in PYTHONPATH.
PYTHONPATH='<path_to_dir_where_mwe_located>' python -W ignore::mwe.ObnoxiousWarning
This way, if you import your module in python shell warning would be filtered as you wish. To use filter in commandline, you must define your warning in separate module, other than that you execute.
mwe.py
class ObnoxiousWarning(UserWarning):
pass
entrypoint.py
#!/usr/bin/env python3.5
import warnings
import pprint
from mwe import ObnoxiousWarning
for i in range(3):
print(i)
warnings.warn("I don't like this.", ObnoxiousWarning)
And finally:
PYTHONPATH='<path_to_dir_where_mwe_located>' python -W ignore::mwe.ObnoxiousWarning ./entrypoint.py
0
1
2
I don't understand why defining separate module with warning works, but it is. May be someone will explain it.