[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