[C++-sig] from_python (repost)

David Abrahams david.abrahams at rcn.com
Thu Jul 18 17:11:57 CEST 2002


From: "Peter Bienstman" <pbienst at MIT.EDU>

> I'm trying to upgrade a piece of code from a prehistoric version of BPL
> V2 to the current CVS version:
>
> namespace boost { namespace python { namespace converter { namespace {

Hmm, you probably shouldn't have been adding anything to the boost
namespace...

> struct cVector_from_python
> {
>   static unaryfunc* get_slot(PyObject* o)
>   {
>     return &py_object_identity;
>   }
>
>   static cVector extract(PyObject* o)
>   {
>     PyArrayObject* a
>       = (PyArrayObject*) PyArray_Cast((PyArrayObject*)o,
> PyArray_CDOUBLE);
>
>     if ( (a->nd != 1) || (a->dimensions[0] != int(global.N)) )
>     {
>       PyErr_SetString(PyExc_ValueError, "array has wrong dimensions.");
>       throw boost::python::argument_error();
>     }
>
>     return cVector((Complex*) a->data,global.N,
>                    blitz::neverDeleteData,fortranArray);
>   }
> };


This looks like an attempt to use the internal slot_rvalue_from_python
converter generator. That's usually not worth it for types where the
get_slot function returns the identity function. That means you're
basically willing to accept anything for overload resolution.

I suggest you back up and look at this thread:
http://aspn.activestate.com/ASPN/Mail/Message/1227504

The basic challenge of building a new rvalue from_python converter is to
come up with two functions with the following signatures:

// Used in overload resolution. A return value of 0 indicates that
conversion
// failed and overload resolution should proceed with other functions and
argument
// converters.
void* convertible(PyObject* source);

// Used once overload resolution has selected this converter; builds the
C++ value.
// On entry, data.convertible will be the result of calling convertible(),
above.
// This function is expected to build a new value of the C++ target type T
in
// ((rvalue_from_python_data<T>*)data)->storage.bytes using placement new.
If
// successful, it should set data->convertible to point at the
newly-constructed
// object.
void constructor(PyObject* source, rvalue_from_python_stage1_data* data);

These need to be registered with:

    python::converter::registry::insert(convertible, constructor,
type_id<T>())

Also see the comment at the top of
boost/python/converter/rvalue_from_python_data.hpp for more details.

Your convertible function should be checking that the source object can be
converted to a cVector(preferably without creating a new Python object),
and your construct function should build it.

Note that used as an argument converter for functions of more than 1
argument, the fact that convertible returns non-zero doesn't mean that
construct() will be called, since overload resolution can still fail for
other arguments. Thus, convertible() cannot allocate memory to be reclaimed
by construct(). Note also that your code leaks a PyArrayObject.

> After reading through the mailing lists and the docs
> (boost/libs/python/doc/v2/from_python.html) I tried something like this:

That part of the doc is obsolete and will be fixed up soon. That header is
called arg_from_python.hpp now, but it shouldn't even be exposed to users
IMO since it's not the right place for user customizations nor is it the
best mechanism to use for extraction. A specialization of arg_from_python
could work for argument conversions if you can guarantee that all needed
wrapping code "sees" your specialization, but it won't work for, e.g.,
extract<>, or call<>(...), which use a different set of templates to
convert results from python.

> Or should I wait a couple of days until extractors are implemented and
> the dust has settled?

I don't think extractors can help you here, since they *use* the registered
converters which I discussed above.

HTH,
Dave








More information about the Cplusplus-sig mailing list