]> granicus.if.org Git - python/commitdiff
Issue #18383: Avoid adding duplicate filters when warnings is reloaded
authorMartin Panter <vadmium+py@gmail.com>
Thu, 26 May 2016 09:10:55 +0000 (09:10 +0000)
committerMartin Panter <vadmium+py@gmail.com>
Thu, 26 May 2016 09:10:55 +0000 (09:10 +0000)
Based on patch by Alex Shkop.

Lib/test/test_warnings/__init__.py
Lib/warnings.py
Misc/NEWS

index fffadad7805c76a8d970d3a39211c4d1d5652610..712f9cde3a7aff7fc8759aa3a5d8f006fea73fd7 100644 (file)
@@ -265,6 +265,53 @@ class FilterTests(BaseTest):
             self.module.warn_explicit(UserWarning("b"), None, "f.py", 42)
             self.assertEqual(str(w[-1].message), "b")
 
+    def test_filterwarnings_duplicate_filters(self):
+        with original_warnings.catch_warnings(module=self.module):
+            self.module.resetwarnings()
+            self.module.filterwarnings("error", category=UserWarning)
+            self.assertEqual(len(self.module.filters), 1)
+            self.module.filterwarnings("ignore", category=UserWarning)
+            self.module.filterwarnings("error", category=UserWarning)
+            self.assertEqual(
+                len(self.module.filters), 2,
+                "filterwarnings inserted duplicate filter"
+            )
+            self.assertEqual(
+                self.module.filters[0][0], "error",
+                "filterwarnings did not promote filter to "
+                "the beginning of list"
+            )
+
+    def test_simplefilter_duplicate_filters(self):
+        with original_warnings.catch_warnings(module=self.module):
+            self.module.resetwarnings()
+            self.module.simplefilter("error", category=UserWarning)
+            self.assertEqual(len(self.module.filters), 1)
+            self.module.simplefilter("ignore", category=UserWarning)
+            self.module.simplefilter("error", category=UserWarning)
+            self.assertEqual(
+                len(self.module.filters), 2,
+                "simplefilter inserted duplicate filter"
+            )
+            self.assertEqual(
+                self.module.filters[0][0], "error",
+                "simplefilter did not promote filter to the beginning of list"
+            )
+    def test_append_duplicate(self):
+        with original_warnings.catch_warnings(module=self.module,
+                record=True) as w:
+            self.module.resetwarnings()
+            self.module.simplefilter("ignore")
+            self.module.simplefilter("error", append=True)
+            self.module.simplefilter("ignore", append=True)
+            self.module.warn("test_append_duplicate", category=UserWarning)
+            self.assertEqual(len(self.module.filters), 2,
+                "simplefilter inserted duplicate filter"
+            )
+            self.assertEqual(len(w), 0,
+                "appended duplicate changed order of filters"
+            )
+
 class CFilterTests(FilterTests, unittest.TestCase):
     module = c_warnings
 
index dfa13ee3fc5bfeb6150bf2ae3a90ad4fdf002e6c..c6631fcbf4758da73033b3fe080b2ccc27f3e597 100644 (file)
@@ -56,13 +56,8 @@ def filterwarnings(action, message="", category=Warning, module="", lineno=0,
     assert isinstance(module, str), "module must be a string"
     assert isinstance(lineno, int) and lineno >= 0, \
            "lineno must be an int >= 0"
-    item = (action, re.compile(message, re.I), category,
-            re.compile(module), lineno)
-    if append:
-        filters.append(item)
-    else:
-        filters.insert(0, item)
-    _filters_mutated()
+    _add_filter(action, re.compile(message, re.I), category,
+            re.compile(module), lineno, append=append)
 
 def simplefilter(action, category=Warning, lineno=0, append=False):
     """Insert a simple entry into the list of warnings filters (at the front).
@@ -78,11 +73,20 @@ def simplefilter(action, category=Warning, lineno=0, append=False):
                       "once"), "invalid action: %r" % (action,)
     assert isinstance(lineno, int) and lineno >= 0, \
            "lineno must be an int >= 0"
-    item = (action, None, category, None, lineno)
-    if append:
-        filters.append(item)
-    else:
+    _add_filter(action, None, category, None, lineno, append=append)
+
+def _add_filter(*item, append):
+    # Remove possible duplicate filters, so new one will be placed
+    # in correct place. If append=True and duplicate exists, do nothing.
+    if not append:
+        try:
+            filters.remove(item)
+        except ValueError:
+            pass
         filters.insert(0, item)
+    else:
+        if item not in filters:
+            filters.append(item)
     _filters_mutated()
 
 def resetwarnings():
index bf9843f950c72a6e32387f9ed81bf4e72d344c7b..4918265b660908176a1da7783fb9317b0bdd3291 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -126,6 +126,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #18383: Avoid creating duplicate filters when using filterwarnings
+  and simplefilter.  Based on patch by Alex Shkop.
+
 - Issue #27057: Fix os.set_inheritable() on Android, ioctl() is blocked by
   SELinux and fails with EACCESS. The function now falls back to fcntl().
   Patch written by MichaƂ Bednarski.