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