[C++-sig] Custom from-python converter (almost working)
pyplusplus at assumetheposition.nl
pyplusplus at assumetheposition.nl
Fri Dec 5 13:39:23 CET 2008
I'm trying to add some custom from-python converters to my bindings (see
code at the end of the mail).
These basically should convert Python 3-tuples of floats to a C++ vec3f
instance. I can't seem to find reference docs on classes related to
conversion, e.g. boost::python::converter::registry, so after some
googling and experimenting I think the code at the end of this mail is a
pretty clean implementation of what I want, and it almost fully works:
Python 2.4.3 (#1, Jun 13 2006, 16:41:18)
[GCC 4.0.2 20051125 (Red Hat 4.0.2-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import doh
>>> doh.f((1,2,3))
1.000000, 2.000000, 3.000000
>>> doh.p((1,2,3))
Traceback (most recent call last):
File "<stdin>", line 1, in ?
Boost.Python.ArgumentError: Python argument types in
doh.p(tuple)
did not match C++ signature:
p(vec3f*)
>>>
So the implicit conversion to a pointer to a vec3f doesn't work. After
some more googling I came across the thread [1], which seemed to suggest
that there is another way of registering a converter, i.e.
"""
Don't try to convert to pointers; there are no pointers in
Boost.Python; only lvalues and rvalues ;-)
void* extract_foo(PyObject* op)
{
return FooObject_ptr(op);
}
boost::python::converter::registry::insert(
&extractor_foo, boost::python::type_id<FOO>());
"""
In the February 2002 progress report [2] (does that reflect the current
situation in 1.37 w.r.t. to/from-python converters, b.t.w?) it says:
"""There are basically two categories of from_python conversions:
those which lvalues stored within or held by the Python object
(essentially extractions), like what happens when an instance of a
C++ class exposed with class_ is used as the target of a wrapped
member function), and those in which a new rvalue gets created, as
when a Python Float is converted to a C++ complex<double> or a Python
tuple is converted to a C++ std::vector<>"""
It seems my non-working case of conversion to a vec3f* is of the latter
category.
Can I assume that the two different ways of registering a converter
reflect these categories?
If so, then I don't see a way to make this work, as I need actual
conversion, not extraction, i.e. I need to create a new object that
doesn't exist yet. Or should I register my converter in both ways to the
registry?
Any help is greatly appreciated,
Regards,
Paul
[1] http://mail.python.org/pipermail/cplusplus-sig/2006-November/011269.html
[2] http://www.boost.org/doc/libs/1_37_0/libs/python/doc/v2/feb2002.html
#include <boost/python.hpp>
namespace bp = boost::python;
struct vec3f
{
vec3f(): x(0), y(0), z(0) {}
vec3f(float xx, float yy, float zz)
{
x = xx; y = yy; z = zz;
}
float x, y, z;
};
struct convert_py_tuple_to_vec3f
{
convert_py_tuple_to_vec3f()
{
bp::converter::registry::push_back(
&convertible,
&construct,
bp::type_id<vec3f>());
}
// Check if given Python object is convertible to a vec3f.
// If so, return obj, otherwise return 0
static void* convertible(PyObject* obj)
{
if (PyTuple_Check(obj))
return obj;
return 0;
}
// Construct a vec3f object from the given Python object, and
// store it in the stage1 (?) data.
static void construct(PyObject* obj,
bp::converter::rvalue_from_python_stage1_data* data)
{
// Fill in values
float x, y, z;
if (!PyArg_ParseTuple(obj, "fff", &x, &y, &z))
{
// Raise exception, error will have been set by PyArg_ParseTuple
boost::python::throw_error_already_set();
}
typedef bp::converter::rvalue_from_python_storage<vec3f>
vec3f_storage;
void* const storage =
reinterpret_cast<vec3f_storage*>(data)->storage.bytes;
vec3f *v = new (storage) vec3f(x, y, z);
data->convertible = storage;
}
};
void
f(vec3f v)
{
printf("%f, %f, %f\n", v.x, v.y, v.z);
}
void
p(vec3f *v)
{
printf("%f, %f, %f\n", v->x, v->y, v->z);
}
BOOST_PYTHON_MODULE(doh)
{
bp::class_< vec3f >("vec3f")
.def(bp::init<float, float, float>())
;
bp::def("f", &f);
bp::def("p", &p);
convert_py_tuple_to_vec3f();
}
More information about the Cplusplus-sig
mailing list