Module missing when embedding?

Garthy garthy_nhtyp at entropicsoftware.com
Thu Dec 12 02:47:24 EST 2013


Hi all,

I've written a minimal set of tests illustrate the issue, which also 
confirms it is independent of threading. Details below. If you build it, 
you might need to tweak the Makefile to run on your system. The script 
"run" will run all eight tests. They pass only when we load everything 
into "__main__", and fail otherwise. I hope this helps highlight what I 
might be doing wrong.

Cheers,
Garth

============= applepy.c:

#include <stdio.h>
#include <Python.h>

#define SCRIPT \
   "import mymodule\n" \
   "\n"\
   "class ClassA:\n" \
   "  def foo(self):\n"\
   "    mymodule.mycall(\"a\")\n"

static int success = 0;
static int tn;

static PyObject *DoMyCall(PyObject *selfr, PyObject *argsr)
{
   //fprintf(stderr, "In DoMyCall\n");
   success = 1;
   Py_INCREF(Py_None);
   return Py_None;
}

static PyMethodDef mycallMethods[] = {
   {"mycall", DoMyCall, METH_VARARGS, "foo"},
   {NULL, NULL, 0, NULL}
};

static struct PyModuleDef mycallModule = {
   PyModuleDef_HEAD_INIT,
   "mymodule", NULL, -1,
   mycallMethods
};

PyMODINIT_FUNC PyInit_mymodule()
{
   return PyModule_Create(&mycallModule);
}

static void check(PyObject *r, const char *msg)
{
   if (!r)
   {
     fprintf(stderr, "FAILED: %s.\n", msg);
     PyErr_PrintEx(0);
     fprintf(stderr, "=== Test %d: Failed.\n", tn);
     exit(1);
   }
}

int main(int argc, char *argv[])
{
   if (argc != 2)
   {
     fprintf(stderr, "Usage: applepy <test>\n");
     exit(1);
   }

   tn = atoi(argv[1]);
   fprintf(stderr, "=== Test %d: Started.\n", tn);
   int test_into_main = tn & 1;
   int test_global_is_module = tn & 2;
   int test_threaded = tn & 4;

   fprintf(stderr, "Load into main:   %s\n", test_into_main ? "y" : "n");
   fprintf(stderr, "Global is module: %s\n", test_global_is_module ? "y" 
: "n");
   fprintf(stderr, "Threaded:         %s\n", test_threaded ? "y" : "n");

   PyGILState_STATE gil;

   PyImport_AppendInittab("mymodule", PyInit_mymodule);
   Py_SetProgramName((wchar_t *)"program");
   Py_InitializeEx(0);

   if (test_threaded)
   {
     PyEval_InitThreads();
     PyThreadState *mtstate = PyThreadState_Get();
     PyEval_ReleaseThread(mtstate);
     gil = PyGILState_Ensure();
   }
   PyObject *main_module = PyImport_AddModule("__main__");
   PyObject *module = PyModule_New("hello");

   if (test_into_main)
     module = main_module;

   PyObject *dg = PyModule_GetDict(test_global_is_module ? module : 
main_module);
   check(dg, "global dict");
   PyObject *dl = PyModule_GetDict(module);
   check(dl, "local dict");
   PyObject *load = PyRun_String(SCRIPT, Py_file_input, dg, dl);
   check(load, "load");

   PyObject *obj = PyObject_CallMethod(module, "ClassA", NULL);
   check(obj, "create object of ClassA");
   PyObject *func = PyObject_GetAttrString(obj, "foo");
   check(func, "obtain foo()");
   PyObject *args = PyTuple_New(0);
   check(args, "args for foo()");
   PyObject *rv = PyObject_CallObject(func, args);
   check(rv, "call foo()");

   if (test_threaded)
     PyGILState_Release(gil);

   if (success)
     fprintf(stderr, "=== Test %d: Success.\n", tn);
   else
     fprintf(stderr, "=== Test %d: FAILED (completed but mycall() not 
called).\n", tn);

   return 0;
}

============= Makefile:

PYINCLUDE=/opt/python/include/python3.3m
PYLIBS=/opt/python/lib

CPPFLAGS=-g -Wall
CC=gcc
LINK=gcc

applepy: applepy.o
	$(LINK) -o applepy applepy.o $(CPPFLAGS) -L$(PYLIBS) -lpython3.3m -ldl 
-lm -lpthread -lutil
	
applepy.o: applepy.c
	$(CC) -c -o applepy.o applepy.c $(CPPFLAGS) -I$(PYINCLUDE)

clean:
	rm -f applepy applepy.o
	
============= run:

#!/bin/sh
make clean
make applepy || exit 1
for t in 0 1 2 3 4 5 6 7; do
   ./applepy $t
done

============= Sample output:

rm -f applepy applepy.o
gcc -c -o applepy.o applepy.c -g -Wall -I/opt/python/include/python3.3m
gcc -o applepy applepy.o -g -Wall -L/opt/python/lib -lpython3.3m -ldl 
-lm -lpthread -lutil
=== Test 0: Started.
Load into main:   n
Global is module: n
Threaded:         n
FAILED: call foo().
=== Test 0: Failed.
=== Test 1: Started.
Load into main:   y
Global is module: n
Threaded:         n
=== Test 1: Success.
=== Test 2: Started.
Load into main:   n
Global is module: y
Threaded:         n
FAILED: load.
=== Test 2: Failed.
=== Test 3: Started.
Load into main:   y
Global is module: y
Threaded:         n
=== Test 3: Success.
=== Test 4: Started.
Load into main:   n
Global is module: n
Threaded:         y
FAILED: call foo().
=== Test 4: Failed.
=== Test 5: Started.
Load into main:   y
Global is module: n
Threaded:         y
=== Test 5: Success.
=== Test 6: Started.
Load into main:   n
Global is module: y
Threaded:         y
FAILED: load.
=== Test 6: Failed.
=== Test 7: Started.
Load into main:   y
Global is module: y
Threaded:         y
=== Test 7: Success.



More information about the Python-list mailing list