Skip to content

Commit f6ffab7

Browse files
committed
Issue #18383: Avoid adding duplicate filters when warnings is reloaded
Based on patch by Alex Shkop.
1 parent 1ce5716 commit f6ffab7

File tree

3 files changed

+65
-11
lines changed

3 files changed

+65
-11
lines changed

Lib/test/test_warnings/__init__.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,53 @@ def match(self, a):
265265
self.module.warn_explicit(UserWarning("b"), None, "f.py", 42)
266266
self.assertEqual(str(w[-1].message), "b")
267267

268+
def test_filterwarnings_duplicate_filters(self):
269+
with original_warnings.catch_warnings(module=self.module):
270+
self.module.resetwarnings()
271+
self.module.filterwarnings("error", category=UserWarning)
272+
self.assertEqual(len(self.module.filters), 1)
273+
self.module.filterwarnings("ignore", category=UserWarning)
274+
self.module.filterwarnings("error", category=UserWarning)
275+
self.assertEqual(
276+
len(self.module.filters), 2,
277+
"filterwarnings inserted duplicate filter"
278+
)
279+
self.assertEqual(
280+
self.module.filters[0][0], "error",
281+
"filterwarnings did not promote filter to "
282+
"the beginning of list"
283+
)
284+
285+
def test_simplefilter_duplicate_filters(self):
286+
with original_warnings.catch_warnings(module=self.module):
287+
self.module.resetwarnings()
288+
self.module.simplefilter("error", category=UserWarning)
289+
self.assertEqual(len(self.module.filters), 1)
290+
self.module.simplefilter("ignore", category=UserWarning)
291+
self.module.simplefilter("error", category=UserWarning)
292+
self.assertEqual(
293+
len(self.module.filters), 2,
294+
"simplefilter inserted duplicate filter"
295+
)
296+
self.assertEqual(
297+
self.module.filters[0][0], "error",
298+
"simplefilter did not promote filter to the beginning of list"
299+
)
300+
def test_append_duplicate(self):
301+
with original_warnings.catch_warnings(module=self.module,
302+
record=True) as w:
303+
self.module.resetwarnings()
304+
self.module.simplefilter("ignore")
305+
self.module.simplefilter("error", append=True)
306+
self.module.simplefilter("ignore", append=True)
307+
self.module.warn("test_append_duplicate", category=UserWarning)
308+
self.assertEqual(len(self.module.filters), 2,
309+
"simplefilter inserted duplicate filter"
310+
)
311+
self.assertEqual(len(w), 0,
312+
"appended duplicate changed order of filters"
313+
)
314+
268315
class CFilterTests(FilterTests, unittest.TestCase):
269316
module = c_warnings
270317

Lib/warnings.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,8 @@ def filterwarnings(action, message="", category=Warning, module="", lineno=0,
5656
assert isinstance(module, str), "module must be a string"
5757
assert isinstance(lineno, int) and lineno >= 0, \
5858
"lineno must be an int >= 0"
59-
item = (action, re.compile(message, re.I), category,
60-
re.compile(module), lineno)
61-
if append:
62-
filters.append(item)
63-
else:
64-
filters.insert(0, item)
65-
_filters_mutated()
59+
_add_filter(action, re.compile(message, re.I), category,
60+
re.compile(module), lineno, append=append)
6661

6762
def simplefilter(action, category=Warning, lineno=0, append=False):
6863
"""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):
7873
"once"), "invalid action: %r" % (action,)
7974
assert isinstance(lineno, int) and lineno >= 0, \
8075
"lineno must be an int >= 0"
81-
item = (action, None, category, None, lineno)
82-
if append:
83-
filters.append(item)
84-
else:
76+
_add_filter(action, None, category, None, lineno, append=append)
77+
78+
def _add_filter(*item, append):
79+
# Remove possible duplicate filters, so new one will be placed
80+
# in correct place. If append=True and duplicate exists, do nothing.
81+
if not append:
82+
try:
83+
filters.remove(item)
84+
except ValueError:
85+
pass
8586
filters.insert(0, item)
87+
else:
88+
if item not in filters:
89+
filters.append(item)
8690
_filters_mutated()
8791

8892
def resetwarnings():

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ Core and Builtins
126126
Library
127127
-------
128128

129+
- Issue #18383: Avoid creating duplicate filters when using filterwarnings
130+
and simplefilter. Based on patch by Alex Shkop.
131+
129132
- Issue #27057: Fix os.set_inheritable() on Android, ioctl() is blocked by
130133
SELinux and fails with EACCESS. The function now falls back to fcntl().
131134
Patch written by Michał Bednarski.

0 commit comments

Comments
 (0)