mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
#3021: Antoine Pitrou's Lexical exception handlers
This commit is contained in:
parent
e8465f2b41
commit
eec3d71379
17 changed files with 410 additions and 303 deletions
|
@ -427,6 +427,7 @@ class ExceptionTests(unittest.TestCase):
|
|||
local_ref = obj
|
||||
raise MyException(obj)
|
||||
|
||||
# Qualified "except" with "as"
|
||||
obj = MyObj()
|
||||
wr = weakref.ref(obj)
|
||||
try:
|
||||
|
@ -437,6 +438,113 @@ class ExceptionTests(unittest.TestCase):
|
|||
obj = wr()
|
||||
self.failUnless(obj is None, "%s" % obj)
|
||||
|
||||
# Qualified "except" without "as"
|
||||
obj = MyObj()
|
||||
wr = weakref.ref(obj)
|
||||
try:
|
||||
inner_raising_func()
|
||||
except MyException:
|
||||
pass
|
||||
obj = None
|
||||
obj = wr()
|
||||
self.failUnless(obj is None, "%s" % obj)
|
||||
|
||||
# Bare "except"
|
||||
obj = MyObj()
|
||||
wr = weakref.ref(obj)
|
||||
try:
|
||||
inner_raising_func()
|
||||
except:
|
||||
pass
|
||||
obj = None
|
||||
obj = wr()
|
||||
self.failUnless(obj is None, "%s" % obj)
|
||||
|
||||
# "except" with premature block leave
|
||||
obj = MyObj()
|
||||
wr = weakref.ref(obj)
|
||||
for i in [0]:
|
||||
try:
|
||||
inner_raising_func()
|
||||
except:
|
||||
break
|
||||
obj = None
|
||||
obj = wr()
|
||||
self.failUnless(obj is None, "%s" % obj)
|
||||
|
||||
# "except" block raising another exception
|
||||
obj = MyObj()
|
||||
wr = weakref.ref(obj)
|
||||
try:
|
||||
try:
|
||||
inner_raising_func()
|
||||
except:
|
||||
raise KeyError
|
||||
except KeyError:
|
||||
obj = None
|
||||
obj = wr()
|
||||
self.failUnless(obj is None, "%s" % obj)
|
||||
|
||||
# Some complicated construct
|
||||
obj = MyObj()
|
||||
wr = weakref.ref(obj)
|
||||
try:
|
||||
inner_raising_func()
|
||||
except MyException:
|
||||
try:
|
||||
try:
|
||||
raise
|
||||
finally:
|
||||
raise
|
||||
except MyException:
|
||||
pass
|
||||
obj = None
|
||||
obj = wr()
|
||||
self.failUnless(obj is None, "%s" % obj)
|
||||
|
||||
# Inside an exception-silencing "with" block
|
||||
class Context:
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__ (self, exc_type, exc_value, exc_tb):
|
||||
return True
|
||||
obj = MyObj()
|
||||
wr = weakref.ref(obj)
|
||||
with Context():
|
||||
inner_raising_func()
|
||||
obj = None
|
||||
obj = wr()
|
||||
self.failUnless(obj is None, "%s" % obj)
|
||||
|
||||
def test_generator_leaking(self):
|
||||
# Test that generator exception state doesn't leak into the calling
|
||||
# frame
|
||||
def yield_raise():
|
||||
try:
|
||||
raise KeyError("caught")
|
||||
except KeyError:
|
||||
yield sys.exc_info()[0]
|
||||
yield sys.exc_info()[0]
|
||||
yield sys.exc_info()[0]
|
||||
g = yield_raise()
|
||||
self.assertEquals(next(g), KeyError)
|
||||
self.assertEquals(sys.exc_info()[0], None)
|
||||
self.assertEquals(next(g), KeyError)
|
||||
self.assertEquals(sys.exc_info()[0], None)
|
||||
self.assertEquals(next(g), None)
|
||||
|
||||
# Same test, but inside an exception handler
|
||||
try:
|
||||
raise TypeError("foo")
|
||||
except TypeError:
|
||||
g = yield_raise()
|
||||
self.assertEquals(next(g), KeyError)
|
||||
self.assertEquals(sys.exc_info()[0], TypeError)
|
||||
self.assertEquals(next(g), KeyError)
|
||||
self.assertEquals(sys.exc_info()[0], TypeError)
|
||||
self.assertEquals(next(g), TypeError)
|
||||
del g
|
||||
self.assertEquals(sys.exc_info()[0], TypeError)
|
||||
|
||||
def test_main():
|
||||
run_unittest(ExceptionTests)
|
||||
|
|
|
@ -16,6 +16,13 @@ def get_tb():
|
|||
return sys.exc_info()[2]
|
||||
|
||||
|
||||
class Context:
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, exc_type, exc_value, exc_tb):
|
||||
return True
|
||||
|
||||
|
||||
class TestRaise(unittest.TestCase):
|
||||
def test_invalid_reraise(self):
|
||||
try:
|
||||
|
@ -37,6 +44,71 @@ class TestRaise(unittest.TestCase):
|
|||
else:
|
||||
self.fail("No exception raised")
|
||||
|
||||
def test_except_reraise(self):
|
||||
def reraise():
|
||||
try:
|
||||
raise TypeError("foo")
|
||||
except:
|
||||
try:
|
||||
raise KeyError("caught")
|
||||
except KeyError:
|
||||
pass
|
||||
raise
|
||||
self.assertRaises(TypeError, reraise)
|
||||
|
||||
def test_finally_reraise(self):
|
||||
def reraise():
|
||||
try:
|
||||
raise TypeError("foo")
|
||||
except:
|
||||
try:
|
||||
raise KeyError("caught")
|
||||
finally:
|
||||
raise
|
||||
self.assertRaises(KeyError, reraise)
|
||||
|
||||
def test_nested_reraise(self):
|
||||
def nested_reraise():
|
||||
raise
|
||||
def reraise():
|
||||
try:
|
||||
raise TypeError("foo")
|
||||
except:
|
||||
nested_reraise()
|
||||
self.assertRaises(TypeError, reraise)
|
||||
|
||||
def test_with_reraise1(self):
|
||||
def reraise():
|
||||
try:
|
||||
raise TypeError("foo")
|
||||
except:
|
||||
with Context():
|
||||
pass
|
||||
raise
|
||||
self.assertRaises(TypeError, reraise)
|
||||
|
||||
def test_with_reraise2(self):
|
||||
def reraise():
|
||||
try:
|
||||
raise TypeError("foo")
|
||||
except:
|
||||
with Context():
|
||||
raise KeyError("caught")
|
||||
raise
|
||||
self.assertRaises(TypeError, reraise)
|
||||
|
||||
def test_yield_reraise(self):
|
||||
def reraise():
|
||||
try:
|
||||
raise TypeError("foo")
|
||||
except:
|
||||
yield 1
|
||||
raise
|
||||
g = reraise()
|
||||
next(g)
|
||||
self.assertRaises(TypeError, lambda: next(g))
|
||||
self.assertRaises(StopIteration, lambda: next(g))
|
||||
|
||||
def test_erroneous_exception(self):
|
||||
class MyException(Exception):
|
||||
def __init__(self):
|
||||
|
@ -158,6 +230,5 @@ class TestRemovedFunctionality(unittest.TestCase):
|
|||
def test_main():
|
||||
support.run_unittest(__name__)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue