Reputation: 3967
I have written code to define a new-type in Python C extension (MyStatus). I wrote the C code to define allocation,deallocation etc as mentioned in this page.
I was able to compile the module and use it from python.
Now i am trying to use this new type in another Python C extension (TestStatus) My requirement is i need to have only one .so for this. I dont want to use MyStatus directly from Python code. I will be only importing TestStatus in my code and i want to initialize the MyStatus from my C extension written for TestStatus.
I have written code like this for TestStatus
static PyObject * TestStatus_checkPyObject *self, PyObject *args)
{
PyObject * mystatus = NULL;
const char *command;
/* Call the class object. */
mystatus = PyObject_CallObject((PyObject *) &MyStatusType, NULL);
return mystatus;
}
PyMODINIT_FUNC initTestStatus(void)
{
(void) Py_InitModule("TestStatus", TestMethods);
initMyStatus();//This is available in the C code written for MyStatus
}
I was able to create the so like what i have mentioned in code. But i am stuck on setting the variables for MyStatus which is a integer and char*(PyObject*) Can somebody throw some light on this, like whether my approach is right and how to initialize and use MyStatus from TestStatus with arguments.
I am trying this with Python 2.6.6 on Rhel 6.3
In MyStatus i have 2 variables
typedef struct {
PyObject_HEAD
int mStatus;
PyObject *mErrorString;
} MyStatus;
I need to initialize the same from TestStatus.
Upvotes: 3
Views: 1445
Reputation: 1726
A Python C extension should provide a C-API to be used from other C modules. So in your case sou should have something in your MyStatus.h
like
/* Header file for MyStatus module */
#ifndef MyStatus_MODULE_H
#define MyStatus_MODULE_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
PyObject_HEAD
int mStatus;
PyObject *mErrorString;
} MyStatus;
#define MyStatus_Type_NUM 0
#define MyStatus_New_NUM 1
#define MyStatus_New_RETURN MyStatus *
#define MyStatus_New_PROTO (int mStatus, PyObject *mErrorString)
/* Total number of C API pointers */
#define MyStatus_API_pointers 2
#ifdef MyStatus_MODULE
/* do nothing for this minimal example */
#else
static void **MyStatus_API;
#define MyStatus_Type (*(PyTypeObject *)(\
MyStatus_API[MyStatus_Type_NUM]))
#define MyStatus_New \
(*(MyStatus_New_RETURN (*)MyStatus_New_PROTO) \
MyStatus_API[MyStatus_New_NUM])
static int import_MyStatus(void)
{
MyStatus_API = (void **)PyCapsule_Import("MyStatus._C_API", 0);
return (MyStatus_API != NULL) ? 0 : -1;
}
#endif /* !defined(MyStatus_MODULE) */
#ifdef __cplusplus
}
#endif
#endif /* !defined(MyStatus_MODULE_H) */
and define something like
static Py MyStatus *
PyMyStatus_New(int mStatus, PyObject *mErrorString){
MyStatus *self;
self = (MyStatus *)MyStatusType.tp_alloc(&MyStatusType, 0);
self->mStatus = mStatus;
Py_INCREF(mErrorString); // in case you don't want to steal a reference
self->mErrorString = mErrorString;
if (!self->mErrorString){
Py_DECREF(self);
return NULL;
}
return self;
}
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif PyMODINIT_FUNC initMyStatus(void){
PyObject *m = Py_InitModule3("MyStatus", methods, "");
static void *MyStatus_API[MyStatus_API_pointers];
MyStatus_API[MyStatus_Type_NUM] = (void *)&MyStatusType;
MyStatus_API[MyStatus_New_NUM] = (void *)MyStatus_New;
PyObject *c_api_object = PyCapsule_New((void *)MyStatus_API, "MyStatus._C_API", NULL);
if (c_api_object != NULL) PyModule_AddObject(m, "_C_API", c_api_object); }
in the MyStauts.c
. Additionally, it is very convenient to
define macros like
PyMyStatus_SET_MSTATUS(self, mStatus)
PyMyStatus_GET_MSTATUS(self)
PyMyStatus_SET_mErrorString(self, mErrorString)
PyMyStatus_GET_mErrorString(self)
to be able to change the underlying structure of MyStatus later on and to handle the reference counts.
If you don't want to do this, you can always initialize and modify MyStatus
objects directly, like shown in the upper example for the MyStatus_New
function.
In TestStatus.c
finally import the C-API.
PyMODINIT_FUNC initTestStatus(void){
import_MyStatus();
Py_InitModule3("TestStatus", methods, "");
}
Now you will be able to use MyStatus_New
and MyStatusType
.
Upvotes: 2