Open In App

C API from Extension Module in Python | Set 1

Improve
Improve
Like Article
Like
Save
Share
Report

Suppose given a C extension module that internally defines a variety of useful functions that can be exported as a public C API for use elsewhere. Now if we want to use these functions inside other extension modules. Then, it is important to know how to link them together but doing it with the C compiler/linker seems excessively complicated.

Code #1 : [C code] Point objects including some utility functions




# Destructor function for points
static void del_Point(PyObject *obj)
{
    free(PyCapsule_GetPointer(obj, "Point"));
}
  
static PyObject *PyPoint_FromPoint(Point *p, int must_free)
{
    return PyCapsule_New(p, "Point", must_free ? del_Point : NULL);
}
  
# Utility functions 
static Point *PyPoint_AsPoint(PyObject *obj)
{
    return (Point *) PyCapsule_GetPointer(obj, "Point");
}


Now, the issue to deal with is how to handle the exportation of the PyPoint_AsPoint() and PyPoint_FromPoint() functions as an API that can be used by and can link to other extension modules. (For example – any other extensions also want to use the wrapped Point objects).

 
Code #2 : Introducing a new header file called Pythonsample.h for the work extension.




//pythonsample.h
#include "Python.h"
#include "work.h"
#ifdef __cplusplus
  
extern "C" {
#endif
  
// Public API Table
    typedef struct
    {
        Point *(*aspoint)(PyObject *);
        PyObject *(*frompoint)(Point *, int);
    } _PointAPIMethods;
  
#ifndef PYTHONSAMPLE_MODULE
  
    /* Method table in external module */
    static _PointAPIMethods *_point_api = 0;


 
Code #3 : Import the API table from “work”




static int import_sample(void)
{
    _point_api = (_PointAPIMethods *) PyCapsule_Import("work._point_api", 0);
    return (_point_api != NULL) ? 1 : 0;
}
/* Macros to implement the programming interface */
#define PyPoint_AsPoint(obj) (_point_api->aspoint)(obj)
#define PyPoint_FromPoint(obj) (_point_api->frompoint)(obj)
#endif
#ifdef __cplusplus
}
#endif


 
_PointAPIMethods table of function pointers is the most important feature as it will be initialized in the exporting module and found by importing modules. The code below shows how to change the original extension module to populate the table and export it.

Code #4 : Destructor and Utility Function




// pythonsample.c
# include "Python.h"
# define PYTHONSAMPLE_MODULE
# include "pythonsample.h"
  
// Destructor function for points 
static void del_Point(PyObject * obj)
{
    printf("Deleting point\n");
    free(PyCapsule_GetPointer(obj, "Point"));
}
  
// Utility functions
static Point * PyPoint_AsPoint(PyObject * obj)
{
    return (Point *) PyCapsule_GetPointer(obj, "Point");
}
  
static PyObject * PyPoint_FromPoint(Point * p, int free)
{
    return PyCapsule_New(p, "Point", free ? del_Point : NULL);
}
  
static _PointAPIMethods _point_api =
{
    PyPoint_AsPoint,
    PyPoint_FromPoint
};


 
Code #5 : Module function




// Module initialization function 
  
PyMODINIT_FUNC
PyInit_sample(void)
{
    PyObject *m;
    PyObject *py_point_api;
    m = PyModule_Create(&samplemodule);
    if (m == NULL)
        return NULL;
          
    // Add the Point C API functions
    py_point_api = PyCapsule_New((void *) &_point_api, "work._point_api", NULL);
    if (py_point_api)
    {
        PyModule_AddObject(m, "_point_api", py_point_api);
    }
    return m;
}




Last Updated : 27 Mar, 2019
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads