I am trying to wrap python functions to C++ apis using Cython. I have 2 modules sam1.pyx and sam2.pyx
## - sam1.pyx
import sam2
cdef public double calc(double x, double y):
return sam2.calc_sub(x,y)
the contents of the file sam2.py is as follows
## - sam2.py
def calc_sub(x, y):
return x*y
with such a structure, the wrapped sam1.h
along with the corresponding sam1.so
are generated
During the usage in Cpp application,
#include<iostream>
#include<Python.h>
#include"sam1.h"
using namespace std;
int main(){
Py_Initialize();
#if PY_MAJOR_VERSION < 3
initsam1();
#else
PyInit_sam1();
#endif
cout << "Starting Program!!"<<endl;
cout << calc(3, 5);
Py_Finalize();
return 0;
}
the sam2.py
(normal python) is not imported and the error is
Exception NameError: "name 'sam2' is not defined" in 'sam1.calc' ignored
Could you please let me know what is missing?
Problem 1 is that your module initialization function is failing. In Python 3 you need to test the output against NULL, and then print the error (if it occurred):
PyObject* m = PyInit_sam1();
if (m==NULL) {
cout << "Module initialization failed!\n";
if (PyErr_Occurred()) {
PyErr_Print();
}
}
(I'm not 100% sure what you do for Python2 since I think it doesn't return anything. Probably just PyErr_Occurred
). This tells you:
Traceback (most recent call last):
File "sam1.pyx", line 2, in init sam1 (sam1.cpp:1094)
import sam2
ModuleNotFoundError: No module named 'sam2'
This traceback hopefully gives you the clue you need - it's not finding sam2
. This is because the current directory isn't on the path by default for C api programs. You need to set it up so that it is - the following code goes after Py_Initialize
but before the module initialization:
PyObject* path = PySys_GetObject("path");
// append "." to the path
PyObject* result = PyObject_CallMethod(path,"append","(s)",".");
Py_XDECREF(result);
// don't decref path though - it's borrowed
It gets sys.path
and appends .
to it. After that everything works fine.
Note - if you call your program from a different directory then "." refers to the wrong place. If this is the case then you need to do something cleverer and work out the fill path to the directory, probably from argv[0]
.