[Pyrex] Pybsddb question

tarkawebfoot at charter.net tarkawebfoot at charter.net
Wed Apr 12 22:44:02 CEST 2006


Hi all,

Been using Pyrex for a few weeks now and am pretty impressed. It provides a great blend of low level access and Python's ease of use.

I'm currently trying to use Pyrex to interface to pybsddb. I need to replace the B-Tree compare function for the dbs I create, so I asked on the pybsddb mailing list how to do that. The following was the response:

>Something like this (untested but it should give you the idea)
>
>class MyBtCompare:
>    def __init__(self, reverse=False):
>	self.reverse=reverse
>    def __call__(self, a, b):
>	if self.reverse:
>	    return cmp(b, a)
>	else
>	    return cmp(a, b)
>
>normaldb = db.DB(...)
>normaldb.set_bt_compare(MyBtCompare())
>backwarddb = db.DB(...)
>backwarddb.set_bt_compare(MyBtCompare(reverse=True))
>
>You should really make that callable comparison "function" class
>faster by dynamically defining the __call__ method in the class at
>__init__ time rather than having it check self.reverse on each
>comparison.
>
>It doesn't have to be a class, just define a function as needed to
>pass to set_bt_compare (better given the above trivial example):
>
>normaldb.set_bt_compare(lambda a, b: cmp(a,b))
>reversedb.set_bt_compare(lambda a, b: cmp(b,a))

Now since this is a time critical function, I'd like the class to be a Pyrex extension class. So I've got the following:

_metadata.pxd:
from _engine cimport c_engine, pcolinfo, oetl_compare, oetl_compare_ab

cdef class c_metadata:
    cdef pcolinfo keylist, ordlist, collist
    cdef int keylen, ordlen, collen, col_datalen

cdef class row_comparison:
    cdef c_metadata meta
    cdef int purpose, lstlen, lstdatalen
    cdef pcolinfo lst
    cdef c_engine parent
    cdef char *name
    cdef void fire_error(self, int *a, int *b)

_metadata.pyx:
cdef class row_comparison:
    def __new__(...):
        #build the self.lst object with column info to compare
        #also set self.lstlen to number of columns
.
.
.
    def __call__(self, DBT *a, DBT *b):
        cdef int i, res
        res = 0
        for i from 0 <= i < self.lstlen:
            res = oetl_compare(&self.lst[i], a[0].data, b[0].data)
            if res:
                if res == ERROR:
                    self.parent.fire_error(a[0].data, b[0].data)
                    res = 0
                break
        return res

Compiling with:
python \python24\scripts\pyrexc -I \python24\lib\site-packages\py_decNumber _metadata.pyx
gives:
C:\Python24\Lib\site-packages\oetl\lib\_metadata.pyx:61:23: Cannot convert Python object argument to type 'DBT (*)'

I guess this isn't suprising since the __call__ function is called by Python. The parameters are going to be passed as Python objects. So the question is, how do I convert them to DBT objects? Just assigning them to cdef DBT objects doesn't work. Do I need to use the Python API to get a pointer to the raw data and typecast it to DBT *?

Thanx for any input

Brian



More information about the Pyrex mailing list