To solve this problem, I extracted the class from the module, given its module name and class name (the code below assumes that the module is not loaded yet):
void Model::Visit(const char* mod_name, const char* class_name) { PyErr_Clear(); PyObject* mod_name_obj = PyString_FromString(mod_name); PyObject* class_name_obj = PyString_FromString(class_name); PyObject* py_module = PyImport_Import(mod_name_obj); PyObject* err_1 = PyErr_Occurred(); if(err_1) PyErr_Print();
As soon as I got a module, I looked for a class from it:
if(py_module) { PyObject* py_module_dict = PyModule_GetDict(py_module); PyObject* py_class = PyDict_GetItem(py_module_dict, class_name_obj);
I simplified my problem a bit by creating an instance of the python class in C ++, then created my visitor, and finally visited it:
if(py_class && PyClass_Check(py_class) && PyCallable_Check(py_class)) { PyObject* inst = PyInstance_New(py_class, 0, 0); if(inst && PyInstance_Check(inst)) { IModel::IVisitorPtr py_visitor = new PyModelVisitor(inst); _model->Visit(py_visitor); } } } }
The visitor had 3 functions OnStateBegin (), OnNode () and OnStateEnd (). I added to my python SWIG binding generator the ability to generate a header file for external access to the SWIG runtime with an external long-term option , so I could create a C ++ class (below INode *) and pass it to Python as an argument to the function- Python OnNode () member as follows (validation error removed for brevity):
VisitorCtrl OnNode(INode* node) { Node* node_impl = new NodeImpl(node); PyObject* pynode = SWIG_NewPointerObj(node_impl, SWIG_TypeQuery("Node *"), 0); PyObject* result = PyObject_CallMethodObjArgs(_inst, PyString_FromString("OnNode"), pynode, 0); long rivis = PyInt_AsLong(result); return(static_cast<VisitorCtrl>(rivis)); }
source share