/Lib/test/test_exceptions.py

http://unladen-swallow.googlecode.com/ · Python · 507 lines · 399 code · 69 blank · 39 comment · 81 complexity · 15711cf1e65fdc03e0875ed71d20617c MD5 · raw file

  1. # Python test set -- part 5, built-in exceptions
  2. import os
  3. import sys
  4. import unittest
  5. import pickle, cPickle
  6. import warnings
  7. from test.test_support import TESTFN, unlink, run_unittest, captured_output
  8. from test.test_pep352 import ignore_message_warning
  9. # XXX This is not really enough, each *operation* should be tested!
  10. class ExceptionTests(unittest.TestCase):
  11. def testReload(self):
  12. # Reloading the built-in exceptions module failed prior to Py2.2, while it
  13. # should act the same as reloading built-in sys.
  14. try:
  15. import exceptions
  16. reload(exceptions)
  17. except ImportError, e:
  18. self.fail("reloading exceptions: %s" % e)
  19. def raise_catch(self, exc, excname):
  20. try:
  21. raise exc, "spam"
  22. except exc, err:
  23. buf1 = str(err)
  24. try:
  25. raise exc("spam")
  26. except exc, err:
  27. buf2 = str(err)
  28. self.assertEquals(buf1, buf2)
  29. self.assertEquals(exc.__name__, excname)
  30. def testRaising(self):
  31. self.raise_catch(AttributeError, "AttributeError")
  32. self.assertRaises(AttributeError, getattr, sys, "undefined_attribute")
  33. self.raise_catch(EOFError, "EOFError")
  34. fp = open(TESTFN, 'w')
  35. fp.close()
  36. fp = open(TESTFN, 'r')
  37. savestdin = sys.stdin
  38. try:
  39. try:
  40. sys.stdin = fp
  41. x = raw_input()
  42. except EOFError:
  43. pass
  44. finally:
  45. sys.stdin = savestdin
  46. fp.close()
  47. unlink(TESTFN)
  48. self.raise_catch(IOError, "IOError")
  49. self.assertRaises(IOError, open, 'this file does not exist', 'r')
  50. self.raise_catch(ImportError, "ImportError")
  51. self.assertRaises(ImportError, __import__, "undefined_module")
  52. self.raise_catch(IndexError, "IndexError")
  53. x = []
  54. self.assertRaises(IndexError, x.__getitem__, 10)
  55. self.raise_catch(KeyError, "KeyError")
  56. x = {}
  57. self.assertRaises(KeyError, x.__getitem__, 'key')
  58. self.raise_catch(KeyboardInterrupt, "KeyboardInterrupt")
  59. self.raise_catch(MemoryError, "MemoryError")
  60. self.raise_catch(NameError, "NameError")
  61. try: x = undefined_variable
  62. except NameError: pass
  63. self.raise_catch(OverflowError, "OverflowError")
  64. x = 1
  65. for dummy in range(128):
  66. x += x # this simply shouldn't blow up
  67. self.raise_catch(RuntimeError, "RuntimeError")
  68. self.raise_catch(SyntaxError, "SyntaxError")
  69. try: exec '/\n'
  70. except SyntaxError: pass
  71. self.raise_catch(IndentationError, "IndentationError")
  72. self.raise_catch(TabError, "TabError")
  73. # can only be tested under -tt, and is the only test for -tt
  74. #try: compile("try:\n\t1/0\n \t1/0\nfinally:\n pass\n", '<string>', 'exec')
  75. #except TabError: pass
  76. #else: self.fail("TabError not raised")
  77. self.raise_catch(SystemError, "SystemError")
  78. self.raise_catch(SystemExit, "SystemExit")
  79. self.assertRaises(SystemExit, sys.exit, 0)
  80. self.raise_catch(TypeError, "TypeError")
  81. try: [] + ()
  82. except TypeError: pass
  83. self.raise_catch(ValueError, "ValueError")
  84. self.assertRaises(ValueError, chr, 10000)
  85. self.raise_catch(ZeroDivisionError, "ZeroDivisionError")
  86. try: x = 1/0
  87. except ZeroDivisionError: pass
  88. self.raise_catch(Exception, "Exception")
  89. try: x = 1/0
  90. except Exception, e: pass
  91. def testExcInfoUnaffectedByNestedFunction(self):
  92. def raise_and_catch():
  93. try:
  94. raise IndexError("inner exception")
  95. except IndexError:
  96. pass
  97. try:
  98. raise ValueError("outer exception")
  99. except ValueError:
  100. exc, val, tb = sys.exc_info()
  101. self.assertEquals(exc, ValueError)
  102. self.assertEquals(val.args, ("outer exception",))
  103. raise_and_catch() # Risk clobbering sys.exc_info().
  104. self.assertEquals(sys.exc_info(), (exc, val, tb))
  105. def testExcInfoUnaffectedByGenerator(self):
  106. def raising_generator():
  107. try:
  108. raise IndexError("inner exception")
  109. except IndexError:
  110. yield 3
  111. try:
  112. raise ValueError("outer exception")
  113. except ValueError:
  114. exc, val, tb = sys.exc_info()
  115. self.assertEquals(exc, ValueError)
  116. self.assertEquals(val.args, ("outer exception",))
  117. g = raising_generator()
  118. self.assertEquals(g.next(), 3) # Risk clobbering sys.exc_info().
  119. self.assertEquals(sys.exc_info(), (exc, val, tb))
  120. self.assertRaises(StopIteration, g.next)
  121. self.assertEquals(sys.exc_info(), (exc, val, tb))
  122. def testExcInfoInGeneratorClobberedByYield(self):
  123. def raising_generator():
  124. try:
  125. raise IndexError("inner exception")
  126. except IndexError:
  127. exc, val, tb = sys.exc_info()
  128. self.assertEquals(exc, IndexError)
  129. self.assertEquals(val.args, ("inner exception",))
  130. yield 3
  131. # The next line ought to be the assertion, but
  132. # Python 2.6 resets the exception from the calling
  133. # function, so we test bug-for-bug compatibility
  134. # within the 2.6 series.
  135. #
  136. # self.assertEquals(sys.exc_info(), (exc, val, tb))
  137. self.assertEquals(sys.exc_info(), (None, None, None))
  138. for i in raising_generator():
  139. pass
  140. def testExcInfoVisibleInNestedFunction(self):
  141. def check_exc_info(exc, val, tb):
  142. self.assertEquals(sys.exc_info(), (exc, val, tb))
  143. try:
  144. raise IndexError("inner exception")
  145. except IndexError:
  146. pass
  147. exc3, val3, tb3 = sys.exc_info()
  148. self.assertEquals(exc3, IndexError)
  149. self.assertEquals(val3.args, ("inner exception",))
  150. self.assertNotEquals(tb3, tb)
  151. try:
  152. raise ValueError("outer exception")
  153. except ValueError:
  154. check_exc_info(*sys.exc_info())
  155. def testSyntaxErrorMessage(self):
  156. # make sure the right exception message is raised for each of
  157. # these code fragments
  158. def ckmsg(src, msg):
  159. try:
  160. compile(src, '<fragment>', 'exec')
  161. except SyntaxError, e:
  162. if e.msg != msg:
  163. self.fail("expected %s, got %s" % (msg, e.msg))
  164. else:
  165. self.fail("failed to get expected SyntaxError")
  166. s = '''while 1:
  167. try:
  168. pass
  169. finally:
  170. continue'''
  171. if not sys.platform.startswith('java'):
  172. ckmsg(s, "'continue' not supported inside 'finally' clause")
  173. s = '''if 1:
  174. try:
  175. continue
  176. except:
  177. pass'''
  178. ckmsg(s, "'continue' not properly in loop")
  179. ckmsg("continue\n", "'continue' not properly in loop")
  180. def testSettingException(self):
  181. # test that setting an exception at the C level works even if the
  182. # exception object can't be constructed.
  183. class BadException:
  184. def __init__(self_):
  185. raise RuntimeError, "can't instantiate BadException"
  186. def test_capi1():
  187. import _testcapi
  188. try:
  189. _testcapi.raise_exception(BadException, 1)
  190. except TypeError, err:
  191. exc, err, tb = sys.exc_info()
  192. co = tb.tb_frame.f_code
  193. self.assertEquals(co.co_name, "test_capi1")
  194. self.assert_(co.co_filename.endswith('test_exceptions'+os.extsep+'py'))
  195. else:
  196. self.fail("Expected exception")
  197. def test_capi2():
  198. import _testcapi
  199. try:
  200. _testcapi.raise_exception(BadException, 0)
  201. except RuntimeError, err:
  202. exc, err, tb = sys.exc_info()
  203. co = tb.tb_frame.f_code
  204. self.assertEquals(co.co_name, "__init__")
  205. self.assert_(co.co_filename.endswith('test_exceptions'+os.extsep+'py'))
  206. co2 = tb.tb_frame.f_back.f_code
  207. self.assertEquals(co2.co_name, "test_capi2")
  208. else:
  209. self.fail("Expected exception")
  210. if not sys.platform.startswith('java'):
  211. test_capi1()
  212. test_capi2()
  213. def test_WindowsError(self):
  214. try:
  215. WindowsError
  216. except NameError:
  217. pass
  218. else:
  219. self.failUnlessEqual(str(WindowsError(1001)),
  220. "1001")
  221. self.failUnlessEqual(str(WindowsError(1001, "message")),
  222. "[Error 1001] message")
  223. self.failUnlessEqual(WindowsError(1001, "message").errno, 22)
  224. self.failUnlessEqual(WindowsError(1001, "message").winerror, 1001)
  225. def testAttributes(self):
  226. # test that exception attributes are happy
  227. exceptionList = [
  228. (BaseException, (), {'message' : '', 'args' : ()}),
  229. (BaseException, (1, ), {'message' : 1, 'args' : (1,)}),
  230. (BaseException, ('foo',),
  231. {'message' : 'foo', 'args' : ('foo',)}),
  232. (BaseException, ('foo', 1),
  233. {'message' : '', 'args' : ('foo', 1)}),
  234. (SystemExit, ('foo',),
  235. {'message' : 'foo', 'args' : ('foo',), 'code' : 'foo'}),
  236. (IOError, ('foo',),
  237. {'message' : 'foo', 'args' : ('foo',), 'filename' : None,
  238. 'errno' : None, 'strerror' : None}),
  239. (IOError, ('foo', 'bar'),
  240. {'message' : '', 'args' : ('foo', 'bar'), 'filename' : None,
  241. 'errno' : 'foo', 'strerror' : 'bar'}),
  242. (IOError, ('foo', 'bar', 'baz'),
  243. {'message' : '', 'args' : ('foo', 'bar'), 'filename' : 'baz',
  244. 'errno' : 'foo', 'strerror' : 'bar'}),
  245. (IOError, ('foo', 'bar', 'baz', 'quux'),
  246. {'message' : '', 'args' : ('foo', 'bar', 'baz', 'quux')}),
  247. (EnvironmentError, ('errnoStr', 'strErrorStr', 'filenameStr'),
  248. {'message' : '', 'args' : ('errnoStr', 'strErrorStr'),
  249. 'strerror' : 'strErrorStr', 'errno' : 'errnoStr',
  250. 'filename' : 'filenameStr'}),
  251. (EnvironmentError, (1, 'strErrorStr', 'filenameStr'),
  252. {'message' : '', 'args' : (1, 'strErrorStr'), 'errno' : 1,
  253. 'strerror' : 'strErrorStr', 'filename' : 'filenameStr'}),
  254. (SyntaxError, (), {'message' : '', 'msg' : None, 'text' : None,
  255. 'filename' : None, 'lineno' : None, 'offset' : None,
  256. 'print_file_and_line' : None}),
  257. (SyntaxError, ('msgStr',),
  258. {'message' : 'msgStr', 'args' : ('msgStr',), 'text' : None,
  259. 'print_file_and_line' : None, 'msg' : 'msgStr',
  260. 'filename' : None, 'lineno' : None, 'offset' : None}),
  261. (SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
  262. 'textStr')),
  263. {'message' : '', 'offset' : 'offsetStr', 'text' : 'textStr',
  264. 'args' : ('msgStr', ('filenameStr', 'linenoStr',
  265. 'offsetStr', 'textStr')),
  266. 'print_file_and_line' : None, 'msg' : 'msgStr',
  267. 'filename' : 'filenameStr', 'lineno' : 'linenoStr'}),
  268. (SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
  269. 'textStr', 'print_file_and_lineStr'),
  270. {'message' : '', 'text' : None,
  271. 'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
  272. 'textStr', 'print_file_and_lineStr'),
  273. 'print_file_and_line' : None, 'msg' : 'msgStr',
  274. 'filename' : None, 'lineno' : None, 'offset' : None}),
  275. (UnicodeError, (), {'message' : '', 'args' : (),}),
  276. (UnicodeEncodeError, ('ascii', u'a', 0, 1, 'ordinal not in range'),
  277. {'message' : '', 'args' : ('ascii', u'a', 0, 1,
  278. 'ordinal not in range'),
  279. 'encoding' : 'ascii', 'object' : u'a',
  280. 'start' : 0, 'reason' : 'ordinal not in range'}),
  281. (UnicodeDecodeError, ('ascii', '\xff', 0, 1, 'ordinal not in range'),
  282. {'message' : '', 'args' : ('ascii', '\xff', 0, 1,
  283. 'ordinal not in range'),
  284. 'encoding' : 'ascii', 'object' : '\xff',
  285. 'start' : 0, 'reason' : 'ordinal not in range'}),
  286. (UnicodeTranslateError, (u"\u3042", 0, 1, "ouch"),
  287. {'message' : '', 'args' : (u'\u3042', 0, 1, 'ouch'),
  288. 'object' : u'\u3042', 'reason' : 'ouch',
  289. 'start' : 0, 'end' : 1}),
  290. ]
  291. try:
  292. exceptionList.append(
  293. (WindowsError, (1, 'strErrorStr', 'filenameStr'),
  294. {'message' : '', 'args' : (1, 'strErrorStr'),
  295. 'strerror' : 'strErrorStr', 'winerror' : 1,
  296. 'errno' : 22, 'filename' : 'filenameStr'})
  297. )
  298. except NameError:
  299. pass
  300. with warnings.catch_warnings():
  301. ignore_message_warning()
  302. for exc, args, expected in exceptionList:
  303. try:
  304. raise exc(*args)
  305. except BaseException, e:
  306. if type(e) is not exc:
  307. raise
  308. # Verify module name
  309. self.assertEquals(type(e).__module__, 'exceptions')
  310. # Verify no ref leaks in Exc_str()
  311. s = str(e)
  312. for checkArgName in expected:
  313. self.assertEquals(repr(getattr(e, checkArgName)),
  314. repr(expected[checkArgName]),
  315. 'exception "%s", attribute "%s"' %
  316. (repr(e), checkArgName))
  317. # test for pickling support
  318. for p in pickle, cPickle:
  319. for protocol in range(p.HIGHEST_PROTOCOL + 1):
  320. new = p.loads(p.dumps(e, protocol))
  321. for checkArgName in expected:
  322. got = repr(getattr(new, checkArgName))
  323. want = repr(expected[checkArgName])
  324. self.assertEquals(got, want,
  325. 'pickled "%r", attribute "%s"' %
  326. (e, checkArgName))
  327. def testDeprecatedMessageAttribute(self):
  328. # Accessing BaseException.message and relying on its value set by
  329. # BaseException.__init__ triggers a deprecation warning.
  330. exc = BaseException("foo")
  331. with warnings.catch_warnings(record=True) as w:
  332. self.assertEquals(exc.message, "foo")
  333. self.assertEquals(len(w), 1)
  334. self.assertEquals(w[0].category, DeprecationWarning)
  335. self.assertEquals(
  336. str(w[0].message),
  337. "BaseException.message has been deprecated as of Python 2.6")
  338. def testRegularMessageAttribute(self):
  339. # Accessing BaseException.message after explicitly setting a value
  340. # for it does not trigger a deprecation warning.
  341. exc = BaseException("foo")
  342. exc.message = "bar"
  343. with warnings.catch_warnings(record=True) as w:
  344. self.assertEquals(exc.message, "bar")
  345. self.assertEquals(len(w), 0)
  346. # Deleting the message is supported, too.
  347. del exc.message
  348. self.assertRaises(AttributeError, getattr, exc, "message")
  349. def testPickleMessageAttribute(self):
  350. # Pickling with message attribute must work, as well.
  351. e = Exception("foo")
  352. f = Exception("foo")
  353. f.message = "bar"
  354. for p in pickle, cPickle:
  355. ep = p.loads(p.dumps(e))
  356. with warnings.catch_warnings():
  357. ignore_message_warning()
  358. self.assertEqual(ep.message, "foo")
  359. fp = p.loads(p.dumps(f))
  360. self.assertEqual(fp.message, "bar")
  361. def testSlicing(self):
  362. # Test that you can slice an exception directly instead of requiring
  363. # going through the 'args' attribute.
  364. args = (1, 2, 3)
  365. exc = BaseException(*args)
  366. self.failUnlessEqual(exc[:], args)
  367. def testKeywordArgs(self):
  368. # test that builtin exception don't take keyword args,
  369. # but user-defined subclasses can if they want
  370. self.assertRaises(TypeError, BaseException, a=1)
  371. class DerivedException(BaseException):
  372. def __init__(self, fancy_arg):
  373. BaseException.__init__(self)
  374. self.fancy_arg = fancy_arg
  375. x = DerivedException(fancy_arg=42)
  376. self.assertEquals(x.fancy_arg, 42)
  377. def testInfiniteRecursion(self):
  378. def f():
  379. return f()
  380. self.assertRaises(RuntimeError, f)
  381. def g():
  382. try:
  383. return g()
  384. except ValueError:
  385. return -1
  386. # The test prints an unraisable recursion error when
  387. # doing "except ValueError", this is because subclass
  388. # checking has recursion checking too.
  389. with captured_output("stderr"):
  390. try:
  391. g()
  392. except RuntimeError:
  393. pass
  394. except:
  395. self.fail("Should have raised KeyError")
  396. else:
  397. self.fail("Should have raised KeyError")
  398. def testUnicodeStrUsage(self):
  399. # Make sure both instances and classes have a str and unicode
  400. # representation.
  401. self.failUnless(str(Exception))
  402. self.failUnless(unicode(Exception))
  403. self.failUnless(str(Exception('a')))
  404. self.failUnless(unicode(Exception(u'a')))
  405. self.failUnless(unicode(Exception(u'\xe1')))
  406. def test_badisinstance(self):
  407. # Bug #2542: if issubclass(e, MyException) raises an exception,
  408. # it should be ignored
  409. class Meta(type):
  410. def __subclasscheck__(cls, subclass):
  411. raise ValueError()
  412. class MyException(Exception):
  413. __metaclass__ = Meta
  414. pass
  415. with captured_output("stderr") as stderr:
  416. try:
  417. raise KeyError()
  418. except MyException, e:
  419. self.fail("exception should not be a MyException")
  420. except KeyError:
  421. pass
  422. except:
  423. self.fail("Should have raised KeyError")
  424. else:
  425. self.fail("Should have raised KeyError")
  426. with captured_output("stderr") as stderr:
  427. def g():
  428. try:
  429. return g()
  430. except RuntimeError:
  431. return sys.exc_info()
  432. e, v, tb = g()
  433. self.assert_(e is RuntimeError, e)
  434. self.assert_("maximum recursion depth exceeded" in str(v), v)
  435. def test_main():
  436. run_unittest(ExceptionTests)
  437. if __name__ == '__main__':
  438. test_main()