Supplemental integration examples

Last update: 8/11/97

This page contains a few additional Python/C integration examples which didn't make it into the first edition, but will probably show up in the second in one form or another (and/or in other publications before that).

For instance, the chapter on embedding (15) may be split into two: one on built-in API tools, and another on the extended API developed in the current chapter 15. The extended API was conceived as a way to teach basic embedding, but I'd like to make it more distinct in the next edition.

Note: there are no plans to start the second edition yet (and it will probably be a year or more before we even talk about it!), so please take these only as supplemental examples, not a preview.

  1. More on calling objects (built-in API)
  2. Calling objects with the extended API
  3. More on running code strings (built-in API)
  4. Running code strings with the extended API
  5. Registering code (objects) through an extension

More on calling objects (built-in API)


task (in C)

import module
object = module.klass()
result = object.method(..args..)



file: module.py

class klass:
    def method(self, x, y):
        return "brave %s %s" % (x, y)   # run me from C



file: objects1.c
#include <Python.h>
#include <import.h>
#include <stdio.h>

char *Py_GetProgramName() { return "objects1"; }
#define error(msg) do { printf("%s\n", msg); exit(1); } while (1)

main() {
  char *arg1="sir", *arg2="robin", *cstr;
  PyObject *pmod, *pclass, *pargs, *pinst, *pmeth, *pres;

  /* instance = module.klass() */
  Py_Initialize();
  pmod = PyImport_ImportModule("module");           /* fetch module */
  if (pmod == NULL)
      error("Can't load module");

  pclass = PyObject_GetAttrString(pmod, "klass");   /* fetch module.class */
  Py_DECREF(pmod);
  if (pclass == NULL)
      error("Can't get module.klass");

  pargs = Py_BuildValue("()");
  if (pargs == NULL) {
      Py_DECREF(pclass);
      error("Can't build arguments list");
  }
  pinst = PyEval_CallObject(pclass, pargs);         /* call class() */
  Py_DECREF(pclass);
  Py_DECREF(pargs);
  if (pinst == NULL)
      error("Error calling module.klass()");

  /* result = instance.method(x,y) */
  pmeth  = PyObject_GetAttrString(pinst, "method"); /* fetch bound method */
  Py_DECREF(pinst);
  if (pmeth == NULL)
      error("Can't fetch klass.method");

  pargs = Py_BuildValue("(ss)", arg1, arg2);        /* convert to Python */
  if (pargs == NULL) {
      Py_DECREF(pmeth);
      error("Can't build arguments list");
  }
  pres = PyEval_CallObject(pmeth, pargs);           /* call method(x,y) */
  Py_DECREF(pmeth);
  Py_DECREF(pargs);
  if (pres == NULL)
      error("Error calling klass.method");

  if (!PyArg_Parse(pres, "s", &cstr))               /* convert to C */
     error("Can't convert klass.method result");
  printf("%s\n", cstr);
  Py_DECREF(pres);
}



% objects1 
brave sir robin


Calling objects with the extended API

Same task as above, but with the extended API in chapter 15.


file: objects2.c
#include <stdio.h>
#include "pyembed.h"
char *Py_GetProgramName() { return "objects2"; }

main () {
  int failflag;
  PyObject *pinst;
  char *arg1="sir", *arg2="robin", *cstr;

  failflag = Run_Function("module", "klass", "O", &pinst, "()") || 
             Run_Method(pinst, "method", "s", &cstr, "(ss)", arg1, arg2);

  printf("%s\n", (!failflag) ? cstr : "Can't call objects");
  Py_XDECREF(pinst);
}


More on running code strings (built-in API)

Run "upper('spam') + '!'" in string module's namespace.


file codestring1.c
#include <Python.h>          /* standard API defs  */
#include <import.h>          /* PyImport functions */
#include <graminit.h>        /* parse-mode flags   */
#include <pythonrun.h>       /* PyRun interfaces   */

char *Py_GetProgramName() { return "codestring1"; }
void error(char *msg) { printf("%s\n", msg); exit(1); }

