[Python-checkins] bpo-39056: Fix handling invalid warning category in the -W option. (GH-17618)

Serhiy Storchaka webhook-mailer at python.org
Sun Jan 5 07:15:31 EST 2020


https://github.com/python/cpython/commit/41ec17e45d54473d32f543396293256f1581e44d
commit: 41ec17e45d54473d32f543396293256f1581e44d
branch: master
author: Serhiy Storchaka <storchaka at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-01-05T14:15:27+02:00
summary:

bpo-39056: Fix handling invalid warning category in the -W option. (GH-17618)

No longer import the re module if it is not needed.

files:
A Misc/NEWS.d/next/Library/2019-12-15-21-05-16.bpo-39056.nEfUM9.rst
M Lib/test/test_warnings/__init__.py
M Lib/warnings.py

diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py
index 3a6d64eaad1f8..c6fb097ae6dd2 100644
--- a/Lib/test/test_warnings/__init__.py
+++ b/Lib/test/test_warnings/__init__.py
@@ -43,6 +43,10 @@ def warnings_state(module):
         module.filters = original_filters
 
 
+class TestWarning(Warning):
+    pass
+
+
 class BaseTest:
 
     """Basic bookkeeping required for testing."""
@@ -566,9 +570,28 @@ def test_improper_input(self):
                               self.module._setoption, 'bogus::Warning')
             self.assertRaises(self.module._OptionError,
                               self.module._setoption, 'ignore:2::4:-5')
+            with self.assertRaises(self.module._OptionError):
+                self.module._setoption('ignore::123')
+            with self.assertRaises(self.module._OptionError):
+                self.module._setoption('ignore::123abc')
+            with self.assertRaises(self.module._OptionError):
+                self.module._setoption('ignore::===')
+            with self.assertRaisesRegex(self.module._OptionError, 'Wärning'):
+                self.module._setoption('ignore::Wärning')
             self.module._setoption('error::Warning::0')
             self.assertRaises(UserWarning, self.module.warn, 'convert to error')
 
+    def test_import_from_module(self):
+        with original_warnings.catch_warnings(module=self.module):
+            self.module._setoption('ignore::Warning')
+            with self.assertRaises(self.module._OptionError):
+                self.module._setoption('ignore::TestWarning')
+            with self.assertRaises(self.module._OptionError):
+                self.module._setoption('ignore::test.test_warnings.bogus')
+            self.module._setoption('error::test.test_warnings.TestWarning')
+            with self.assertRaises(TestWarning):
+                self.module.warn('test warning', TestWarning)
+
 
 class CWCmdLineTests(WCmdLineTests, unittest.TestCase):
     module = c_warnings
diff --git a/Lib/warnings.py b/Lib/warnings.py
index 00f740ca3a95b..691ccddfa450a 100644
--- a/Lib/warnings.py
+++ b/Lib/warnings.py
@@ -211,7 +211,6 @@ def _processoptions(args):
 
 # Helper for _processoptions()
 def _setoption(arg):
-    import re
     parts = arg.split(':')
     if len(parts) > 5:
         raise _OptionError("too many fields (max 5): %r" % (arg,))
@@ -220,11 +219,13 @@ def _setoption(arg):
     action, message, category, module, lineno = [s.strip()
                                                  for s in parts]
     action = _getaction(action)
-    message = re.escape(message)
     category = _getcategory(category)
-    module = re.escape(module)
+    if message or module:
+        import re
+    if message:
+        message = re.escape(message)
     if module:
-        module = module + '$'
+        module = re.escape(module) + r'\Z'
     if lineno:
         try:
             lineno = int(lineno)
@@ -248,26 +249,21 @@ def _getaction(action):
 
 # Helper for _setoption()
 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,)) from None
+    if '.' not in category:
+        import builtins as m
+        klass = category
     else:
-        i = category.rfind(".")
-        module = category[:i]
-        klass = category[i+1:]
+        module, _, klass = category.rpartition('.')
         try:
             m = __import__(module, None, None, [klass])
         except ImportError:
             raise _OptionError("invalid module name: %r" % (module,)) from None
-        try:
-            cat = getattr(m, klass)
-        except AttributeError:
-            raise _OptionError("unknown warning category: %r" % (category,)) from None
+    try:
+        cat = getattr(m, klass)
+    except AttributeError:
+        raise _OptionError("unknown warning category: %r" % (category,)) from None
     if not issubclass(cat, Warning):
         raise _OptionError("invalid warning category: %r" % (category,))
     return cat
diff --git a/Misc/NEWS.d/next/Library/2019-12-15-21-05-16.bpo-39056.nEfUM9.rst b/Misc/NEWS.d/next/Library/2019-12-15-21-05-16.bpo-39056.nEfUM9.rst
new file mode 100644
index 0000000000000..d5d2b98e9b0b3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-12-15-21-05-16.bpo-39056.nEfUM9.rst
@@ -0,0 +1,2 @@
+Fixed handling invalid warning category in the -W option.  No longer import
+the re module if it is not needed.



More information about the Python-checkins mailing list