Mailing List Archive

Python/C API and setattr
Hi

I'm building an extention type for Python in C using NT, MSVC++.
It's built as a dll to link in at Runtime.

I'm doing this for practice so the type is quite simple, it's
a CounterType, with an attribute called value (an int)
and the simple operations/methods inc() and dec().

I've looked pretty much at Mark Lutz's example StackType from
Programming Python and I think I'm doing the same, but I've added
setattrfunc to be able to directly manipulate value as c.value = 23
and when I use it something goes wrong.
(inc() and dec() work fine)

Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> from CounterType import *
>>> c = Counter()
>>> c.value = 23
Traceback (innermost last):
File "<stdin>", line 1, in ?
SystemError: error return without exception set
>>> c.value
23
>>>
The value is set properly but I can't figure out the system error, it
seems to be something wrong with my setattrfunc.

static void counter_setattr
(counterobject *self, char *name, PyObject *v)
{
if(strcmp(name, "value") == 0)
{
self->value = (int)PyInt_AsLong(v);
}
}

But what would that be??
I have a hard time finding examples of how to do setattr so
any pointers would be great. Also if someone understands this error,
please post an answer.

My counterobject is this:
typedef struct
{
PyObject_HEAD
int value;
} counterobject;

Thanks
-- Thomas S. Strinnhed, thstr@serop.abb.se
Python/C API and setattr [ In reply to ]
Hi,

Thank you for a fast response.

Moshe Zadka wrote:
[my original message]
> You should return Py_None from a function. Every function called by
> Python has the following prototype:
> PyObject *f(PyObject *self, PyObject *args)
> (Actually, this is a lie. But a small white Knuth one)
> --
> Moshe Zadka <mzadka@geocities.com>.
> QOTD: My own exit is more likely to be horizontal then perpendicular.

Well I thought so too, but actually it must be something else,
cause it doesn't go away!!

static PyObject *counter_setattr(counterobject *self, char *name,
PyObject *v)
{
if(strcmp(name, "value") == 0)
{
self->value = (int)PyInt_AsLong(v);
Py_INCREF(Py_None);
return Py_None;
}
Py_INCREF(Py_None);
return Py_None;
}
Just doesn't help!!

Could there be something about this line;
self->value = (int)PyInt_AsLong(v);
(self->value is an int and v is PyObject*)

And about the prototype:
The few examples I've found about setattr are just like I've used it:
compare my prototype
static void counter_setattr(counterobject *self, char *name, PyObject
*v)
with this one from Objects\xxobject.c
static int xx_setattr(xxobject *xp, char *name, PyObject *v)

I think my main question would be:
Where to find detailed documentation/information about this?
and subquestion asked standing on my bare knees (?? :-)
What's happening here?? (Here beeing my code)

Admit it's tricky??

Many Thanks
-- Thomas S. Strinnhed, thstr@serop.abb.se
Python/C API and setattr [ In reply to ]
Hi,

Thanks, but unfortunately it doesn't seem to be the problem.
Please take a look at the response posted to myself.

Thank you

-- Thomas S. Strinnhed, thstr@serop.abb.se