main() {
    char *cstr;
    PyObject *pstr, *pmod, *pdict;               /* with error tests */
    Py_Initialize();

    /* result = string.upper('spam') + '!' */
    pmod = PyImport_ImportModule("string");      /* fetch module */
    if (pmod == NULL)                            /* for name-space */
        error("Can't import module");

    pdict = PyModule_GetDict(pmod);              /* string.__dict__ */
    Py_DECREF(pmod);
    if (pdict == NULL)
        error("Can't get module dict");

    pstr = PyRun_String("upper('spam') + '!'", eval_input, pdict, pdict);
    if (pstr == NULL)
        error("Error while running string");

    /* convert result to C */
    if (!PyArg_Parse(pstr, "s", &cstr))
        error("Bad result type");
    printf("%s\n", cstr);
    Py_DECREF(pstr);        /* free exported objects, not pdict */
}



% codestring1
SPAM!


Running code strings with the extended API

Same task, but using extended API in chapter 15


file: codestring2.c
#include "pyembed.h"
#include <stdio.h>
char *Py_GetProgramName() { return "codestring2"; }

main() {
    char *cstr;
    int err = Run_Codestr(
                    PY_EXPRESSION,                       /* expr or stmt? */
                    "upper('spam') + '!'", "string",     /* code, module  */
                    "s", &cstr);                         /* expr result   */
    printf("%s\n", (!err) ? cstr : "Can't run string");
}


Registering code (objects) through an extension

Discussed abstractly near the end of chapter 15, but here's a concrete example. Note that this is just a way to locate embedded code to run; the code can be objects (as here), code strings, etc.


file: cregister.c
#include <Python.h>
#include <stdlib.h>

/***********************************************/
/* 1) code to route events to Python object    */
/* note that we could run strings here instead */
/***********************************************/

static PyObject *Handler = NULL;     /* keep Python object in C */

void Route_Event(char *label, int count) 
{
    char *cres;
    PyObject *args, *pres;

    /* call Python handler */
    args = Py_BuildValue("(si)", label, count);   /* make arg-list */
    pres = PyEval_CallObject(Handler, args);      /* apply: run a call */
    Py_DECREF(args);                              /* add error checks */

    if (pres != NULL) {
        /* use and decref handler result */
        PyArg_Parse(pres, "s", &cres);
        printf("%s\n", cres);
        Py_DECREF(pres);
    }
}

/*****************************************************/
/* 2) python extension module to register handlers   */
/* python imports this module to set handler objects */
/*****************************************************/

static PyObject *
Register_Handler(PyObject *self, PyObject *args)
{
    /* save Python callable object */
    Py_XDECREF(Handler);                 /* called before? */
    PyArg_Parse(args, "O", &Handler);    /* one argument? */
    Py_XINCREF(Handler);                 /* add a reference */
    Py_INCREF(Py_None);                  /* return 'None': success */
    return Py_None;
}

static PyObject *
Trigger_Event(PyObject *self, PyObject *args)
{
    /* let Python simulate event caught by C */
    static count = 0;
    Route_Event("spam", count++);
    Py_INCREF(Py_None);  
    return Py_None;
}

static struct PyMethodDef cregister_methods[] = {
    {"setHandler",    Register_Handler},       /* name, address */
    {"triggerEvent",  Trigger_Event},  
    {NULL, NULL}
};

void initcregister()                  /* this is called by Python  */
{                                     /* on first "import cregister" */
    (void) Py_InitModule("cregister", cregister_methods);
}



file: register.py
# handle an event, return a result (or None)

def function1(label, count):
    return "%s number %i..." % (label, count)

def function2(label, count):
    return label * count

# register handlers, trigger events 

import cregister
cregister.setHandler(function1)
for i in range(3):
    cregister.triggerEvent()   # simulate events caught by C layer

cregister.setHandler(function2)
for i in range(3):
    cregister.triggerEvent()   # routes these events to function2 



% python register.py
spam number 0...
spam number 1...
spam number 2...
spamspamspam
spamspamspamspam
spamspamspamspamspam


Back to the errata page
Back to my homepage



[Home page] Books Code Blog Python Author Train Find ©M.Lutz