[Pyrex] how do I "dispatch" calls to different C functions...?
Alex Martelli
aleaxit at yahoo.com
Fri Jul 25 16:40:01 CEST 2003
I'm trying to wrap the mp3lame library, and it has a *LOT* of getter/setter
functions which I'd like to wrap into getattr/setattr special methods for use
from Python. I've been trying various approaches but I keep running into
various different errors, so I thought I'd ask for guidance.
Here's an example of something that doesn't work:
cdef extern from "lame/lame.h":
ctypedef struct lame_global_flags
ctypedef lame_global_flags* lame_t
lame_t lame_init()
int lame_set_num_samples(lame_t, int)
int lame_get_num_samples(lame_t)
/* snip: a zillion more lame_set_... and lame_get... declarations */
int lame_close(lame_t)
class lameError(Exception): pass
Lamer_int_attribs = {
'numSamples': (<long>lame_get_num_samples, <long>lame_set_num_samples),
'inSampleRate': (<long>lame_get_in_samplerate, <long>lame_set_in_samplerate),
'numChannels': (<long>lame_get_num_channels, <long>lame_set_num_channels),
/* snip: a zillion more dict entries in exactly the same vein as the above */
}
ctypedef int (*lame_int_getter)(lame_global_flags *)
ctypedef int (*lame_int_setter)(lame_global_flags *, int)
cdef object Lamer_getter(lame_t flags, char* name):
if name not in Lamer_int_attribs: raise AttributeError
getter = Lamer_int_attribs[name][0]
return (<lame_int_getter>getter)(flags)
cdef object Lamer_setter(lame_t flags, char* name, object value):
if name not in Lamer_int_attribs: raise AttributeError
setter = Lamer_int_attribs[name][1]
if (<lame_int_setter>setter)(flags, value):
raise lameError(name)
cdef class Lamer:
cdef lame_t flags
def __new__(self):
self.flags = lame_init()
def __dealloc__(self):
lame_close(self.flags)
def __getattr__(self, name):
return Lamer_getter(self.flags, name)
def __setattr__(self, name, value):
return Lamer_setter(self.flags, name, value)
This specific attempt fails during C compilation (on Linux, gcc 3.2.2)
with sundry errors in lame.c about "cast specifies function type". Without
the <long> casts (and the casts back to lame_int_getter etc), I don't
even get to the C compilation -- pyrexc croaks with a zillion errs of
"""
Cannot convert 'int ((lame_global_flags (*),int ))' to Python object
"""
The problems seems to boil down to: how do I wrap pointers to
functions into Python objects in such a way that Pyrex can perform
a call through the pointer to function when it gets the object back.
To a lesser extent, I've met similar problems with other kinds of
"opaque pointers" -- I'd like to wrap them just in order to get them
to Python and back (or into Python structure, mostly dictionaries,
and back out of them from within Pyrex) but I think I do not fully
understand how to do that with Pyrex. E.g., with respect to the
"lame_t" above, I've finessed that by making it a cdef member of
the "cdef class Lamer" -- but while often handy it seems to me
that this approach can't be fully general. So what's the pyrex
way to wrap/unwrap opaque pointers to data and functions?
Thanks,
Alex
More information about the Pyrex
mailing list