# HG changeset patch # Parent 40db18240177731ca92fce1717c34e8e7c2e5a67 Issue #18383: Avoid adding duplicate filters when warnings is reloaded diff -r 40db18240177 Lib/test/test_warnings/__init__.py --- a/Lib/test/test_warnings/__init__.py Sun May 22 03:10:11 2016 +0000 +++ b/Lib/test/test_warnings/__init__.py Sun May 22 04:44:12 2016 +0000 @@ -267,6 +267,53 @@ 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): + initial_len = len(self.module.filters) + self.module.filterwarnings("error", category=UserWarning) + self.assertEqual(len(self.module.filters), initial_len + 1) + self.module.filterwarnings("ignore", category=UserWarning) + self.module.filterwarnings("error", category=UserWarning) + self.assertEqual( + len(self.module.filters), initial_len + 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): + initial_len = len(self.module.filters) + self.module.simplefilter("error", category=UserWarning) + self.assertEqual(len(self.module.filters), initial_len + 1) + self.module.simplefilter("ignore", category=UserWarning) + self.module.simplefilter("error", category=UserWarning) + self.assertEqual( + len(self.module.filters), initial_len + 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: + initial_len = len(self.module.filters) + 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), initial_len + 2, + "simplefilter inserted duplicate filter" + ) + self.assertEqual(len(w), 0, + "appended duplicate changed order of filters" + ) + class CFilterTests(FilterTests, unittest.TestCase): module = c_warnings diff -r 40db18240177 Lib/warnings.py --- a/Lib/warnings.py Sun May 22 03:10:11 2016 +0000 +++ b/Lib/warnings.py Sun May 22 04:44:12 2016 +0000 @@ -131,10 +131,18 @@ "lineno must be an int >= 0" item = (action, re.compile(message, re.I), category, re.compile(module), lineno) - if append: - filters.append(item) + + # 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: - filters.insert(0, item) + if item not in filters: + filters.append(item) _filters_mutated() def simplefilter(action, category=Warning, lineno=0, append=False): @@ -152,10 +160,18 @@ assert isinstance(lineno, int) and lineno >= 0, \ "lineno must be an int >= 0" item = (action, None, category, None, lineno) - if append: - filters.append(item) + + # 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: - filters.insert(0, item) + if item not in filters: + filters.append(item) _filters_mutated() def resetwarnings():