* *message* is a string containing a regular expression that the start of
the warning message must match, case-insensitively. In :option:`-W` and
- :envvar:`PYTHONWARNINGS`, *message* is a literal string that the start of the
- warning message must contain (case-insensitively), ignoring any whitespace at
+ :envvar:`PYTHONWARNINGS`, if *message* starts and ends with a forward slash
+ (``/``), it specifies a regular expression as above;
+ otherwise it is a literal string that the start of the
+ warning message must match (case-insensitively), ignoring any whitespace at
the start or end of *message*.
* *category* is a class (a subclass of :exc:`Warning`) of which the warning
* *module* is a string containing a regular expression that the start of the
fully qualified module name must match, case-sensitively. In :option:`-W` and
- :envvar:`PYTHONWARNINGS`, *module* is a literal string that the
+ :envvar:`PYTHONWARNINGS`, if *module* starts and ends with a forward slash
+ (``/``), it specifies a regular expression as above;
+ otherwise it is a literal string that the
fully qualified module name must be equal to (case-sensitively), ignoring any
whitespace at the start or end of *module*.
The *action* field is as explained above but only applies to warnings that
match the remaining fields.
- The *message* field must match the whole warning message; this match is
- case-insensitive.
+ The *message* field must match the start of the warning message;
+ this match is case-insensitive.
+ If it starts and ends with a forward slash (``/``), it specifies
+ a regular expression, otherwise it specifies a literal string.
The *category* field matches the warning category
(ex: ``DeprecationWarning``). This must be a class name; the match test
The *module* field matches the (fully qualified) module name; this match is
case-sensitive.
+ If it starts and ends with a forward slash (``/``), it specifies
+ a regular expression that the start of the fully qualified module name
+ must match, otherwise it specifies a literal string that the fully
+ qualified module name must be equal to.
The *lineno* field matches the line number, where zero matches all line
numbers and is thus equivalent to an omitted line number.
See :ref:`warning-filter` and :ref:`describing-warning-filters` for more
details.
+ .. versionchanged:: next
+ Added regular expression support for *message* and *module*.
+
.. option:: -x
See :ref:`warning-filter` and :ref:`describing-warning-filters` for more
details.
+ .. versionchanged:: next
+ Added regular expression support for *message* and *module*.
+
.. envvar:: PYTHONFAULTHANDLER
This speeds up class creation, and helps avoid reference cycles.
(Contributed by Petr Viktorin in :gh:`135228`.)
+* The :option:`-W` option and the :envvar:`PYTHONWARNINGS` environment variable
+ can now specify regular expressions instead of literal strings to match
+ the warning message and the module name, if the corresponding field starts
+ and ends with a forward slash (``/``).
+ (Contributed by Serhiy Storchaka in :gh:`134716`.)
+
New modules
===========
if message or module:
import re
if message:
- message = re.escape(message)
+ if len(message) >= 2 and message[0] == message[-1] == '/':
+ message = message[1:-1]
+ else:
+ message = re.escape(message)
if module:
- module = re.escape(module) + r'\z'
+ if len(module) >= 2 and module[0] == module[-1] == '/':
+ module = module[1:-1]
+ else:
+ module = re.escape(module) + r'\z'
if lineno:
try:
lineno = int(lineno)
raise _wm._OptionError("invalid lineno %r" % (lineno,)) from None
else:
lineno = 0
- _wm.filterwarnings(action, message, category, module, lineno)
+ try:
+ _wm.filterwarnings(action, message, category, module, lineno)
+ except re.PatternError if message or module else ():
+ if message:
+ try:
+ re.compile(message)
+ except re.PatternError:
+ raise _wm._OptionError(f"invalid regular expression for "
+ f"message: {message!r}") from None
+ if module:
+ try:
+ re.compile(module)
+ except re.PatternError:
+ raise _wm._OptionError(f"invalid regular expression for "
+ f"module: {module!r}") from None
+ # Should never happen.
+ raise
# Helper for _setoption()
self.module._setoption('ignore::===')
with self.assertRaisesRegex(self.module._OptionError, 'Wärning'):
self.module._setoption('ignore::Wärning')
+ with self.assertRaisesRegex(self.module._OptionError, 'message'):
+ self.module._setoption('ignore:/?/:Warning')
+ with self.assertRaisesRegex(self.module._OptionError, 'module'):
+ self.module._setoption('ignore::Warning:/?/')
self.module._setoption('error::Warning::0')
self.assertRaises(UserWarning, self.module.warn, 'convert to error')
with self.assertRaises(TestWarning):
self.module.warn('test warning', TestWarning)
+ def test_message(self):
+ # Match prefix, case-insensitive.
+ with self.module.catch_warnings():
+ self.module._setoption('error:TEST WARN:UserWarning')
+ with self.assertRaises(UserWarning):
+ self.module.warn('Test Warning')
+ with self.module.catch_warnings():
+ self.module._setoption(r'error:/TE.*WARN/:UserWarning')
+ with self.assertRaises(UserWarning):
+ self.module.warn('Test Warning')
+
+ def test_module(self):
+ with self.module.catch_warnings():
+ self.module._setoption(f'error::UserWarning:{__name__}')
+ with self.assertRaises(UserWarning):
+ self.module.warn('test warning')
+ # Only full match.
+ self.module._setoption(f'ignore::UserWarning:{__name__[:-2]}')
+ with self.assertRaises(UserWarning):
+ self.module.warn('test warning')
+ with self.module.catch_warnings():
+ self.module._setoption(f'error::UserWarning:/{re.escape(__name__[:-2])}./')
+ with self.assertRaises(UserWarning):
+ self.module.warn('test warning')
+
class CWCmdLineTests(WCmdLineTests, unittest.TestCase):
module = c_warnings
--- /dev/null
+Add support of regular expressions in the :option:`-W` option and the
+:envvar:`PYTHONWARNINGS` environment variable.