diff options
-rw-r--r-- | Lib/test/test_generators.py | 11 | ||||
-rw-r--r-- | Lib/test/test_with.py | 1 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Python/ceval.c | 14 | ||||
-rw-r--r-- | Python/compile.c | 3 |
5 files changed, 26 insertions, 6 deletions
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index ad7e17c..19bfe07 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -1700,6 +1700,17 @@ And finalization: >>> del g exiting +>>> class context(object): +... def __enter__(self): pass +... def __exit__(self, *args): print 'exiting' +>>> def f(): +... with context(): +... yield +>>> g = f() +>>> g.next() +>>> del g +exiting + GeneratorExit is not caught by except Exception: diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py index 4b947d8..a1ec80b 100644 --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -361,7 +361,6 @@ class ExceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin): self.assertAfterWithManagerInvariantsWithError(cm) self.assertAfterWithGeneratorInvariantsWithError(self.resource) - @unittest.expectedFailure def testExceptionNormalized(self): cm = mock_contextmanager_generator() def shouldThrow(): @@ -12,6 +12,9 @@ What's New in Python 2.7 alpha 3? Core and Builtins ----------------- +- Issue #7853: Normalize exceptions before they are passed to a context managers + __exit__ method. + - Issue #7385: Fix a crash in `MemoryView_FromObject` when `PyObject_GetBuffer` fails. Patch by Florent Xicluna. diff --git a/Python/ceval.c b/Python/ceval.c index d501a4e..0b8a377 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2555,9 +2555,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) Py_DECREF(u); if (!x) break; - /* Setup the finally block before pushing the result - of __enter__ on the stack. */ - PyFrame_BlockSetup(f, SETUP_FINALLY, INSTR_OFFSET() + oparg, + /* Setup a finally block (SETUP_WITH as a block is + equivalent to SETUP_FINALLY except it normalizes + the exception) before pushing the result of + __enter__ on the stack. */ + PyFrame_BlockSetup(f, SETUP_WITH, INSTR_OFFSET() + oparg, STACK_LEVEL()); PUSH(x); @@ -2898,7 +2900,8 @@ fast_block_end: } if (b->b_type == SETUP_FINALLY || (b->b_type == SETUP_EXCEPT && - why == WHY_EXCEPTION)) { + why == WHY_EXCEPTION) || + b->b_type == SETUP_WITH) { if (why == WHY_EXCEPTION) { PyObject *exc, *val, *tb; PyErr_Fetch(&exc, &val, &tb); @@ -2911,7 +2914,8 @@ fast_block_end: so a program can emulate the Python main loop. Don't do this for 'finally'. */ - if (b->b_type == SETUP_EXCEPT) { + if (b->b_type == SETUP_EXCEPT || + b->b_type == SETUP_WITH) { PyErr_NormalizeException( &exc, &val, &tb); set_exc_info(tstate, diff --git a/Python/compile.c b/Python/compile.c index 1e27539..4ea2ee9 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2927,6 +2927,9 @@ compiler_with(struct compiler *c, stmt_ty s) /* SETUP_WITH pushes a finally block. */ compiler_use_next_block(c, block); + /* Note that the block is actually called SETUP_WITH in ceval.c, but + functions the same as SETUP_FINALLY except that exceptions are + normalized. */ if (!compiler_push_fblock(c, FINALLY_TRY, block)) { return 0; } |