pythonwarnings

Filtering based on custom warning categories


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.


Solution

  • 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.