diff options
author | Guido van Rossum <guido@python.org> | 2006-03-10 02:28:35 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2006-03-10 02:28:35 (GMT) |
commit | f669436189dd44a841caa9ab1ad97a3f7662bf58 (patch) | |
tree | 1a717975d09d4867e8807710a36a6c2999afdb7e /Lib | |
parent | 692cdbc5d648da5239b5caececc954960aa024e9 (diff) | |
download | cpython-f669436189dd44a841caa9ab1ad97a3f7662bf58.zip cpython-f669436189dd44a841caa9ab1ad97a3f7662bf58.tar.gz cpython-f669436189dd44a841caa9ab1ad97a3f7662bf58.tar.bz2 |
Um, I thought I'd already checked this in.
Anyway, this is the changes to the with-statement
so that __exit__ must return a true value in order
for a pending exception to be ignored.
The PEP (343) is already updated.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/compiler/pyassem.py | 2 | ||||
-rw-r--r-- | Lib/compiler/pycodegen.py | 2 | ||||
-rw-r--r-- | Lib/contextlib.py | 11 | ||||
-rw-r--r-- | Lib/decimal.py | 2 | ||||
-rw-r--r-- | Lib/test/test_with.py | 32 | ||||
-rw-r--r-- | Lib/threading.py | 6 |
6 files changed, 28 insertions, 27 deletions
diff --git a/Lib/compiler/pyassem.py b/Lib/compiler/pyassem.py index b59661f..82ff396 100644 --- a/Lib/compiler/pyassem.py +++ b/Lib/compiler/pyassem.py @@ -779,7 +779,7 @@ class StackDepthTracker: 'SETUP_EXCEPT': 3, 'SETUP_FINALLY': 3, 'FOR_ITER': 1, - 'WITH_CLEANUP': 3, + 'WITH_CLEANUP': -1, } # use pattern match patterns = [ diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py index a1236de..2b3a24f 100644 --- a/Lib/compiler/pycodegen.py +++ b/Lib/compiler/pycodegen.py @@ -858,8 +858,6 @@ class CodeGenerator: self.nextBlock(final) self.setups.push((END_FINALLY, final)) self.emit('WITH_CLEANUP') - self.emit('CALL_FUNCTION', 3) - self.emit('POP_TOP') self.emit('END_FINALLY') self.setups.pop() self.__with_count -= 1 diff --git a/Lib/contextlib.py b/Lib/contextlib.py index 33c302d..0a5d608 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -30,8 +30,9 @@ class GeneratorContextManager(object): else: try: self.gen.throw(type, value, traceback) + return True except StopIteration: - pass + return True def contextmanager(func): @@ -91,6 +92,7 @@ def nested(*contexts): """ exits = [] vars = [] + exc = (None, None, None) try: try: for context in contexts: @@ -102,17 +104,14 @@ def nested(*contexts): yield vars except: exc = sys.exc_info() - else: - exc = (None, None, None) finally: while exits: exit = exits.pop() try: - exit(*exc) + if exit(*exc): + exc = (None, None, None) except: exc = sys.exc_info() - else: - exc = (None, None, None) if exc != (None, None, None): raise diff --git a/Lib/decimal.py b/Lib/decimal.py index 49f8115..967f101 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -2196,8 +2196,6 @@ class ContextManager(object): return self.new_context def __exit__(self, t, v, tb): setcontext(self.saved_context) - if t is not None: - raise t, v, tb class Context(object): """Contains the context for a Decimal instance. diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py index 36035e3..4854436 100644 --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -78,8 +78,8 @@ class Nested(object): vars.append(mgr.__enter__()) self.entered.appendleft(mgr) except: - self.__exit__(*sys.exc_info()) - raise + if not self.__exit__(*sys.exc_info()): + raise return vars def __exit__(self, *exc_info): @@ -89,7 +89,8 @@ class Nested(object): ex = exc_info for mgr in self.entered: try: - mgr.__exit__(*ex) + if mgr.__exit__(*ex): + ex = (None, None, None) except: ex = sys.exc_info() self.entered = None @@ -574,9 +575,7 @@ class AssignmentTargetTestCase(unittest.TestCase): class C: def __context__(self): return self def __enter__(self): return 1, 2, 3 - def __exit__(self, t, v, tb): - if t is not None: - raise t, v, tb + def __exit__(self, t, v, tb): pass targets = {1: [0, 1, 2]} with C() as (targets[1][0], targets[1][1], targets[1][2]): self.assertEqual(targets, {1: [1, 2, 3]}) @@ -594,17 +593,30 @@ class AssignmentTargetTestCase(unittest.TestCase): class ExitSwallowsExceptionTestCase(unittest.TestCase): - def testExitSwallowsException(self): - class AfricanOrEuropean: + def testExitTrueSwallowsException(self): + class AfricanSwallow: def __context__(self): return self def __enter__(self): pass - def __exit__(self, t, v, tb): pass + def __exit__(self, t, v, tb): return True try: - with AfricanOrEuropean(): + with AfricanSwallow(): 1/0 except ZeroDivisionError: self.fail("ZeroDivisionError should have been swallowed") + def testExitFalseDoesntSwallowException(self): + class EuropeanSwallow: + def __context__(self): return self + def __enter__(self): pass + def __exit__(self, t, v, tb): return False + try: + with EuropeanSwallow(): + 1/0 + except ZeroDivisionError: + pass + else: + self.fail("ZeroDivisionError should have been raised") + def test_main(): run_unittest(FailureTestCase, NonexceptionalTestCase, diff --git a/Lib/threading.py b/Lib/threading.py index 5b485d5..cc1adce 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -128,8 +128,6 @@ class _RLock(_Verbose): def __exit__(self, t, v, tb): self.release() - if t is not None: - raise t, v, tb # Internal methods used by condition variables @@ -190,8 +188,6 @@ class _Condition(_Verbose): def __exit__(self, t, v, tb): self.release() - if t is not None: - raise t, v, tb def __repr__(self): return "<Condition(%s, %d)>" % (self.__lock, len(self.__waiters)) @@ -321,8 +317,6 @@ class _Semaphore(_Verbose): def __exit__(self, t, v, tb): self.release() - if t is not None: - raise t, v, tb def BoundedSemaphore(*args, **kwargs): |