gh-134716: Support regular expressions in -W and PYTHONWARNINGS (GH-138149)
Some checks are pending
Tests / Windows MSI (push) Blocked by required conditions
Tests / Change detection (push) Waiting to run
Tests / Docs (push) Blocked by required conditions
Tests / Check if Autoconf files are up to date (push) Blocked by required conditions
Tests / Check if generated files are up to date (push) Blocked by required conditions
Tests / (push) Blocked by required conditions
Tests / Ubuntu SSL tests with OpenSSL (push) Blocked by required conditions
Tests / Ubuntu SSL tests with AWS-LC (push) Blocked by required conditions
Tests / Android (aarch64) (push) Blocked by required conditions
Tests / Android (x86_64) (push) Blocked by required conditions
Tests / WASI (push) Blocked by required conditions
Tests / Hypothesis tests on Ubuntu (push) Blocked by required conditions
Tests / Address sanitizer (push) Blocked by required conditions
Tests / Sanitizers (push) Blocked by required conditions
Tests / Cross build Linux (push) Blocked by required conditions
Tests / CIFuzz (push) Blocked by required conditions
Tests / All required checks pass (push) Blocked by required conditions
Lint / lint (push) Waiting to run
mypy / Run mypy on Lib/_pyrepl (push) Waiting to run
mypy / Run mypy on Lib/test/libregrtest (push) Waiting to run
mypy / Run mypy on Lib/tomllib (push) Waiting to run
mypy / Run mypy on Tools/build (push) Waiting to run
mypy / Run mypy on Tools/cases_generator (push) Waiting to run
mypy / Run mypy on Tools/clinic (push) Waiting to run
mypy / Run mypy on Tools/jit (push) Waiting to run
mypy / Run mypy on Tools/peg_generator (push) Waiting to run

This commit is contained in:
Serhiy Storchaka 2025-09-16 20:06:44 +03:00 committed by GitHub
parent 530ddd3e06
commit cf9ef73121
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 83 additions and 8 deletions

View file

@ -159,8 +159,10 @@ the disposition of the match. Each entry is a tuple of the form (*action*,
* *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
@ -168,7 +170,9 @@ the disposition of the match. Each entry is a tuple of the form (*action*,
* *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*.

View file

@ -479,8 +479,10 @@ Miscellaneous options
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
@ -489,6 +491,10 @@ Miscellaneous options
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.
@ -506,6 +512,9 @@ Miscellaneous options
See :ref:`warning-filter` and :ref:`describing-warning-filters` for more
details.
.. versionchanged:: next
Added regular expression support for *message* and *module*.
.. option:: -x
@ -980,6 +989,9 @@ conflict.
See :ref:`warning-filter` and :ref:`describing-warning-filters` for more
details.
.. versionchanged:: next
Added regular expression support for *message* and *module*.
.. envvar:: PYTHONFAULTHANDLER

View file

@ -273,6 +273,12 @@ Other language changes
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
===========

View file

@ -369,9 +369,15 @@ def _setoption(arg):
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)
@ -381,7 +387,23 @@ def _setoption(arg):
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()

View file

@ -755,6 +755,10 @@ class WCmdLineTests(BaseTest):
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')
@ -769,6 +773,31 @@ class WCmdLineTests(BaseTest):
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

View file

@ -0,0 +1,2 @@
Add support of regular expressions in the :option:`-W` option and the
:envvar:`PYTHONWARNINGS` environment variable.