C++ extension problem

P

pythoncurious

Hi,

I'm having a bit of trouble when writing a python extension. I can't
seem to figure out what I did wrong.
I tried to make a minimal example, but it's still quite a bit of
code.
It would be very appreciated if anyone could tell me what I've done
wrong.

First a short description of what I've done. The extension just wraps
a string and the class in it will just hold the string data. A 'get'
method is suppsed to just return the string value.
There's a python part that will call C/C++ functions in the
extension.
I've tried using the same approach SWIG has, so the class in the
extension doesn't really have any methods,
it's all done in methods in the module.

This is what it looks like when I try it out (also tried with
different python version and compiler):
% python
Python 2.4.3 (#1, Aug 1 2006, 16:54:29)
[GCC 3.4.6] on sunos5
Type "help", "copyright", "credits" or "license" for more information.Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "example.py", line 7, in get
def get(self): return _example.get(self._s)
TypeError: argument 1 must be SillyString, not SillyString

Now this is what confuses me: Why does it say that I have the wrong
type when it's the same type as it suggests?

setup.py file:
###########
from distutils.core import setup, Extension
module1 = Extension('_example',
sources = ['_example.cc'])
setup (name = 'example',
ext_modules = [module1])

example.py file:
############
#!/usr/bin/env python
import _example

class StringWrapper(object):
def __init__(self, value):
self._s = _example.new_string(value)
def get(self): return _example.get(self._s)


and finally, the c/c++ file '_example.cc':
(I need to use c++ compiler which means I couldn't use
'staticforward'
and the 'cstring is used instead of 'string.h' )
########################
#include "Python.h"
#include <cstring>

// forward declaration
extern PyTypeObject SillyStringType;

typedef struct {
PyObject_HEAD
char s[21];
} SillyStringObject;

PyObject *
new_string(PyTypeObject *type, PyObject *args)
{
char *value = 0;

if (!PyArg_ParseTuple(args, "s", &value))
return NULL;
SillyStringObject *self = PyObject_NEW(SillyStringObject,
&SillyStringType);
if (self != NULL) {
strncpy(self->s, value, 20);
}
return (PyObject *)self;
}

PyObject *
get(PyTypeObject *type, PyObject *args)
{
SillyStringObject *o;

if (!PyArg_ParseTuple(args, "O!", SillyStringType, &o))
return NULL;
return (PyObject *)PyString_FromString(o->s);
}

PyMethodDef SillyStringMethods[] = {
{"get", (PyCFunction)get, METH_VARARGS,
""
},
{"new_string", (PyCFunction)new_string, METH_VARARGS,
""
},
{NULL, NULL, 0, NULL} /* Sentinel */
};

PyTypeObject SillyStringType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
(char *)"SillyString", /* tp_name */
sizeof(SillyStringObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)0, /* tp_dealloc */
(printfunc)0, /* tp_print */
(getattrfunc)0, /* tp_getattr */
(setattrfunc)0, /* tp_setattr */
(cmpfunc)0, /* tp_compare */
(reprfunc)0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)0, /* tp_hash */
(ternaryfunc)0, /* tp_call */
(reprfunc)0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"SillyString class." /* tp_doc */
};

extern "C"
{
PyMODINIT_FUNC
init_example(void)
{
PyObject* m;
SillyStringType.tp_new = PyType_GenericNew;
if (PyType_Ready(&SillyStringType) < 0)
return;
m = Py_InitModule3("_example", SillyStringMethods,
"_example module.");
Py_INCREF(&SillyStringType);
PyModule_AddObject(m, "SillyStringObject", (PyObject
*)&SillyStringType);
}
}
 
M

Michael Hoffman

I'm having a bit of trouble when writing a python extension. I can't
seem to figure out what I did wrong.
I tried to make a minimal example, but it's still quite a bit of
code.
It would be very appreciated if anyone could tell me what I've done
wrong.

I can't answer your question since I have no experience writing
extension types. I know this is at least partially a learning exercise
for you, but might I suggest that your time might be better spent
learning Boost.Python instead? It is "a C++ library which enables
seamless interoperability between C++ and the Python programming language."

http://www.boost.org/libs/python/doc/
 
?

=?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=

Now this is what confuses me: Why does it say that I have the wrong
type when it's the same type as it suggests?

When referring to the type, you must *always* form the address of the
type structure, including, but not limited to, the line
if (!PyArg_ParseTuple(args, "O!", SillyStringType, &o))

HTH,
Martin
 
P

pythoncurious

I can't answer your question since I have no experience writingextensiontypes. I know this is at least partially a learning exercise
for you, but might I suggest that your time might be better spent
learning Boost.Python instead? It is "aC++library which enables
seamless interoperability betweenC++and the Python programming language."

http://www.boost.org/libs/python/doc/

Yes, that's good advice. Unfortunately, boost has not been working
very well with the tools I'm forced to use (Sun studio). Otherwise I
would have started there.

/Matt
 
P

pythoncurious

When referring to the type, you must *always* form the address of the
type structure, including, but not limited to, the line


HTH,
Martin


Yes, that did help. Thanks.
I assumed that the compiler would warn me about that kind of problem,
but I know better know. :)
Still, the error message is somewhat confusing.
 
?

=?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=

I assumed that the compiler would warn me about that kind of problem,
but I know better know. :)

It's a variable argument list (...). The compiler is not supposed to
give any warnings for that (although I do have a gcc patch that enables
warnings for PyArg_ParseTuple).
Still, the error message is somewhat confusing.

Passing incorrect parameters to variable argument lists causes undefined
behavior. Anything can happen under undefined behavior, including
mysterious error messages, erasure of your hard disk, and reversal of
the global warming.

To understand why the specific error message is printed, you would have
to debug what values are passed on the stack at what point.

Regards,
Martin
 

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

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top