Author: Armin Rigo <[email protected]>
Branch:
Changeset: r1030:a988b91f31fc
Date: 2012-11-06 16:22 +0100
http://bitbucket.org/cffi/cffi/changeset/a988b91f31fc/
Log: Write a full traceback when getting an exception in a callback.
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -3788,6 +3788,23 @@
return convert_from_object(result, ctype, pyobj);
}
+static void _my_PyErr_WriteUnraisable(PyObject *obj)
+{
+ /* like PyErr_WriteUnraisable(), but write a full traceback */
+ PyObject *f, *t, *v, *tb;
+ PyErr_Fetch(&t, &v, &tb);
+ f = PySys_GetObject("stderr");
+ if (f != NULL) {
+ PyFile_WriteString("From callback ", f);
+ PyFile_WriteObject(obj, f, 0);
+ PyFile_WriteString(":\n", f);
+ PyErr_Display(t, v, tb);
+ }
+ Py_XDECREF(t);
+ Py_XDECREF(v);
+ Py_XDECREF(tb);
+}
+
static void invoke_callback(ffi_cif *cif, void *result, void **args,
void *userdata)
{
@@ -3837,7 +3854,7 @@
return;
error:
- PyErr_WriteUnraisable(py_ob);
+ _my_PyErr_WriteUnraisable(py_ob);
if (SIGNATURE(1)->ct_size > 0) {
py_rawerr = PyTuple_GET_ITEM(cb_args, 2);
memcpy(result, PyBytes_AS_STRING(py_rawerr),
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1024,6 +1024,52 @@
e = py.test.raises(TypeError, f)
assert str(e.value) == "'int(*)(int)' expects 1 arguments, got 0"
+def test_callback_exception():
+ import cStringIO
+ def matches(str, pattern):
+ while '$' in pattern:
+ i = pattern.index('$')
+ assert str[:i] == pattern[:i]
+ j = str.find(pattern[i+1], i)
+ assert i + 1 <= j < str.find('\n', i)
+ str = str[j:]
+ pattern = pattern[i+1:]
+ assert str == pattern
+ return True
+ def check_value(x):
+ if x == 10000:
+ raise ValueError(42)
+ def cb1(x):
+ check_value(x)
+ return x * 3
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BInt,), BInt, False)
+ f = callback(BFunc, cb1, -42)
+ orig_stderr = sys.stderr
+ try:
+ sys.stderr = cStringIO.StringIO()
+ assert f(100) == 300
+ assert sys.stderr.getvalue() == ''
+ assert f(10000) == -42
+ assert matches(sys.stderr.getvalue(), """\
+From callback <function cb1 at 0x$>:
+Traceback (most recent call last):
+ File "$", line $, in cb1
+ check_value(x)
+ File "$", line $, in check_value
+ raise ValueError(42)
+ValueError: 42
+""")
+ sys.stderr = cStringIO.StringIO()
+ bigvalue = 1 << (8 * size_of_int() - 2)
+ assert f(bigvalue) == -42
+ assert matches(sys.stderr.getvalue(), """\
+From callback <function cb1 at 0x$>:
+OverflowError: integer %d does not fit 'int'
+""" % (bigvalue * 3,))
+ finally:
+ sys.stderr = orig_stderr
+
def test_callback_return_type():
for rettype in ["signed char", "short", "int", "long", "long long",
"unsigned char", "unsigned short", "unsigned int",
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit