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