Skip to content

Commit cf9ef73

Browse files
gh-134716: Support regular expressions in -W and PYTHONWARNINGS (GH-138149)
1 parent 530ddd3 commit cf9ef73

File tree

6 files changed

+83
-8
lines changed

6 files changed

+83
-8
lines changed

Doc/library/warnings.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,16 +159,20 @@ the disposition of the match. Each entry is a tuple of the form (*action*,
159159

160160
* *message* is a string containing a regular expression that the start of
161161
the warning message must match, case-insensitively. In :option:`-W` and
162-
:envvar:`PYTHONWARNINGS`, *message* is a literal string that the start of the
163-
warning message must contain (case-insensitively), ignoring any whitespace at
162+
:envvar:`PYTHONWARNINGS`, if *message* starts and ends with a forward slash
163+
(``/``), it specifies a regular expression as above;
164+
otherwise it is a literal string that the start of the
165+
warning message must match (case-insensitively), ignoring any whitespace at
164166
the start or end of *message*.
165167

166168
* *category* is a class (a subclass of :exc:`Warning`) of which the warning
167169
category must be a subclass in order to match.
168170

169171
* *module* is a string containing a regular expression that the start of the
170172
fully qualified module name must match, case-sensitively. In :option:`-W` and
171-
:envvar:`PYTHONWARNINGS`, *module* is a literal string that the
173+
:envvar:`PYTHONWARNINGS`, if *module* starts and ends with a forward slash
174+
(``/``), it specifies a regular expression as above;
175+
otherwise it is a literal string that the
172176
fully qualified module name must be equal to (case-sensitively), ignoring any
173177
whitespace at the start or end of *module*.
174178

Doc/using/cmdline.rst

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,10 @@ Miscellaneous options
479479
The *action* field is as explained above but only applies to warnings that
480480
match the remaining fields.
481481

482-
The *message* field must match the whole warning message; this match is
483-
case-insensitive.
482+
The *message* field must match the start of the warning message;
483+
this match is case-insensitive.
484+
If it starts and ends with a forward slash (``/``), it specifies
485+
a regular expression, otherwise it specifies a literal string.
484486

485487
The *category* field matches the warning category
486488
(ex: ``DeprecationWarning``). This must be a class name; the match test
@@ -489,6 +491,10 @@ Miscellaneous options
489491

490492
The *module* field matches the (fully qualified) module name; this match is
491493
case-sensitive.
494+
If it starts and ends with a forward slash (``/``), it specifies
495+
a regular expression that the start of the fully qualified module name
496+
must match, otherwise it specifies a literal string that the fully
497+
qualified module name must be equal to.
492498

493499
The *lineno* field matches the line number, where zero matches all line
494500
numbers and is thus equivalent to an omitted line number.
@@ -506,6 +512,9 @@ Miscellaneous options
506512
See :ref:`warning-filter` and :ref:`describing-warning-filters` for more
507513
details.
508514

515+
.. versionchanged:: next
516+
Added regular expression support for *message* and *module*.
517+
509518

510519
.. option:: -x
511520

@@ -980,6 +989,9 @@ conflict.
980989
See :ref:`warning-filter` and :ref:`describing-warning-filters` for more
981990
details.
982991

992+
.. versionchanged:: next
993+
Added regular expression support for *message* and *module*.
994+
983995

984996
.. envvar:: PYTHONFAULTHANDLER
985997

Doc/whatsnew/3.15.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,12 @@ Other language changes
273273
This speeds up class creation, and helps avoid reference cycles.
274274
(Contributed by Petr Viktorin in :gh:`135228`.)
275275

276+
* The :option:`-W` option and the :envvar:`PYTHONWARNINGS` environment variable
277+
can now specify regular expressions instead of literal strings to match
278+
the warning message and the module name, if the corresponding field starts
279+
and ends with a forward slash (``/``).
280+
(Contributed by Serhiy Storchaka in :gh:`134716`.)
281+
276282

277283
New modules
278284
===========

Lib/_py_warnings.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,9 +369,15 @@ def _setoption(arg):
369369
if message or module:
370370
import re
371371
if message:
372-
message = re.escape(message)
372+
if len(message) >= 2 and message[0] == message[-1] == '/':
373+
message = message[1:-1]
374+
else:
375+
message = re.escape(message)
373376
if module:
374-
module = re.escape(module) + r'\z'
377+
if len(module) >= 2 and module[0] == module[-1] == '/':
378+
module = module[1:-1]
379+
else:
380+
module = re.escape(module) + r'\z'
375381
if lineno:
376382
try:
377383
lineno = int(lineno)
@@ -381,7 +387,23 @@ def _setoption(arg):
381387
raise _wm._OptionError("invalid lineno %r" % (lineno,)) from None
382388
else:
383389
lineno = 0
384-
_wm.filterwarnings(action, message, category, module, lineno)
390+
try:
391+
_wm.filterwarnings(action, message, category, module, lineno)
392+
except re.PatternError if message or module else ():
393+
if message:
394+
try:
395+
re.compile(message)
396+
except re.PatternError:
397+
raise _wm._OptionError(f"invalid regular expression for "
398+
f"message: {message!r}") from None
399+
if module:
400+
try:
401+
re.compile(module)
402+
except re.PatternError:
403+
raise _wm._OptionError(f"invalid regular expression for "
404+
f"module: {module!r}") from None
405+
# Should never happen.
406+
raise
385407

386408

387409
# Helper for _setoption()

Lib/test/test_warnings/__init__.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,10 @@ def test_improper_input(self):
755755
self.module._setoption('ignore::===')
756756
with self.assertRaisesRegex(self.module._OptionError, 'Wärning'):
757757
self.module._setoption('ignore::Wärning')
758+
with self.assertRaisesRegex(self.module._OptionError, 'message'):
759+
self.module._setoption('ignore:/?/:Warning')
760+
with self.assertRaisesRegex(self.module._OptionError, 'module'):
761+
self.module._setoption('ignore::Warning:/?/')
758762
self.module._setoption('error::Warning::0')
759763
self.assertRaises(UserWarning, self.module.warn, 'convert to error')
760764

@@ -769,6 +773,31 @@ def test_import_from_module(self):
769773
with self.assertRaises(TestWarning):
770774
self.module.warn('test warning', TestWarning)
771775

776+
def test_message(self):
777+
# Match prefix, case-insensitive.
778+
with self.module.catch_warnings():
779+
self.module._setoption('error:TEST WARN:UserWarning')
780+
with self.assertRaises(UserWarning):
781+
self.module.warn('Test Warning')
782+
with self.module.catch_warnings():
783+
self.module._setoption(r'error:/TE.*WARN/:UserWarning')
784+
with self.assertRaises(UserWarning):
785+
self.module.warn('Test Warning')
786+
787+
def test_module(self):
788+
with self.module.catch_warnings():
789+
self.module._setoption(f'error::UserWarning:{__name__}')
790+
with self.assertRaises(UserWarning):
791+
self.module.warn('test warning')
792+
# Only full match.
793+
self.module._setoption(f'ignore::UserWarning:{__name__[:-2]}')
794+
with self.assertRaises(UserWarning):
795+
self.module.warn('test warning')
796+
with self.module.catch_warnings():
797+
self.module._setoption(f'error::UserWarning:/{re.escape(__name__[:-2])}./')
798+
with self.assertRaises(UserWarning):
799+
self.module.warn('test warning')
800+
772801

773802
class CWCmdLineTests(WCmdLineTests, unittest.TestCase):
774803
module = c_warnings
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add support of regular expressions in the :option:`-W` option and the
2+
:envvar:`PYTHONWARNINGS` environment variable.

0 commit comments

Comments
 (0)