1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | Lib/test/test_pep352.py
import unittest import __builtin__ import exceptions import warnings from test.test_support import run_unittest, check_warnings import os import sys from platform import system as platform_system DEPRECATION_WARNINGS = ["BaseException.message has been deprecated"] if sys.py3kwarning: DEPRECATION_WARNINGS.extend( ["exceptions must derive from BaseException", "catching classes that don't inherit from BaseException is not allowed", "__get(item|slice)__ not supported for exception classes"]) _deprecations = [(msg, DeprecationWarning) for msg in DEPRECATION_WARNINGS] # Silence Py3k and other deprecation warnings def ignore_deprecation_warnings(func): """Ignore the known DeprecationWarnings.""" def wrapper(*args, **kw): with check_warnings(*_deprecations, quiet=True): return func(*args, **kw) return wrapper class ExceptionClassTests(unittest.TestCase): """Tests for anything relating to exception objects themselves (e.g., inheritance hierarchy)""" def test_builtins_new_style(self): self.assertTrue(issubclass(Exception, object)) @ignore_deprecation_warnings def verify_instance_interface(self, ins): for attr in ("args", "message", "__str__", "__repr__", "__getitem__"): self.assertTrue(hasattr(ins, attr), "%s missing %s attribute" % (ins.__class__.__name__, attr)) def test_inheritance(self): # Make sure the inheritance hierarchy matches the documentation exc_set = set(x for x in dir(exceptions) if not x.startswith('_')) inheritance_tree = open(os.path.join(os.path.split(__file__)[0], 'exception_hierarchy.txt')) try: superclass_name = inheritance_tree.readline().rstrip() try: last_exc = getattr(__builtin__, superclass_name) except AttributeError: self.fail("base class %s not a built-in" % superclass_name) self.assertIn(superclass_name, exc_set) exc_set.discard(superclass_name) superclasses = [] # Loop will insert base exception last_depth = 0 for exc_line in inheritance_tree: exc_line = exc_line.rstrip() depth = exc_line.rindex('-') exc_name = exc_line[depth+2:] # Slice past space if '(' in exc_name: paren_index = exc_name.index('(') platform_name = exc_name[paren_index+1:-1] exc_name = exc_name[:paren_index-1] # Slice off space if platform_system() != platform_name: exc_set.discard(exc_name) continue if '[' in exc_name: left_bracket = exc_name.index('[') exc_name = exc_name[:left_bracket-1] # cover space try: exc = getattr(__builtin__, exc_name) except AttributeError: self.fail("%s not a built-in exception" % exc_name) if last_depth < depth: superclasses.append((last_depth, last_exc)) elif last_depth > depth: while superclasses[-1][0] >= depth: superclasses.pop() self.assertTrue(issubclass(exc, superclasses[-1][1]), "%s is not a subclass of %s" % (exc.__name__, superclasses[-1][1].__name__)) try: # Some exceptions require arguments; just skip them self.verify_instance_interface(exc()) except TypeError: pass self.assertIn(exc_name, exc_set) exc_set.discard(exc_name) last_exc = exc last_depth = depth finally: inheritance_tree.close() self.assertEqual(len(exc_set), 0, "%s not accounted for" % exc_set) interface_tests = ("length", "args", "message", "str", "unicode", "repr", "indexing") def interface_test_driver(self, results): for test_name, (given, expected) in zip(self.interface_tests, results): self.assertEqual(given, expected, "%s: %s != %s" % (test_name, given, expected)) @ignore_deprecation_warnings def test_interface_single_arg(self): # Make sure interface works properly when given a single argument arg = "spam" exc = Exception(arg) results = ([len(exc.args), 1], [exc.args[0], arg], [exc.message, arg], [str(exc), str(arg)], [unicode(exc), unicode(arg)], [repr(exc), exc.__class__.__name__ + repr(exc.args)], [exc[0], arg]) self.interface_test_driver(results) @ignore_deprecation_warnings def test_interface_multi_arg(self): # Make sure interface correct when multiple arguments given arg_count = 3 args = tuple(range(arg_count)) exc = Exception(*args) results = ([len(exc.args), arg_count], [exc.args, args], [exc.message, ''], [str(exc), str(args)], [unicode(exc), unicode(args)], [repr(exc), exc.__class__.__name__ + repr(exc.args)], [exc[-1], args[-1]]) self.interface_test_driver(results) @ignore_deprecation_warnings def test_interface_no_arg(self): # Make sure that with no args that interface is correct exc = Exception() results = ([len(exc.args), 0], [exc.args, tuple()], [exc.message, ''], [str(exc), ''], [unicode(exc), u''], [repr(exc), exc.__class__.__name__ + '()'], [True, True]) self.interface_test_driver(results) def test_message_deprecation(self): # As of Python 2.6, BaseException.message is deprecated. with check_warnings(("", DeprecationWarning)): BaseException().message class UsageTests(unittest.TestCase): """Test usage of exceptions""" def raise_fails(self, object_): """Make sure that raising 'object_' triggers a TypeError.""" try: raise object_ except TypeError: return # What is expected. self.fail("TypeError expected for raising %s" % type(object_)) def catch_fails(self, object_): """Catching 'object_' should raise a TypeError.""" try: try: raise StandardError except object_: pass except TypeError: pass except StandardError: self.fail("TypeError expected when catching %s" % type(object_)) try: try: raise StandardError except (object_,): pass except TypeError: return except StandardError: self.fail("TypeError expected when catching %s as specified in a " "tuple" % type(object_)) @ignore_deprecation_warnings def test_raise_classic(self): # Raising a classic class is okay (for now). class ClassicClass: pass try: raise ClassicClass except ClassicClass: pass except: self.fail("unable to raise classic class") try: raise ClassicClass() except ClassicClass: pass except: self.fail("unable to raise classic class instance") def test_raise_new_style_non_exception(self): # You cannot raise a new-style class that does not inherit from # BaseException; the ability was not possible until BaseException's # introduction so no need to support new-style objects that do not # inherit from it. class NewStyleClass(object): pass self.raise_fails(NewStyleClass) self.raise_fails(NewStyleClass()) def test_raise_string(self): # Raising a string raises TypeError. self.raise_fails("spam") def test_catch_string(self): # Catching a string should trigger a DeprecationWarning. with warnings.catch_warnings(): warnings.resetwarnings() warnings.filterwarnings("error") str_exc = "spam" with self.assertRaises(DeprecationWarning): try: raise StandardError except str_exc: pass # Make sure that even if the string exception is listed in a tuple # that a warning is raised. with self.assertRaises(DeprecationWarning): try: raise StandardError except (AssertionError, str_exc): pass def test_main(): run_unittest(ExceptionClassTests, UsageTests) if __name__ == '__main__': test_main() |