diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -365,16 +365,34 @@ class WarnTests(BaseTest): """Warning with a bad format string for __str__.""" def __str__(self): return ("A bad formatted string %(err)" % {"err" : "there is no %(err)s"}) with self.assertRaises(ValueError): self.module.warn(BadStrWarning()) + def test_simplefilter_invalid_category(self): + class MyWarningClass(Warning): + pass + + class NonWarningSubclass: + pass + + msg_regex = 'category must be a Warning subclass, not (.*)' + + with self.assertRaisesRegex(TypeError, msg_regex): + self.module.simplefilter('always', '') + + with self.assertRaisesRegex(TypeError, msg_regex): + self.module.simplefilter('always', NonWarningSubclass) + + with self.assertRaisesRegex(TypeError, msg_regex): + self.module.simplefilter('always', MyWarningClass()) + class CWarnTests(WarnTests, unittest.TestCase): module = c_warnings # As an early adopter, we sanity check the # test.support.import_fresh_module utility function def test_accelerated(self): self.assertFalse(original_warnings is self.module) diff --git a/Lib/warnings.py b/Lib/warnings.py --- a/Lib/warnings.py +++ b/Lib/warnings.py @@ -62,16 +62,19 @@ def simplefilter(action, category=Warnin 'category' -- a class that the warning must be a subclass of 'lineno' -- an integer line number, 0 matches all warnings 'append' -- if true, append to the list of filters """ assert action in ("error", "ignore", "always", "default", "module", "once"), "invalid action: %r" % (action,) assert isinstance(lineno, int) and lineno >= 0, \ "lineno must be an int >= 0" + if not (isinstance(category, type) and issubclass(category, Warning)): + raise TypeError('category must be a Warning subclass, ' + 'not {!r}'.format(category)) item = (action, None, category, None, lineno) if append: filters.append(item) else: filters.insert(0, item) def resetwarnings(): """Clear the list of warning filters, so that no filters are active."""