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.
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to