Gordon McMillan wrote:
>
> Thomas S. Strinnhed writes:
> >
> > I'm building an extention type for Python in C using NT, MSVC++.
>
> > I've looked pretty much at Mark Lutz's example StackType from
> > Programming Python and I think I'm doing the same, but I've added
> > setattrfunc to be able to directly manipulate value as c.value = 23
> > and when I use it something goes wrong. (inc() and dec() work fine)
> >
> > Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on
> > win32 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
> > >>> from CounterType import *
> > >>> c = Counter()
> > >>> c.value = 23
> > Traceback (innermost last):
> > File "<stdin>", line 1, in ?
> > SystemError: error return without exception set
>
> You returned NULL (or 0, or the compiler generated a return of NULL
> because you didn't state anything) from your C code. That signifies
> an error to Python, which expects you to have set an error string.
>
> Return (an increfed) None and Python will be happy.
>
> > >>> c.value
> > 23
> > >>>
> > The value is set properly but I can't figure out the system error,
> > it seems to be something wrong with my setattrfunc.
> >
> > static void counter_setattr
> > (counterobject *self, char *name, PyObject *v)
> > {
> > if(strcmp(name, "value") == 0)
> > {
> > self->value = (int)PyInt_AsLong(v);
> > }
> > }
> >
> > But what would that be??
> > I have a hard time finding examples of how to do setattr so
> > any pointers would be great. Also if someone understands this error,
> > please post an answer.
> >
> > My counterobject is this:
> > typedef struct
> > {
> > PyObject_HEAD
> > int value;
> > } counterobject;
> >
> > Thanks
> > -- Thomas S. Strinnhed, thstr@serop.abb.se
> >
> > --
> > http://www.python.org/mailman/listinfo/python-list
>
> - Gordon
Python/C API and setattr [ In reply to ]
Thomas S. Strinnhed writes:
>
> I'm building an extention type for Python in C using NT, MSVC++.

> I've looked pretty much at Mark Lutz's example StackType from
> Programming Python and I think I'm doing the same, but I've added
> setattrfunc to be able to directly manipulate value as c.value = 23
> and when I use it something goes wrong. (inc() and dec() work fine)
>
> Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on
> win32 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
> >>> from CounterType import *
> >>> c = Counter()
> >>> c.value = 23
> Traceback (innermost last):
> File "<stdin>", line 1, in ?
> SystemError: error return without exception set

You returned NULL (or 0, or the compiler generated a return of NULL
because you didn't state anything) from your C code. That signifies
an error to Python, which expects you to have set an error string.

Return (an increfed) None and Python will be happy.

> >>> c.value
> 23
> >>>
> The value is set properly but I can't figure out the system error,
> it seems to be something wrong with my setattrfunc.
>
> static void counter_setattr
> (counterobject *self, char *name, PyObject *v)
> {
> if(strcmp(name, "value") == 0)
> {
> self->value = (int)PyInt_AsLong(v);
> }
> }
>
> But what would that be??
> I have a hard time finding examples of how to do setattr so
> any pointers would be great. Also if someone understands this error,
> please post an answer.
>
> My counterobject is this:
> typedef struct
> {
> PyObject_HEAD
> int value;
> } counterobject;
>
> Thanks
> -- Thomas S. Strinnhed, thstr@serop.abb.se
>
> --
> http://www.python.org/mailman/listinfo/python-list

- Gordon
Python/C API and setattr [ In reply to ]
Hi again

Gee, you guys are so fast :-)

Moshe Zadka wrote:
> > Could there be something about this line;
> > self->value = (int)PyInt_AsLong(v);
> > (self->value is an int and v is PyObject*)
>
> Err......defensive programing says: check it is a Python int before
> converting (there's a PyInt_Check() function somewhere -- check with
> the docs).
Ok, you're right about that one, but PyInt_AsLong() *does* deliver and
int and the value *is* correct.

> Are you sure there shouldn't be a Py_ParseTuple(..) function somewhere
> too?
No I'm not, but my Objects\xxobject.c inspiration doesn't use one
so I thought I'd get away without one.

> What exactly "doesn't fly?" (i.e., what error do you get?)

>>> c.value = 23
Traceback (innermost last):
File "<stdin>", line 1, in ?
SystemError: error return without exception set
>>> c.value
23

This is the error I get and according to Gordon McMillan this
is (just like you pointed out) related to the fact that C
returns NULL to Python. But the value is, as you can see
from the printout, just what I wanted.

And I now always return a Py_None (carefully incref'd),
but the error remains :-/

Many Thanks
-- Thomas S. Strinnhed, thstr@serop.abb.se
Python/C API and setattr [ In reply to ]
Thomas S. Strinnhed <thstr@serop.abb.se> wrote:
: Hi

: I'm building an extention type for Python in C using NT, MSVC++.
: It's built as a dll to link in at Runtime.

: I'm doing this for practice so the type is quite simple, it's
: a CounterType, with an attribute called value (an int)
: and the simple operations/methods inc() and dec().

: I've looked pretty much at Mark Lutz's example StackType from
: Programming Python and I think I'm doing the same, but I've added
: setattrfunc to be able to directly manipulate value as c.value = 23
: and when I use it something goes wrong.
: (inc() and dec() work fine)

: Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32
: Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
:>>> from CounterType import *
:>>> c = Counter()
:>>> c.value = 23
: Traceback (innermost last):
: File "<stdin>", line 1, in ?
: SystemError: error return without exception set
:>>> c.value
: 23
:>>>
: The value is set properly but I can't figure out the system error, it
: seems to be something wrong with my setattrfunc.

: static void counter_setattr
: (counterobject *self, char *name, PyObject *v)
: {
: if(strcmp(name, "value") == 0)
: {
: self->value = (int)PyInt_AsLong(v);
: }
: }

: But what would that be??
: I have a hard time finding examples of how to do setattr so
: any pointers would be great. Also if someone understands this error,
: please post an answer.

: My counterobject is this:
: typedef struct
: {
: PyObject_HEAD
: int value;
: } counterobject;

: Thanks
: -- Thomas S. Strinnhed, thstr@serop.abb.se

Thomas, the prototype for functions in the setattr slot of a Python type
is:
typedef int (*setattrfunc)(PyObject *, char *, PyObject *);

Your counter_setattr function should return an int, true (0) for
success, false (-1) for error. I believe the source code and Mark's
book (somewhere in Ch 15? but I don't have the book with me) are about
the only places this is documented, and it is very obscure.

"This looks like a job for Documentation Man!"

-Arcege
Python/C API and setattr [ In reply to ]
Hi

Michael P. Reilly wrote:
> [quoted my message]
> Thomas, the prototype for functions in the setattr slot of a Python type
> is:
> typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
>
> Your counter_setattr function should return an int, true (0) for
> success, false (-1) for error. I believe the source code and Mark's
> book (somewhere in Ch 15? but I don't have the book with me) are about
> the only places this is documented, and it is very obscure.
>
> "This looks like a job for Documentation Man!"
>
> -Arcege

Thanks everyone, I finally managed to get it all to work.
Embarrassing enough, the answer was in the Programming Python-book all
the time (in ch.14 at p.561), but as said below: "it is very obscure".

Actually we were all almost right, the prototype in the book is
static int mytype_setattr(mytype *x, char *name, PyObject *value);
so the problem was me trying to return nothing at all, None, the
int value assigned and so on.

I guess this answers a question from an earlier thread:
"Programming Python" still worthwhile?
with a big: "Yes, very much so!" (as goes for c.l.py :-)

If anyone is interrested I've pasted the code to my function
as it turned out below.

Many Thanks
-- Thomas S. Strinnhed. thstr@serop.abb.se

static int counter_setattr(counterobject *self, char *name, PyObject *v)
{
if(strcmp(name, "value") == 0)
{
self->value = (int)PyInt_AsLong(v);
return 0;
}
return -1;
}