[pypy-commit] pypy default: Extension to cpyext proposed by Stefan Behnel: PyErr_{Get, Set}ExcInfo().
arigo
noreply at buildbot.pypy.org
Sun Apr 1 12:34:34 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r54115:623bcea85df3
Date: 2012-04-01 12:30 +0200
http://bitbucket.org/pypy/pypy/changeset/623bcea85df3/
Log: Extension to cpyext proposed by Stefan Behnel:
PyErr_{Get,Set}ExcInfo().
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -167,6 +167,11 @@
frame = self.getnextframe_nohidden(frame)
return None
+ def set_sys_exc_info(self, operror):
+ frame = self.gettopframe_nohidden()
+ if frame: # else, the exception goes nowhere and is lost
+ frame.last_exception = operror
+
def settrace(self, w_func):
"""Set the global trace function."""
if self.space.is_w(w_func, self.space.w_None):
diff --git a/pypy/module/cpyext/pyerrors.py b/pypy/module/cpyext/pyerrors.py
--- a/pypy/module/cpyext/pyerrors.py
+++ b/pypy/module/cpyext/pyerrors.py
@@ -315,3 +315,63 @@
It may be called without holding the interpreter lock."""
space.check_signal_action.set_interrupt()
+ at cpython_api([PyObjectP, PyObjectP, PyObjectP], lltype.Void)
+def PyErr_GetExcInfo(space, ptype, pvalue, ptraceback):
+ """---Cython extension---
+
+ Retrieve the exception info, as known from ``sys.exc_info()``. This
+ refers to an exception that was already caught, not to an exception
+ that was freshly raised. Returns new references for the three
+ objects, any of which may be *NULL*. Does not modify the exception
+ info state.
+
+ .. note::
+
+ This function is not normally used by code that wants to handle
+ exceptions. Rather, it can be used when code needs to save and
+ restore the exception state temporarily. Use
+ :c:func:`PyErr_SetExcInfo` to restore or clear the exception
+ state.
+ """
+ ec = space.getexecutioncontext()
+ operror = ec.sys_exc_info()
+ if operror:
+ ptype[0] = make_ref(space, operror.w_type)
+ pvalue[0] = make_ref(space, operror.get_w_value(space))
+ ptraceback[0] = make_ref(space, space.wrap(operror.get_traceback()))
+ else:
+ ptype[0] = lltype.nullptr(PyObject.TO)
+ pvalue[0] = lltype.nullptr(PyObject.TO)
+ ptraceback[0] = lltype.nullptr(PyObject.TO)
+
+ at cpython_api([PyObject, PyObject, PyObject], lltype.Void)
+def PyErr_SetExcInfo(space, w_type, w_value, w_traceback):
+ """---Cython extension---
+
+ Set the exception info, as known from ``sys.exc_info()``. This refers
+ to an exception that was already caught, not to an exception that was
+ freshly raised. This function steals the references of the arguments.
+ To clear the exception state, pass *NULL* for all three arguments.
+ For general rules about the three arguments, see :c:func:`PyErr_Restore`.
+
+ .. note::
+
+ This function is not normally used by code that wants to handle
+ exceptions. Rather, it can be used when code needs to save and
+ restore the exception state temporarily. Use
+ :c:func:`PyErr_GetExcInfo` to read the exception state.
+ """
+ if w_value is None or space.is_w(w_value, space.w_None):
+ operror = None
+ else:
+ if w_traceback is None or space.is_w(w_traceback, space.w_None):
+ tb = None
+ else:
+ tb = w_traceback
+ operror = OperationError(w_type, w_value, tb)
+ #
+ ec = space.getexecutioncontext()
+ ec.set_sys_exc_info(operror)
+ Py_DecRef(space, w_type)
+ Py_DecRef(space, w_value)
+ Py_DecRef(space, w_traceback)
diff --git a/pypy/module/cpyext/test/test_pyerrors.py b/pypy/module/cpyext/test/test_pyerrors.py
--- a/pypy/module/cpyext/test/test_pyerrors.py
+++ b/pypy/module/cpyext/test/test_pyerrors.py
@@ -218,3 +218,51 @@
assert e.filename == "blyf"
assert e.errno == errno.EBADF
assert e.strerror == os.strerror(errno.EBADF)
+
+ def test_GetSetExcInfo(self):
+ import sys
+ module = self.import_extension('foo', [
+ ("getset_exc_info", "METH_VARARGS",
+ r'''
+ PyObject *type, *val, *tb;
+ PyObject *new_type, *new_val, *new_tb;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple(args, "OOO", &new_type, &new_val, &new_tb))
+ return NULL;
+
+ PyErr_GetExcInfo(&type, &val, &tb);
+
+ Py_INCREF(new_type);
+ Py_INCREF(new_val);
+ Py_INCREF(new_tb);
+ PyErr_SetExcInfo(new_type, new_val, new_tb);
+
+ result = Py_BuildValue("OOO",
+ type ? type : Py_None,
+ val ? val : Py_None,
+ tb ? tb : Py_None);
+ Py_XDECREF(type);
+ Py_XDECREF(val);
+ Py_XDECREF(tb);
+ return result;
+ '''
+ ),
+ ])
+ try:
+ raise ValueError(5)
+ except ValueError, old_exc:
+ new_exc = TypeError("TEST")
+ orig_sys_exc_info = sys.exc_info()
+ orig_exc_info = module.getset_exc_info(new_exc.__class__,
+ new_exc, None)
+ new_sys_exc_info = sys.exc_info()
+ new_exc_info = module.getset_exc_info(*orig_exc_info)
+ reset_sys_exc_info = sys.exc_info()
+
+ assert orig_exc_info[0] is old_exc.__class__
+ assert orig_exc_info[1] is old_exc
+ assert orig_exc_info == orig_sys_exc_info
+ assert orig_exc_info == reset_sys_exc_info
+ assert new_exc_info == (new_exc.__class__, new_exc, None)
+ assert new_exc_info == new_sys_exc_info
More information about the pypy-commit
mailing list