summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/compiler/pyassem.py2
-rw-r--r--Lib/compiler/pycodegen.py2
-rw-r--r--Lib/contextlib.py11
-rw-r--r--Lib/decimal.py2
-rw-r--r--Lib/test/test_with.py32
-rw-r--r--Lib/threading.py6
-rw-r--r--Modules/threadmodule.c31
-rw-r--r--Objects/fileobject.c27
-rw-r--r--Python/ceval.c47
-rw-r--r--Python/compile.c4
-rw-r--r--Python/import.c1
11 files changed, 60 insertions, 105 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):
diff --git a/Modules/threadmodule.c b/Modules/threadmodule.c
index f15cacb..9a6c5d8 100644
--- a/Modules/threadmodule.c
+++ b/Modules/threadmodule.c
@@ -68,7 +68,7 @@ lock_PyThread_acquire_lock(lockobject *self, PyObject *args)
PyDoc_STRVAR(acquire_doc,
"acquire([wait]) -> None or bool\n\
-(PyThread_acquire_lock() is an obsolete synonym)\n\
+(acquire_lock() is an obsolete synonym)\n\
\n\
Lock the lock. Without argument, this blocks if the lock is already\n\
locked (even by the same thread), waiting for another thread to release\n\
@@ -94,7 +94,7 @@ lock_PyThread_release_lock(lockobject *self)
PyDoc_STRVAR(release_doc,
"release()\n\
-(PyThread_release_lock() is an obsolete synonym)\n\
+(release_lock() is an obsolete synonym)\n\
\n\
Release the lock, allowing another thread that is blocked waiting for\n\
the lock to acquire the lock. The lock must be in the locked state,\n\
@@ -123,29 +123,6 @@ lock_context(lockobject *self)
return (PyObject *)self;
}
-PyDoc_STRVAR(lock_exit_doc,
-"__exit__(type, value, tb)\n\
-\n\
-Releases the lock; then re-raises the exception if type is not None.");
-
-static PyObject *
-lock_exit(lockobject *self, PyObject *args)
-{
- PyObject *type, *value, *tb, *result;
- if (!PyArg_ParseTuple(args, "OOO:__exit__", &type, &value, &tb))
- return NULL;
- result = lock_PyThread_release_lock(self);
- if (result != NULL && type != Py_None) {
- Py_DECREF(result);
- result = NULL;
- Py_INCREF(type);
- Py_INCREF(value);
- Py_INCREF(tb);
- PyErr_Restore(type, value, tb);
- }
- return result;
-}
-
static PyMethodDef lock_methods[] = {
{"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock,
METH_VARARGS, acquire_doc},
@@ -163,8 +140,8 @@ static PyMethodDef lock_methods[] = {
METH_NOARGS, PyDoc_STR("__context__() -> self.")},
{"__enter__", (PyCFunction)lock_PyThread_acquire_lock,
METH_VARARGS, acquire_doc},
- {"__exit__", (PyCFunction)lock_exit,
- METH_VARARGS, lock_exit_doc},
+ {"__exit__", (PyCFunction)lock_PyThread_release_lock,
+ METH_VARARGS, release_doc},
{NULL, NULL} /* sentinel */
};
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index b39a10f..57a9e9d 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -1617,24 +1617,6 @@ file_self(PyFileObject *f)
return (PyObject *)f;
}
-static PyObject *
-file_exit(PyFileObject *f, PyObject *args)
-{
- PyObject *type, *value, *tb, *result;
- if (!PyArg_ParseTuple(args, "OOO:__exit__", &type, &value, &tb))
- return NULL;
- result = file_close(f);
- if (result != NULL && type != Py_None) {
- Py_DECREF(result);
- result = NULL;
- Py_INCREF(type);
- Py_INCREF(value);
- Py_INCREF(tb);
- PyErr_Restore(type, value, tb);
- }
- return result;
-}
-
PyDoc_STRVAR(readline_doc,
"readline([size]) -> next line from the file, as a string.\n"
"\n"
@@ -1725,13 +1707,6 @@ PyDoc_STRVAR(context_doc,
PyDoc_STRVAR(enter_doc,
"__enter__() -> self.");
-PyDoc_STRVAR(exit_doc,
-"__exit__(type, value, traceback).\n\
-\n\
-Closes the file; then re-raises the exception if type is not None.\n\
-If no exception is re-raised, the return value is the same as for close().\n\
-");
-
static PyMethodDef file_methods[] = {
{"readline", (PyCFunction)file_readline, METH_VARARGS, readline_doc},
{"read", (PyCFunction)file_read, METH_VARARGS, read_doc},
@@ -1751,7 +1726,7 @@ static PyMethodDef file_methods[] = {
{"isatty", (PyCFunction)file_isatty, METH_NOARGS, isatty_doc},
{"__context__", (PyCFunction)file_self, METH_NOARGS, context_doc},
{"__enter__", (PyCFunction)file_self, METH_NOARGS, enter_doc},
- {"__exit__", (PyCFunction)file_exit, METH_VARARGS, exit_doc},
+ {"__exit__", (PyCFunction)file_close, METH_VARARGS, close_doc},
{NULL, NULL} /* sentinel */
};
diff --git a/Python/ceval.c b/Python/ceval.c
index e7fb875..de2b35b 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2189,48 +2189,51 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw)
Below that are 1-3 values indicating how/why
we entered the finally clause:
- SECOND = None
- - (SECOND, THIRD) = (WHY_RETURN or WHY_CONTINUE), retval
+ - (SECOND, THIRD) = (WHY_{RETURN,CONTINUE}), retval
- SECOND = WHY_*; no retval below it
- (SECOND, THIRD, FOURTH) = exc_info()
In the last case, we must call
TOP(SECOND, THIRD, FOURTH)
otherwise we must call
TOP(None, None, None)
- but we must preserve the stack entries below TOP.
- The code here just sets the stack up for the call;
- separate CALL_FUNCTION(3) and POP_TOP opcodes are
- emitted by the compiler.
In addition, if the stack represents an exception,
- we "zap" this information; __exit__() should
- re-raise the exception if it wants to, and if
- __exit__() returns normally, END_FINALLY should
- *not* re-raise the exception. (But non-local
- gotos should still be resumed.)
+ *and* the function call returns a 'true' value, we
+ "zap" this information, to prevent END_FINALLY from
+ re-raising the exception. (But non-local gotos
+ should still be resumed.)
*/
x = TOP();
u = SECOND();
if (PyInt_Check(u) || u == Py_None) {
u = v = w = Py_None;
- Py_INCREF(u);
- Py_INCREF(v);
- Py_INCREF(w);
}
else {
v = THIRD();
w = FOURTH();
- /* Zap the exception from the stack,
- to fool END_FINALLY. */
- STACKADJ(-2);
- SET_TOP(x);
+ }
+ /* XXX Not the fastest way to call it... */
+ x = PyObject_CallFunctionObjArgs(x, u, v, w, NULL);
+ if (x == NULL)
+ break; /* Go to error exit */
+ if (u != Py_None && PyObject_IsTrue(x)) {
+ /* There was an exception and a true return */
+ Py_DECREF(x);
+ x = TOP(); /* Again */
+ STACKADJ(-3);
Py_INCREF(Py_None);
- SET_SECOND(Py_None);
+ SET_TOP(Py_None);
+ Py_DECREF(x);
+ Py_DECREF(u);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ } else {
+ /* Let END_FINALLY do its thing */
+ Py_DECREF(x);
+ x = POP();
+ Py_DECREF(x);
}
- STACKADJ(3);
- SET_THIRD(u);
- SET_SECOND(v);
- SET_TOP(w);
break;
}
diff --git a/Python/compile.c b/Python/compile.c
index c07b6d3..e3b3df8 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1382,7 +1382,7 @@ opcode_stack_effect(int opcode, int oparg)
case BREAK_LOOP:
return 0;
case WITH_CLEANUP:
- return 3;
+ return -1; /* XXX Sometimes more */
case LOAD_LOCALS:
return 1;
case RETURN_VALUE:
@@ -3472,8 +3472,6 @@ compiler_with(struct compiler *c, stmt_ty s)
!compiler_nameop(c, tmpexit, Del))
return 0;
ADDOP(c, WITH_CLEANUP);
- ADDOP_I(c, CALL_FUNCTION, 3);
- ADDOP(c, POP_TOP);
/* Finally block ends. */
ADDOP(c, END_FINALLY);
diff --git a/Python/import.c b/Python/import.c
index f214ed5..73051a2 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -55,6 +55,7 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
Python 2.5a0: 62071
Python 2.5a0: 62081 (ast-branch)
Python 2.5a0: 62091 (with)
+ Python 2.5a0: 62092 (changed WITH_CLEANUP opcode)
.
*/
#define MAGIC (62092 | ((long)'\r'<<16) | ((long)'\n'<<24))