1 | # Python test set -- part 5, built-in exceptions
|
---|
2 |
|
---|
3 | import os
|
---|
4 | import sys
|
---|
5 | import unittest
|
---|
6 | import pickle, cPickle
|
---|
7 |
|
---|
8 | from test.test_support import (TESTFN, unlink, run_unittest, captured_output,
|
---|
9 | check_warnings, cpython_only)
|
---|
10 | from test.test_pep352 import ignore_deprecation_warnings
|
---|
11 |
|
---|
12 | # XXX This is not really enough, each *operation* should be tested!
|
---|
13 |
|
---|
14 | class ExceptionTests(unittest.TestCase):
|
---|
15 |
|
---|
16 | def testReload(self):
|
---|
17 | # Reloading the built-in exceptions module failed prior to Py2.2, while it
|
---|
18 | # should act the same as reloading built-in sys.
|
---|
19 | try:
|
---|
20 | from imp import reload
|
---|
21 | import exceptions
|
---|
22 | reload(exceptions)
|
---|
23 | except ImportError, e:
|
---|
24 | self.fail("reloading exceptions: %s" % e)
|
---|
25 |
|
---|
26 | def raise_catch(self, exc, excname):
|
---|
27 | try:
|
---|
28 | raise exc, "spam"
|
---|
29 | except exc, err:
|
---|
30 | buf1 = str(err)
|
---|
31 | try:
|
---|
32 | raise exc("spam")
|
---|
33 | except exc, err:
|
---|
34 | buf2 = str(err)
|
---|
35 | self.assertEqual(buf1, buf2)
|
---|
36 | self.assertEqual(exc.__name__, excname)
|
---|
37 |
|
---|
38 | def testRaising(self):
|
---|
39 | self.raise_catch(AttributeError, "AttributeError")
|
---|
40 | self.assertRaises(AttributeError, getattr, sys, "undefined_attribute")
|
---|
41 |
|
---|
42 | self.raise_catch(EOFError, "EOFError")
|
---|
43 | fp = open(TESTFN, 'w')
|
---|
44 | fp.close()
|
---|
45 | fp = open(TESTFN, 'r')
|
---|
46 | savestdin = sys.stdin
|
---|
47 | try:
|
---|
48 | try:
|
---|
49 | sys.stdin = fp
|
---|
50 | x = raw_input()
|
---|
51 | except EOFError:
|
---|
52 | pass
|
---|
53 | finally:
|
---|
54 | sys.stdin = savestdin
|
---|
55 | fp.close()
|
---|
56 | unlink(TESTFN)
|
---|
57 |
|
---|
58 | self.raise_catch(IOError, "IOError")
|
---|
59 | self.assertRaises(IOError, open, 'this file does not exist', 'r')
|
---|
60 |
|
---|
61 | self.raise_catch(ImportError, "ImportError")
|
---|
62 | self.assertRaises(ImportError, __import__, "undefined_module")
|
---|
63 |
|
---|
64 | self.raise_catch(IndexError, "IndexError")
|
---|
65 | x = []
|
---|
66 | self.assertRaises(IndexError, x.__getitem__, 10)
|
---|
67 |
|
---|
68 | self.raise_catch(KeyError, "KeyError")
|
---|
69 | x = {}
|
---|
70 | self.assertRaises(KeyError, x.__getitem__, 'key')
|
---|
71 |
|
---|
72 | self.raise_catch(KeyboardInterrupt, "KeyboardInterrupt")
|
---|
73 |
|
---|
74 | self.raise_catch(MemoryError, "MemoryError")
|
---|
75 |
|
---|
76 | self.raise_catch(NameError, "NameError")
|
---|
77 | try: x = undefined_variable
|
---|
78 | except NameError: pass
|
---|
79 |
|
---|
80 | self.raise_catch(OverflowError, "OverflowError")
|
---|
81 | x = 1
|
---|
82 | for dummy in range(128):
|
---|
83 | x += x # this simply shouldn't blow up
|
---|
84 |
|
---|
85 | self.raise_catch(RuntimeError, "RuntimeError")
|
---|
86 |
|
---|
87 | self.raise_catch(SyntaxError, "SyntaxError")
|
---|
88 | try: exec '/\n'
|
---|
89 | except SyntaxError: pass
|
---|
90 |
|
---|
91 | self.raise_catch(IndentationError, "IndentationError")
|
---|
92 |
|
---|
93 | self.raise_catch(TabError, "TabError")
|
---|
94 | # can only be tested under -tt, and is the only test for -tt
|
---|
95 | #try: compile("try:\n\t1/0\n \t1/0\nfinally:\n pass\n", '<string>', 'exec')
|
---|
96 | #except TabError: pass
|
---|
97 | #else: self.fail("TabError not raised")
|
---|
98 |
|
---|
99 | self.raise_catch(SystemError, "SystemError")
|
---|
100 |
|
---|
101 | self.raise_catch(SystemExit, "SystemExit")
|
---|
102 | self.assertRaises(SystemExit, sys.exit, 0)
|
---|
103 |
|
---|
104 | self.raise_catch(TypeError, "TypeError")
|
---|
105 | try: [] + ()
|
---|
106 | except TypeError: pass
|
---|
107 |
|
---|
108 | self.raise_catch(ValueError, "ValueError")
|
---|
109 | self.assertRaises(ValueError, chr, 10000)
|
---|
110 |
|
---|
111 | self.raise_catch(ZeroDivisionError, "ZeroDivisionError")
|
---|
112 | try: x = 1 // 0
|
---|
113 | except ZeroDivisionError: pass
|
---|
114 |
|
---|
115 | self.raise_catch(Exception, "Exception")
|
---|
116 | try: x = 1 // 0
|
---|
117 | except Exception, e: pass
|
---|
118 |
|
---|
119 | def testSyntaxErrorMessage(self):
|
---|
120 | # make sure the right exception message is raised for each of
|
---|
121 | # these code fragments
|
---|
122 |
|
---|
123 | def ckmsg(src, msg):
|
---|
124 | try:
|
---|
125 | compile(src, '<fragment>', 'exec')
|
---|
126 | except SyntaxError, e:
|
---|
127 | if e.msg != msg:
|
---|
128 | self.fail("expected %s, got %s" % (msg, e.msg))
|
---|
129 | else:
|
---|
130 | self.fail("failed to get expected SyntaxError")
|
---|
131 |
|
---|
132 | s = '''while 1:
|
---|
133 | try:
|
---|
134 | pass
|
---|
135 | finally:
|
---|
136 | continue'''
|
---|
137 |
|
---|
138 | if not sys.platform.startswith('java'):
|
---|
139 | ckmsg(s, "'continue' not supported inside 'finally' clause")
|
---|
140 |
|
---|
141 | s = '''if 1:
|
---|
142 | try:
|
---|
143 | continue
|
---|
144 | except:
|
---|
145 | pass'''
|
---|
146 |
|
---|
147 | ckmsg(s, "'continue' not properly in loop")
|
---|
148 | ckmsg("continue\n", "'continue' not properly in loop")
|
---|
149 |
|
---|
150 | @cpython_only
|
---|
151 | def testSettingException(self):
|
---|
152 | # test that setting an exception at the C level works even if the
|
---|
153 | # exception object can't be constructed.
|
---|
154 |
|
---|
155 | class BadException:
|
---|
156 | def __init__(self_):
|
---|
157 | raise RuntimeError, "can't instantiate BadException"
|
---|
158 |
|
---|
159 | def test_capi1():
|
---|
160 | import _testcapi
|
---|
161 | try:
|
---|
162 | _testcapi.raise_exception(BadException, 1)
|
---|
163 | except TypeError, err:
|
---|
164 | exc, err, tb = sys.exc_info()
|
---|
165 | co = tb.tb_frame.f_code
|
---|
166 | self.assertEqual(co.co_name, "test_capi1")
|
---|
167 | self.assertTrue(co.co_filename.endswith('test_exceptions'+os.extsep+'py'))
|
---|
168 | else:
|
---|
169 | self.fail("Expected exception")
|
---|
170 |
|
---|
171 | def test_capi2():
|
---|
172 | import _testcapi
|
---|
173 | try:
|
---|
174 | _testcapi.raise_exception(BadException, 0)
|
---|
175 | except RuntimeError, err:
|
---|
176 | exc, err, tb = sys.exc_info()
|
---|
177 | co = tb.tb_frame.f_code
|
---|
178 | self.assertEqual(co.co_name, "__init__")
|
---|
179 | self.assertTrue(co.co_filename.endswith('test_exceptions'+os.extsep+'py'))
|
---|
180 | co2 = tb.tb_frame.f_back.f_code
|
---|
181 | self.assertEqual(co2.co_name, "test_capi2")
|
---|
182 | else:
|
---|
183 | self.fail("Expected exception")
|
---|
184 |
|
---|
185 | if not sys.platform.startswith('java'):
|
---|
186 | test_capi1()
|
---|
187 | test_capi2()
|
---|
188 |
|
---|
189 | def test_WindowsError(self):
|
---|
190 | try:
|
---|
191 | WindowsError
|
---|
192 | except NameError:
|
---|
193 | pass
|
---|
194 | else:
|
---|
195 | self.assertEqual(str(WindowsError(1001)),
|
---|
196 | "1001")
|
---|
197 | self.assertEqual(str(WindowsError(1001, "message")),
|
---|
198 | "[Error 1001] message")
|
---|
199 | self.assertEqual(WindowsError(1001, "message").errno, 22)
|
---|
200 | self.assertEqual(WindowsError(1001, "message").winerror, 1001)
|
---|
201 |
|
---|
202 | @ignore_deprecation_warnings
|
---|
203 | def testAttributes(self):
|
---|
204 | # test that exception attributes are happy
|
---|
205 |
|
---|
206 | exceptionList = [
|
---|
207 | (BaseException, (), {'message' : '', 'args' : ()}),
|
---|
208 | (BaseException, (1, ), {'message' : 1, 'args' : (1,)}),
|
---|
209 | (BaseException, ('foo',),
|
---|
210 | {'message' : 'foo', 'args' : ('foo',)}),
|
---|
211 | (BaseException, ('foo', 1),
|
---|
212 | {'message' : '', 'args' : ('foo', 1)}),
|
---|
213 | (SystemExit, ('foo',),
|
---|
214 | {'message' : 'foo', 'args' : ('foo',), 'code' : 'foo'}),
|
---|
215 | (IOError, ('foo',),
|
---|
216 | {'message' : 'foo', 'args' : ('foo',), 'filename' : None,
|
---|
217 | 'errno' : None, 'strerror' : None}),
|
---|
218 | (IOError, ('foo', 'bar'),
|
---|
219 | {'message' : '', 'args' : ('foo', 'bar'), 'filename' : None,
|
---|
220 | 'errno' : 'foo', 'strerror' : 'bar'}),
|
---|
221 | (IOError, ('foo', 'bar', 'baz'),
|
---|
222 | {'message' : '', 'args' : ('foo', 'bar'), 'filename' : 'baz',
|
---|
223 | 'errno' : 'foo', 'strerror' : 'bar'}),
|
---|
224 | (IOError, ('foo', 'bar', 'baz', 'quux'),
|
---|
225 | {'message' : '', 'args' : ('foo', 'bar', 'baz', 'quux')}),
|
---|
226 | (EnvironmentError, ('errnoStr', 'strErrorStr', 'filenameStr'),
|
---|
227 | {'message' : '', 'args' : ('errnoStr', 'strErrorStr'),
|
---|
228 | 'strerror' : 'strErrorStr', 'errno' : 'errnoStr',
|
---|
229 | 'filename' : 'filenameStr'}),
|
---|
230 | (EnvironmentError, (1, 'strErrorStr', 'filenameStr'),
|
---|
231 | {'message' : '', 'args' : (1, 'strErrorStr'), 'errno' : 1,
|
---|
232 | 'strerror' : 'strErrorStr', 'filename' : 'filenameStr'}),
|
---|
233 | (SyntaxError, (), {'message' : '', 'msg' : None, 'text' : None,
|
---|
234 | 'filename' : None, 'lineno' : None, 'offset' : None,
|
---|
235 | 'print_file_and_line' : None}),
|
---|
236 | (SyntaxError, ('msgStr',),
|
---|
237 | {'message' : 'msgStr', 'args' : ('msgStr',), 'text' : None,
|
---|
238 | 'print_file_and_line' : None, 'msg' : 'msgStr',
|
---|
239 | 'filename' : None, 'lineno' : None, 'offset' : None}),
|
---|
240 | (SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
|
---|
241 | 'textStr')),
|
---|
242 | {'message' : '', 'offset' : 'offsetStr', 'text' : 'textStr',
|
---|
243 | 'args' : ('msgStr', ('filenameStr', 'linenoStr',
|
---|
244 | 'offsetStr', 'textStr')),
|
---|
245 | 'print_file_and_line' : None, 'msg' : 'msgStr',
|
---|
246 | 'filename' : 'filenameStr', 'lineno' : 'linenoStr'}),
|
---|
247 | (SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
|
---|
248 | 'textStr', 'print_file_and_lineStr'),
|
---|
249 | {'message' : '', 'text' : None,
|
---|
250 | 'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
|
---|
251 | 'textStr', 'print_file_and_lineStr'),
|
---|
252 | 'print_file_and_line' : None, 'msg' : 'msgStr',
|
---|
253 | 'filename' : None, 'lineno' : None, 'offset' : None}),
|
---|
254 | (UnicodeError, (), {'message' : '', 'args' : (),}),
|
---|
255 | (UnicodeEncodeError, ('ascii', u'a', 0, 1, 'ordinal not in range'),
|
---|
256 | {'message' : '', 'args' : ('ascii', u'a', 0, 1,
|
---|
257 | 'ordinal not in range'),
|
---|
258 | 'encoding' : 'ascii', 'object' : u'a',
|
---|
259 | 'start' : 0, 'reason' : 'ordinal not in range'}),
|
---|
260 | (UnicodeDecodeError, ('ascii', '\xff', 0, 1, 'ordinal not in range'),
|
---|
261 | {'message' : '', 'args' : ('ascii', '\xff', 0, 1,
|
---|
262 | 'ordinal not in range'),
|
---|
263 | 'encoding' : 'ascii', 'object' : '\xff',
|
---|
264 | 'start' : 0, 'reason' : 'ordinal not in range'}),
|
---|
265 | (UnicodeTranslateError, (u"\u3042", 0, 1, "ouch"),
|
---|
266 | {'message' : '', 'args' : (u'\u3042', 0, 1, 'ouch'),
|
---|
267 | 'object' : u'\u3042', 'reason' : 'ouch',
|
---|
268 | 'start' : 0, 'end' : 1}),
|
---|
269 | ]
|
---|
270 | try:
|
---|
271 | exceptionList.append(
|
---|
272 | (WindowsError, (1, 'strErrorStr', 'filenameStr'),
|
---|
273 | {'message' : '', 'args' : (1, 'strErrorStr'),
|
---|
274 | 'strerror' : 'strErrorStr', 'winerror' : 1,
|
---|
275 | 'errno' : 22, 'filename' : 'filenameStr'})
|
---|
276 | )
|
---|
277 | except NameError:
|
---|
278 | pass
|
---|
279 |
|
---|
280 | for exc, args, expected in exceptionList:
|
---|
281 | try:
|
---|
282 | raise exc(*args)
|
---|
283 | except BaseException, e:
|
---|
284 | if type(e) is not exc:
|
---|
285 | raise
|
---|
286 | # Verify module name
|
---|
287 | self.assertEqual(type(e).__module__, 'exceptions')
|
---|
288 | # Verify no ref leaks in Exc_str()
|
---|
289 | s = str(e)
|
---|
290 | for checkArgName in expected:
|
---|
291 | self.assertEqual(repr(getattr(e, checkArgName)),
|
---|
292 | repr(expected[checkArgName]),
|
---|
293 | 'exception "%s", attribute "%s"' %
|
---|
294 | (repr(e), checkArgName))
|
---|
295 |
|
---|
296 | # test for pickling support
|
---|
297 | for p in pickle, cPickle:
|
---|
298 | for protocol in range(p.HIGHEST_PROTOCOL + 1):
|
---|
299 | new = p.loads(p.dumps(e, protocol))
|
---|
300 | for checkArgName in expected:
|
---|
301 | got = repr(getattr(new, checkArgName))
|
---|
302 | want = repr(expected[checkArgName])
|
---|
303 | self.assertEqual(got, want,
|
---|
304 | 'pickled "%r", attribute "%s"' %
|
---|
305 | (e, checkArgName))
|
---|
306 |
|
---|
307 |
|
---|
308 | def testDeprecatedMessageAttribute(self):
|
---|
309 | # Accessing BaseException.message and relying on its value set by
|
---|
310 | # BaseException.__init__ triggers a deprecation warning.
|
---|
311 | exc = BaseException("foo")
|
---|
312 | with check_warnings(("BaseException.message has been deprecated "
|
---|
313 | "as of Python 2.6", DeprecationWarning)) as w:
|
---|
314 | self.assertEqual(exc.message, "foo")
|
---|
315 | self.assertEqual(len(w.warnings), 1)
|
---|
316 |
|
---|
317 | def testRegularMessageAttribute(self):
|
---|
318 | # Accessing BaseException.message after explicitly setting a value
|
---|
319 | # for it does not trigger a deprecation warning.
|
---|
320 | exc = BaseException("foo")
|
---|
321 | exc.message = "bar"
|
---|
322 | with check_warnings(quiet=True) as w:
|
---|
323 | self.assertEqual(exc.message, "bar")
|
---|
324 | self.assertEqual(len(w.warnings), 0)
|
---|
325 | # Deleting the message is supported, too.
|
---|
326 | del exc.message
|
---|
327 | with self.assertRaises(AttributeError):
|
---|
328 | exc.message
|
---|
329 |
|
---|
330 | @ignore_deprecation_warnings
|
---|
331 | def testPickleMessageAttribute(self):
|
---|
332 | # Pickling with message attribute must work, as well.
|
---|
333 | e = Exception("foo")
|
---|
334 | f = Exception("foo")
|
---|
335 | f.message = "bar"
|
---|
336 | for p in pickle, cPickle:
|
---|
337 | ep = p.loads(p.dumps(e))
|
---|
338 | self.assertEqual(ep.message, "foo")
|
---|
339 | fp = p.loads(p.dumps(f))
|
---|
340 | self.assertEqual(fp.message, "bar")
|
---|
341 |
|
---|
342 | @ignore_deprecation_warnings
|
---|
343 | def testSlicing(self):
|
---|
344 | # Test that you can slice an exception directly instead of requiring
|
---|
345 | # going through the 'args' attribute.
|
---|
346 | args = (1, 2, 3)
|
---|
347 | exc = BaseException(*args)
|
---|
348 | self.assertEqual(exc[:], args)
|
---|
349 | self.assertEqual(exc.args[:], args)
|
---|
350 |
|
---|
351 | def testKeywordArgs(self):
|
---|
352 | # test that builtin exception don't take keyword args,
|
---|
353 | # but user-defined subclasses can if they want
|
---|
354 | self.assertRaises(TypeError, BaseException, a=1)
|
---|
355 |
|
---|
356 | class DerivedException(BaseException):
|
---|
357 | def __init__(self, fancy_arg):
|
---|
358 | BaseException.__init__(self)
|
---|
359 | self.fancy_arg = fancy_arg
|
---|
360 |
|
---|
361 | x = DerivedException(fancy_arg=42)
|
---|
362 | self.assertEqual(x.fancy_arg, 42)
|
---|
363 |
|
---|
364 | def testInfiniteRecursion(self):
|
---|
365 | def f():
|
---|
366 | return f()
|
---|
367 | self.assertRaises(RuntimeError, f)
|
---|
368 |
|
---|
369 | def g():
|
---|
370 | try:
|
---|
371 | return g()
|
---|
372 | except ValueError:
|
---|
373 | return -1
|
---|
374 |
|
---|
375 | # The test prints an unraisable recursion error when
|
---|
376 | # doing "except ValueError", this is because subclass
|
---|
377 | # checking has recursion checking too.
|
---|
378 | with captured_output("stderr"):
|
---|
379 | try:
|
---|
380 | g()
|
---|
381 | except RuntimeError:
|
---|
382 | pass
|
---|
383 | except:
|
---|
384 | self.fail("Should have raised KeyError")
|
---|
385 | else:
|
---|
386 | self.fail("Should have raised KeyError")
|
---|
387 |
|
---|
388 | def testUnicodeStrUsage(self):
|
---|
389 | # Make sure both instances and classes have a str and unicode
|
---|
390 | # representation.
|
---|
391 | self.assertTrue(str(Exception))
|
---|
392 | self.assertTrue(unicode(Exception))
|
---|
393 | self.assertTrue(str(Exception('a')))
|
---|
394 | self.assertTrue(unicode(Exception(u'a')))
|
---|
395 | self.assertTrue(unicode(Exception(u'\xe1')))
|
---|
396 |
|
---|
397 | def testUnicodeChangeAttributes(self):
|
---|
398 | # See issue 7309. This was a crasher.
|
---|
399 |
|
---|
400 | u = UnicodeEncodeError('baz', u'xxxxx', 1, 5, 'foo')
|
---|
401 | self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: foo")
|
---|
402 | u.end = 2
|
---|
403 | self.assertEqual(str(u), "'baz' codec can't encode character u'\\x78' in position 1: foo")
|
---|
404 | u.end = 5
|
---|
405 | u.reason = 0x345345345345345345
|
---|
406 | self.assertEqual(str(u), "'baz' codec can't encode characters in position 1-4: 965230951443685724997")
|
---|
407 | u.encoding = 4000
|
---|
408 | self.assertEqual(str(u), "'4000' codec can't encode characters in position 1-4: 965230951443685724997")
|
---|
409 | u.start = 1000
|
---|
410 | self.assertEqual(str(u), "'4000' codec can't encode characters in position 1000-4: 965230951443685724997")
|
---|
411 |
|
---|
412 | u = UnicodeDecodeError('baz', 'xxxxx', 1, 5, 'foo')
|
---|
413 | self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: foo")
|
---|
414 | u.end = 2
|
---|
415 | self.assertEqual(str(u), "'baz' codec can't decode byte 0x78 in position 1: foo")
|
---|
416 | u.end = 5
|
---|
417 | u.reason = 0x345345345345345345
|
---|
418 | self.assertEqual(str(u), "'baz' codec can't decode bytes in position 1-4: 965230951443685724997")
|
---|
419 | u.encoding = 4000
|
---|
420 | self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1-4: 965230951443685724997")
|
---|
421 | u.start = 1000
|
---|
422 | self.assertEqual(str(u), "'4000' codec can't decode bytes in position 1000-4: 965230951443685724997")
|
---|
423 |
|
---|
424 | u = UnicodeTranslateError(u'xxxx', 1, 5, 'foo')
|
---|
425 | self.assertEqual(str(u), "can't translate characters in position 1-4: foo")
|
---|
426 | u.end = 2
|
---|
427 | self.assertEqual(str(u), "can't translate character u'\\x78' in position 1: foo")
|
---|
428 | u.end = 5
|
---|
429 | u.reason = 0x345345345345345345
|
---|
430 | self.assertEqual(str(u), "can't translate characters in position 1-4: 965230951443685724997")
|
---|
431 | u.start = 1000
|
---|
432 | self.assertEqual(str(u), "can't translate characters in position 1000-4: 965230951443685724997")
|
---|
433 |
|
---|
434 | def test_badisinstance(self):
|
---|
435 | # Bug #2542: if issubclass(e, MyException) raises an exception,
|
---|
436 | # it should be ignored
|
---|
437 | class Meta(type):
|
---|
438 | def __subclasscheck__(cls, subclass):
|
---|
439 | raise ValueError()
|
---|
440 |
|
---|
441 | class MyException(Exception):
|
---|
442 | __metaclass__ = Meta
|
---|
443 | pass
|
---|
444 |
|
---|
445 | with captured_output("stderr") as stderr:
|
---|
446 | try:
|
---|
447 | raise KeyError()
|
---|
448 | except MyException, e:
|
---|
449 | self.fail("exception should not be a MyException")
|
---|
450 | except KeyError:
|
---|
451 | pass
|
---|
452 | except:
|
---|
453 | self.fail("Should have raised KeyError")
|
---|
454 | else:
|
---|
455 | self.fail("Should have raised KeyError")
|
---|
456 |
|
---|
457 | with captured_output("stderr") as stderr:
|
---|
458 | def g():
|
---|
459 | try:
|
---|
460 | return g()
|
---|
461 | except RuntimeError:
|
---|
462 | return sys.exc_info()
|
---|
463 | e, v, tb = g()
|
---|
464 | self.assertTrue(e is RuntimeError, e)
|
---|
465 | self.assertIn("maximum recursion depth exceeded", str(v))
|
---|
466 |
|
---|
467 | def test_new_returns_invalid_instance(self):
|
---|
468 | # See issue #11627.
|
---|
469 | class MyException(Exception):
|
---|
470 | def __new__(cls, *args):
|
---|
471 | return object()
|
---|
472 |
|
---|
473 | with self.assertRaises(TypeError):
|
---|
474 | raise MyException
|
---|
475 |
|
---|
476 | def test_assert_with_tuple_arg(self):
|
---|
477 | try:
|
---|
478 | assert False, (3,)
|
---|
479 | except AssertionError as e:
|
---|
480 | self.assertEqual(str(e), "(3,)")
|
---|
481 |
|
---|
482 | def test_bad_exception_clearing(self):
|
---|
483 | # See issue 16445: use of Py_XDECREF instead of Py_CLEAR in
|
---|
484 | # BaseException_set_message gave a possible way to segfault the
|
---|
485 | # interpreter.
|
---|
486 | class Nasty(str):
|
---|
487 | def __del__(message):
|
---|
488 | del e.message
|
---|
489 |
|
---|
490 | e = ValueError(Nasty("msg"))
|
---|
491 | e.args = ()
|
---|
492 | del e.message
|
---|
493 |
|
---|
494 |
|
---|
495 | # Helper class used by TestSameStrAndUnicodeMsg
|
---|
496 | class ExcWithOverriddenStr(Exception):
|
---|
497 | """Subclass of Exception that accepts a keyword 'msg' arg that is
|
---|
498 | returned by __str__. 'msg' won't be included in self.args"""
|
---|
499 | def __init__(self, *args, **kwargs):
|
---|
500 | self.msg = kwargs.pop('msg') # msg should always be present
|
---|
501 | super(ExcWithOverriddenStr, self).__init__(*args, **kwargs)
|
---|
502 | def __str__(self):
|
---|
503 | return self.msg
|
---|
504 |
|
---|
505 |
|
---|
506 | class TestSameStrAndUnicodeMsg(unittest.TestCase):
|
---|
507 | """unicode(err) should return the same message of str(err). See #6108"""
|
---|
508 |
|
---|
509 | def check_same_msg(self, exc, msg):
|
---|
510 | """Helper function that checks if str(exc) == unicode(exc) == msg"""
|
---|
511 | self.assertEqual(str(exc), msg)
|
---|
512 | self.assertEqual(str(exc), unicode(exc))
|
---|
513 |
|
---|
514 | def test_builtin_exceptions(self):
|
---|
515 | """Check same msg for built-in exceptions"""
|
---|
516 | # These exceptions implement a __str__ method that uses the args
|
---|
517 | # to create a better error message. unicode(e) should return the same
|
---|
518 | # message.
|
---|
519 | exceptions = [
|
---|
520 | SyntaxError('invalid syntax', ('<string>', 1, 3, '2+*3')),
|
---|
521 | IOError(2, 'No such file or directory'),
|
---|
522 | KeyError('both should have the same quotes'),
|
---|
523 | UnicodeDecodeError('ascii', '\xc3\xa0', 0, 1,
|
---|
524 | 'ordinal not in range(128)'),
|
---|
525 | UnicodeEncodeError('ascii', u'\u1234', 0, 1,
|
---|
526 | 'ordinal not in range(128)')
|
---|
527 | ]
|
---|
528 | for exception in exceptions:
|
---|
529 | self.assertEqual(str(exception), unicode(exception))
|
---|
530 |
|
---|
531 | def test_0_args(self):
|
---|
532 | """Check same msg for Exception with 0 args"""
|
---|
533 | # str() and unicode() on an Exception with no args should return an
|
---|
534 | # empty string
|
---|
535 | self.check_same_msg(Exception(), '')
|
---|
536 |
|
---|
537 | def test_0_args_with_overridden___str__(self):
|
---|
538 | """Check same msg for exceptions with 0 args and overridden __str__"""
|
---|
539 | # str() and unicode() on an exception with overridden __str__ that
|
---|
540 | # returns an ascii-only string should return the same string
|
---|
541 | for msg in ('foo', u'foo'):
|
---|
542 | self.check_same_msg(ExcWithOverriddenStr(msg=msg), msg)
|
---|
543 |
|
---|
544 | # if __str__ returns a non-ascii unicode string str() should fail
|
---|
545 | # but unicode() should return the unicode string
|
---|
546 | e = ExcWithOverriddenStr(msg=u'f\xf6\xf6') # no args
|
---|
547 | self.assertRaises(UnicodeEncodeError, str, e)
|
---|
548 | self.assertEqual(unicode(e), u'f\xf6\xf6')
|
---|
549 |
|
---|
550 | def test_1_arg(self):
|
---|
551 | """Check same msg for Exceptions with 1 arg"""
|
---|
552 | for arg in ('foo', u'foo'):
|
---|
553 | self.check_same_msg(Exception(arg), arg)
|
---|
554 |
|
---|
555 | # if __str__ is not overridden and self.args[0] is a non-ascii unicode
|
---|
556 | # string, str() should try to return str(self.args[0]) and fail.
|
---|
557 | # unicode() should return unicode(self.args[0]) and succeed.
|
---|
558 | e = Exception(u'f\xf6\xf6')
|
---|
559 | self.assertRaises(UnicodeEncodeError, str, e)
|
---|
560 | self.assertEqual(unicode(e), u'f\xf6\xf6')
|
---|
561 |
|
---|
562 | def test_1_arg_with_overridden___str__(self):
|
---|
563 | """Check same msg for exceptions with overridden __str__ and 1 arg"""
|
---|
564 | # when __str__ is overridden and __unicode__ is not implemented
|
---|
565 | # unicode(e) returns the same as unicode(e.__str__()).
|
---|
566 | for msg in ('foo', u'foo'):
|
---|
567 | self.check_same_msg(ExcWithOverriddenStr('arg', msg=msg), msg)
|
---|
568 |
|
---|
569 | # if __str__ returns a non-ascii unicode string, str() should fail
|
---|
570 | # but unicode() should succeed.
|
---|
571 | e = ExcWithOverriddenStr('arg', msg=u'f\xf6\xf6') # 1 arg
|
---|
572 | self.assertRaises(UnicodeEncodeError, str, e)
|
---|
573 | self.assertEqual(unicode(e), u'f\xf6\xf6')
|
---|
574 |
|
---|
575 | def test_many_args(self):
|
---|
576 | """Check same msg for Exceptions with many args"""
|
---|
577 | argslist = [
|
---|
578 | (3, 'foo'),
|
---|
579 | (1, u'foo', 'bar'),
|
---|
580 | (4, u'f\xf6\xf6', u'bar', 'baz')
|
---|
581 | ]
|
---|
582 | # both str() and unicode() should return a repr() of the args
|
---|
583 | for args in argslist:
|
---|
584 | self.check_same_msg(Exception(*args), repr(args))
|
---|
585 |
|
---|
586 | def test_many_args_with_overridden___str__(self):
|
---|
587 | """Check same msg for exceptions with overridden __str__ and many args"""
|
---|
588 | # if __str__ returns an ascii string / ascii unicode string
|
---|
589 | # both str() and unicode() should succeed
|
---|
590 | for msg in ('foo', u'foo'):
|
---|
591 | e = ExcWithOverriddenStr('arg1', u'arg2', u'f\xf6\xf6', msg=msg)
|
---|
592 | self.check_same_msg(e, msg)
|
---|
593 |
|
---|
594 | # if __str__ returns a non-ascii unicode string, str() should fail
|
---|
595 | # but unicode() should succeed
|
---|
596 | e = ExcWithOverriddenStr('arg1', u'f\xf6\xf6', u'arg3', # 3 args
|
---|
597 | msg=u'f\xf6\xf6')
|
---|
598 | self.assertRaises(UnicodeEncodeError, str, e)
|
---|
599 | self.assertEqual(unicode(e), u'f\xf6\xf6')
|
---|
600 |
|
---|
601 | @cpython_only
|
---|
602 | def test_exception_with_doc(self):
|
---|
603 | import _testcapi
|
---|
604 | doc2 = "This is a test docstring."
|
---|
605 | doc4 = "This is another test docstring."
|
---|
606 |
|
---|
607 | self.assertRaises(SystemError, _testcapi.make_exception_with_doc,
|
---|
608 | "error1")
|
---|
609 |
|
---|
610 | # test basic usage of PyErr_NewException
|
---|
611 | error1 = _testcapi.make_exception_with_doc("_testcapi.error1")
|
---|
612 | self.assertIs(type(error1), type)
|
---|
613 | self.assertTrue(issubclass(error1, Exception))
|
---|
614 | self.assertIsNone(error1.__doc__)
|
---|
615 |
|
---|
616 | # test with given docstring
|
---|
617 | error2 = _testcapi.make_exception_with_doc("_testcapi.error2", doc2)
|
---|
618 | self.assertEqual(error2.__doc__, doc2)
|
---|
619 |
|
---|
620 | # test with explicit base (without docstring)
|
---|
621 | error3 = _testcapi.make_exception_with_doc("_testcapi.error3",
|
---|
622 | base=error2)
|
---|
623 | self.assertTrue(issubclass(error3, error2))
|
---|
624 |
|
---|
625 | # test with explicit base tuple
|
---|
626 | class C(object):
|
---|
627 | pass
|
---|
628 | error4 = _testcapi.make_exception_with_doc("_testcapi.error4", doc4,
|
---|
629 | (error3, C))
|
---|
630 | self.assertTrue(issubclass(error4, error3))
|
---|
631 | self.assertTrue(issubclass(error4, C))
|
---|
632 | self.assertEqual(error4.__doc__, doc4)
|
---|
633 |
|
---|
634 | # test with explicit dictionary
|
---|
635 | error5 = _testcapi.make_exception_with_doc("_testcapi.error5", "",
|
---|
636 | error4, {'a': 1})
|
---|
637 | self.assertTrue(issubclass(error5, error4))
|
---|
638 | self.assertEqual(error5.a, 1)
|
---|
639 | self.assertEqual(error5.__doc__, "")
|
---|
640 |
|
---|
641 |
|
---|
642 | def test_main():
|
---|
643 | run_unittest(ExceptionTests, TestSameStrAndUnicodeMsg)
|
---|
644 |
|
---|
645 | if __name__ == '__main__':
|
---|
646 | test_main()
|
---|