C API version of str(exception) is not the same as pure python version
Barry Scott
barry at barrys-emacs.org
Sun Feb 10 06:59:16 EST 2019
When I use the C API to get the str() of an execption I see this text:
<class 'TypeError'>
But python reports the following for the same exception:
TypeError: unsupported operand type(s) for +: 'int' and 'str'
What do I need to do in the C API to get the the same text for the exception?
All the code I'm using is below. I have been debugging this on Fedora 29 with
python 3.7.2.
To repoduce the problem put the three files in a folder and run:
$ py3 setup.py build
$ PYTHONPATH=build/lib.linux-x86_64-3.7 python3 simple_test.py
Which will output:
Error: <class 'TypeError'>
Traceback (most recent call last):
File "simple_test.py", line 7, in <module>
simple.test_error()
File "simple_test.py", line 5, in simple_eval
return eval( arg )
File "<string>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
---- setup.py ---
import os
os.environ['CFLAGS'] = "-O0 -g"
from distutils.core import setup, Extension
setup(name = 'simple', version = '1.0',
ext_modules = [Extension('simple', ['simple.c'])])
--- simple.c ---
#include <Python.h>
#include <stdio.h>
// Yes I know the ref counts are not decremented
static PyObject *test_error(PyObject *self, PyObject *args)
{
PyObject *m = PyImport_AddModule( "__main__" );
PyObject *m_dict = PyModule_GetDict( m );
PyObject *func_args = PyTuple_New( 1 );
PyObject *str = PyUnicode_FromString( "1 + 'q'" );
PyTuple_SetItem( func_args, 0, str);
PyObject *func = PyMapping_GetItemString( m_dict, "simple_eval" );
assert( func != 0 );
PyObject *result = PyObject_CallObject( func, func_args );
PyObject *err = PyErr_Occurred();
if( err != 0 )
{
PyObject *u_why = PyObject_Str( err );
PyObject *b_why = PyUnicode_AsEncodedString( u_why, "utf-8", "strict"
);
int size = PyBytes_Size( b_why );
char *why = PyBytes_AsString( b_why );
printf("Error: %*s\n", size, why );
return 0;
}
return result;
}
static PyMethodDef myMethods[] = {
{ "test_error", test_error, METH_NOARGS, "test eval with error" },
{ NULL, NULL, 0, NULL }
};
static struct PyModuleDef simple = {
PyModuleDef_HEAD_INIT,
"simple",
"Simple Module",
-1,
myMethods
};
// Initializes our module using our above struct
PyMODINIT_FUNC PyInit_simple(void)
{
return PyModule_Create(&simple);
}
--- simple_test.py ---
import sys
import simple
def simple_eval( arg ):
return eval( arg )
simple.test_error()
--- end --
Barry
More information about the Python-list
mailing list