Question

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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top