[Python-checkins] cpython: Issue #15836: assertRaises(), assertRaisesRegex(), assertWarns() and

serhiy.storchaka python-checkins at python.org
Thu May 21 19:16:16 CEST 2015


https://hg.python.org/cpython/rev/84d7ec21cc43
changeset:   96187:84d7ec21cc43
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Thu May 21 20:15:40 2015 +0300
summary:
  Issue #15836: assertRaises(), assertRaisesRegex(), assertWarns() and
assertWarnsRegex() assertments now check the type of the first argument
to prevent possible user error.  Based on patch by Daniel Wagner-Hall.

files:
  Lib/test/test_importlib/builtin/test_loader.py |   1 -
  Lib/unittest/case.py                           |  13 ++
  Lib/unittest/test/test_case.py                 |  56 ++++++++++
  Misc/ACKS                                      |   1 +
  Misc/NEWS                                      |   4 +
  5 files changed, 74 insertions(+), 1 deletions(-)


diff --git a/Lib/test/test_importlib/builtin/test_loader.py b/Lib/test/test_importlib/builtin/test_loader.py
--- a/Lib/test/test_importlib/builtin/test_loader.py
+++ b/Lib/test/test_importlib/builtin/test_loader.py
@@ -97,7 +97,6 @@
             method = getattr(self.machinery.BuiltinImporter, meth_name)
         with self.assertRaises(ImportError) as cm:
             method(util.BUILTINS.bad_name)
-        self.assertRaises(util.BUILTINS.bad_name)
 
 
 (Frozen_InspectLoaderTests,
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -119,6 +119,10 @@
     test_item.__unittest_expecting_failure__ = True
     return test_item
 
+def _is_subtype(expected, basetype):
+    if isinstance(expected, tuple):
+        return all(_is_subtype(e, basetype) for e in expected)
+    return isinstance(expected, type) and issubclass(expected, basetype)
 
 class _BaseTestCaseContext:
 
@@ -148,6 +152,9 @@
         If args is not empty, call a callable passing positional and keyword
         arguments.
         """
+        if not _is_subtype(self.expected, self._base_type):
+            raise TypeError('%s() arg 1 must be %s' %
+                            (name, self._base_type_str))
         if args and args[0] is None:
             warnings.warn("callable is None",
                           DeprecationWarning, 3)
@@ -172,6 +179,9 @@
 class _AssertRaisesContext(_AssertRaisesBaseContext):
     """A context manager used to implement TestCase.assertRaises* methods."""
 
+    _base_type = BaseException
+    _base_type_str = 'an exception type or tuple of exception types'
+
     def __enter__(self):
         return self
 
@@ -206,6 +216,9 @@
 class _AssertWarnsContext(_AssertRaisesBaseContext):
     """A context manager used to implement TestCase.assertWarns* methods."""
 
+    _base_type = Warning
+    _base_type_str = 'a warning type or tuple of warning types'
+
     def __enter__(self):
         # The __warningregistry__'s need to be in a pristine state for tests
         # to work properly.
diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py
--- a/Lib/unittest/test/test_case.py
+++ b/Lib/unittest/test/test_case.py
@@ -1185,6 +1185,18 @@
         with self.assertRaises(ExceptionMock):
             self.assertRaises(ValueError, Stub)
 
+    def testAssertRaisesNoExceptionType(self):
+        with self.assertRaises(TypeError):
+            self.assertRaises()
+        with self.assertRaises(TypeError):
+            self.assertRaises(1)
+        with self.assertRaises(TypeError):
+            self.assertRaises(object)
+        with self.assertRaises(TypeError):
+            self.assertRaises((ValueError, 1))
+        with self.assertRaises(TypeError):
+            self.assertRaises((ValueError, object))
+
     def testAssertRaisesRegex(self):
         class ExceptionMock(Exception):
             pass
@@ -1258,6 +1270,20 @@
         self.assertIsInstance(e, ExceptionMock)
         self.assertEqual(e.args[0], v)
 
+    def testAssertRaisesRegexNoExceptionType(self):
+        with self.assertRaises(TypeError):
+            self.assertRaisesRegex()
+        with self.assertRaises(TypeError):
+            self.assertRaisesRegex(ValueError)
+        with self.assertRaises(TypeError):
+            self.assertRaisesRegex(1, 'expect')
+        with self.assertRaises(TypeError):
+            self.assertRaisesRegex(object, 'expect')
+        with self.assertRaises(TypeError):
+            self.assertRaisesRegex((ValueError, 1), 'expect')
+        with self.assertRaises(TypeError):
+            self.assertRaisesRegex((ValueError, object), 'expect')
+
     def testAssertWarnsCallable(self):
         def _runtime_warn():
             warnings.warn("foo", RuntimeWarning)
@@ -1336,6 +1362,20 @@
                 with self.assertWarns(DeprecationWarning):
                     _runtime_warn()
 
+    def testAssertWarnsNoExceptionType(self):
+        with self.assertRaises(TypeError):
+            self.assertWarns()
+        with self.assertRaises(TypeError):
+            self.assertWarns(1)
+        with self.assertRaises(TypeError):
+            self.assertWarns(object)
+        with self.assertRaises(TypeError):
+            self.assertWarns((UserWarning, 1))
+        with self.assertRaises(TypeError):
+            self.assertWarns((UserWarning, object))
+        with self.assertRaises(TypeError):
+            self.assertWarns((UserWarning, Exception))
+
     def testAssertWarnsRegexCallable(self):
         def _runtime_warn(msg):
             warnings.warn(msg, RuntimeWarning)
@@ -1414,6 +1454,22 @@
                 with self.assertWarnsRegex(RuntimeWarning, "o+"):
                     _runtime_warn("barz")
 
+    def testAssertWarnsRegexNoExceptionType(self):
+        with self.assertRaises(TypeError):
+            self.assertWarnsRegex()
+        with self.assertRaises(TypeError):
+            self.assertWarnsRegex(UserWarning)
+        with self.assertRaises(TypeError):
+            self.assertWarnsRegex(1, 'expect')
+        with self.assertRaises(TypeError):
+            self.assertWarnsRegex(object, 'expect')
+        with self.assertRaises(TypeError):
+            self.assertWarnsRegex((UserWarning, 1), 'expect')
+        with self.assertRaises(TypeError):
+            self.assertWarnsRegex((UserWarning, object), 'expect')
+        with self.assertRaises(TypeError):
+            self.assertWarnsRegex((UserWarning, Exception), 'expect')
+
     @contextlib.contextmanager
     def assertNoStderr(self):
         with captured_stderr() as buf:
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1472,6 +1472,7 @@
 Martijn Vries
 Sjoerd de Vries
 Guido Vranken
+Daniel Wagner-Hall
 Niki W. Waibel
 Wojtek Walczak
 Charles Waldman
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -52,6 +52,10 @@
 Library
 -------
 
+- Issue #15836: assertRaises(), assertRaisesRegex(), assertWarns() and
+  assertWarnsRegex() assertments now check the type of the first argument
+  to prevent possible user error.  Based on patch by Daniel Wagner-Hall.
+
 - Issue #9858: Add missing method stubs to _io.RawIOBase.  Patch by Laura
   Rupprecht.
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list