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..)


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() */
  pmod = PyImport_ImportModule("module");           /* fetch module */
  if (pmod == NULL)
      error("Can't load module");

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

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

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

  pargs = Py_BuildValue("(ss)", arg1, arg2);        /* convert to Python */
  if (pargs == NULL) {
      error("Can't build arguments list");
  pres = PyEval_CallObject(pmeth, pargs);           /* call method(x,y) */
  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);

% 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");

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 */

    /* 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__ */
    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

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);

/* 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++);
    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);

# 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
for i in range(3):
    cregister.triggerEvent()   # simulate events caught by C layer

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

% python
spam number 0...
spam number 1...
spam number 2...

Back to the errata page
Back to my homepage

[Home page] Books Code Blog Python Author Training Search ©M.Lutz