Reputation: 10885
I am trying to use the Python 3.5 C API to execute some code that includes constructing a class. Specifically this:
class MyClass:
def test(self):
print('test')
MyClass().test()
The problem I have is that it errors like this:
Traceback (most recent call last):
File "<string>", line 1, in <module>
NameError: __build_class__ not found
So somehow I need my module to include __build_class__
, but I am not sure how (I guess that I would also miss other things you get by default when using Python too) - is there a way to include all this built-in stuff in my module?
Here is my code so far:
#include <Python.h>
int main(void)
{
int ret = 0;
PyObject *pValue, *pModule, *pGlobal, *pLocal;
Py_Initialize();
pGlobal = PyDict_New();
pModule = PyModule_New("mymod");
pLocal = PyModule_GetDict(pModule);
pValue = PyRun_String(
"class MyClass:\n\tdef test(self):\n\t\tprint('test')\n\nMyClass().test()",
Py_file_input,
pGlobal,
pLocal);
if (pValue == NULL) {
if (PyErr_Occurred()) {
PyErr_Print();
}
ret = 1;
} else {
Py_DECREF(pValue);
}
Py_Finalize();
return ret;
}
so pValue
is NULL
and it is calling PyErr_Print
.
Upvotes: 0
Views: 866
Reputation: 10885
Their are (at least) two ways to solve this it seems...
Instead of:
pGlobal = PyDict_New();
You can import the __main__
module and get it's globals dictionary like this:
pGlobal = PyModule_GetDict(PyImport_AddModule("__main__"));
This way is described like so:
BUT PyEval_GetGlobals will return null it it is not called from within Python. This will never be the case when extending Python, but when Python is embedded, it may happen. This is because PyRun_* define the global scope, so if you're not somehow inside a PyRun_ thing (e.g. module called from python called from embedder), there are no globals.
In an embedded-python situation, if you decide that all of your PyRun_* calls are going to use
__main__
as the global namespace, PyModule_GetDict(PyImport_AddModule("__main__
")) will do it.
Which I got from the question embedding I found over on this Python list.
Or as an alternative, which I personally prefer to importing the main module (and found here), you can do this to populate the new dictionary you created with the built-in stuff which includes __build_class__
:
pGlobal = PyDict_New();
PyDict_SetItemString(pGlobal, "__builtins__", PyEval_GetBuiltins());
Upvotes: 1