Problems with dict and C API

M

Matjaz

Dear all,

I have trouble with creating objects with Python C API,
subclassed from dict type. What I am trying to do is to
subclass a dict class (in Python) and create its instance
in a Python extension (C API).

When I subclass from the (obsolete) UserDict class it works.
When I subclass from the (recommended) dict class,
the program fails with the following error:

SystemError: classobject.c:518: bad argument to internal function

Below is the complete code, both C and Python, as well as a simple
example.

Please advise what am I missing.

Best regards,

Matjaz.

/* ------------------------------------------------------------------ */
/* example.c */
/* ------------------------------------------------------------------ */

#include "Python.h"

PyObject* find_class(const char *module_name, const char *global_name)
{
PyObject *global = NULL;
PyObject *module = NULL;
PyObject *err = NULL;
PyObject *py_module_name = PyString_FromString( module_name ) ;
PyObject *py_global_name = PyString_FromString( global_name ) ;

int module_imported = 0;

module = PySys_GetObject("modules");
if (module == NULL) return NULL;

module = PyDict_GetItem(module, py_module_name);
if (module == NULL) {
printf("Importing %s\n", module_name);
module = PyImport_Import(py_module_name);
if ((err = PyErr_Occurred()))
if (err == PyExc_ImportError)
PyErr_Clear();
else
module_imported = 1;
}
if (module) {
global = PyObject_GetAttr(module, py_global_name);
if ((err = PyErr_Occurred()))
if (err == PyExc_AttributeError)
PyErr_Clear();
if (module_imported)
Py_DECREF(module);
}

return global;
}




static PyObject *
ex_test(PyObject *self, PyObject *args)
{ PyObject *cl, *ob;


char *module, *name;
if (!PyArg_ParseTuple(args, "ss", &module, &name))
return NULL;

printf("Testing '%s' from '%s'...\n", name, module);

cl = find_class(module,name);
ob = PyInstance_New( cl, NULL, NULL);

return ob;

}

static PyMethodDef example_methods[] = {
{"test", ex_test, METH_VARARGS , "test() doc string"},
{NULL, NULL}
};

void
initexample(void)
{
Py_InitModule("example", example_methods);
}

# ------------------------------------------------------------------
# testcl.py
# ------------------------------------------------------------------

from UserDict import UserDict

class PD(dict):
def __init__(self):
dict.__init__(self)


class UD(UserDict):
def __init__(self):
UserDict.__init__(self)


# ------------------------------------------------------------------
# test.py
# ------------------------------------------------------------------

import testcl
import example

x = example.test("testcl","UD") # This works
print x

y = example.test("testcl","PD") # This fails
print y

# SystemError: classobject.c:518: bad argument to internal function
 
A

Alex Martelli

Matjaz said:
Dear all,

I have trouble with creating objects with Python C API,
subclassed from dict type. What I am trying to do is to
subclass a dict class (in Python) and create its instance
in a Python extension (C API).

PyIntance_New wants specifically an old-style class as its first
argument, and you're not giving that in the latter case (a subclass of
dict is intrinsically new-style) so it's diagnosing that and raising the
exception you see. Just use PyObject_Call and you should be fine. More
generally, use abstract-object-layer API calls unless you've got very
specific reasons to use something lower-level (concrete layer) -- 90%+
of the time you'll be far happied with the AOL calls.

BTW, to get sys.modules, I suggest you use PyImport_GetModuleDict()
rather than PySys_GetObject("modules") -- it's slightly more direct.


Alex
 
M

Matjaz

Alex,

thank you for this valuable piece of information. I will
indeed try to use mapping protocol as much as possible.
However, I am curious of the following: were the
functions for setting/getting items (should be PyMapping_SetItem
and PyMapping_GetItem, like that for object and dictionaries)
left out on purpose, because there exist
only "string" versions PyMapping_SetItemString and
PyMapping_GetItemString?

Matjaz.
 
A

Alex Martelli

Matjaz said:
Alex,

thank you for this valuable piece of information. I will
indeed try to use mapping protocol as much as possible.
However, I am curious of the following: were the
functions for setting/getting items (should be PyMapping_SetItem
and PyMapping_GetItem, like that for object and dictionaries)
left out on purpose, because there exist
only "string" versions PyMapping_SetItemString and
PyMapping_GetItemString?

No, you're just still looking at a too-specific level -- think abstract!

PyObject_SetItem and PyObject_GetItem are the API functions you're
looking for; there is no PyMapping_SetItem because it would just be a
total duplicate of PyObject_SetItem, just about. The ...String
convenience functions are there because using a string key is such a
frequent task on mappings specifically, not on objects in general. But
indexing _IS_ frequent on objects in general, so it's supported at that
level.


Alex
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,992
Messages
2,570,220
Members
46,805
Latest member
ClydeHeld1

Latest Threads

Top