3

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.

2
  • You're stuck on setting "the variables", which variables? can you be more specific, that would help. Why is it required to have only on .so file? Would it work, if you put the code of both modules in one file? - Sorry, but I did not quit get the problem, so it's hard to shed some light on it. Commented Nov 25, 2013 at 9:34
  • I have edited the post to add information about the variables. Commented Nov 26, 2013 at 5:37

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

11 Comments

I have this code as part of MyStatus. But my doubt is how should i call this from TestStatus. As you can see i am calling initMyStatus. But in the methods of TestStatus, i should initialize a object of MyStatus initialize it with errorstring and status. Thats where i am stuck
I see. I think the problem is that you try to call initMyStatus(); in initTestStatus. You need to call import_MyStatus(); which you have to define in the MyStatus module, to import the C-API. Then you are able to call functions from MyStatus in TestStatus and use the type if you exported it via the C-API.
Will try this and let u know...Thanks for your input
Was your try successful?
You should be able to put everything in one file, the definition of the MyStatus type and the TestStatus type. In that case you don't even need to import the C-API explicitly. However, the way you create and interact with MyStatus objects should remain the same, e.g. via PyMyStatus_New. What I don't get is, why MyStatus should be a python type if you don't want to expose it to python. In that case I would just use normal C structs and functions instead of dealing with a complicated python C-API.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.