[C++-sig] Custom from-python converter (almost working)
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.00, 2.00, 3.00 >>> doh.p((1,2,3)) Traceback (most recent call last): File "", 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()); """ 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 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 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()); } // 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_storage; void* const storage = reinterpret_cast(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()) ; bp::def("f", &f); bp::def("p", &p); convert_py_tuple_to_vec3f(); } ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] Custom from-python converter (almost working)
Hi, >> void >> p(vec3f *v) >> { >> printf("%f, %f, %f\n", v->x, v->y, v->z); >> } > > This is indeed not supported, since it would require "converters with > write-back". Ok, that makes sense. > vec3f const* v > > should work, but > > ve3f* v > > doesn't because the missing const indicates that you want to modify the > pointee in place. Unfortunately I don't control the API. The actual use case I'm working on (the vec3f was just a simplified example) is a class method that takes a non-const pointer, but it does not modify the pointee. The pointee is basically stored in the instance and is used as a data array. As such I wanted a conversion from Python list of tuples to a C++ instance. > For a Python tuple this can definitely not work since tuples are > immutable. > It could in theory work for a Python list, but Boost.Python doesn't > support this. > A few years ago we had extensive discussions about this, but it was too > hard to > implement. I think I can imagine some obstacles :) In SWIG it is possible to simply define an extra class method that takes a PyObject* and perform any conversion you want in that method (although this means having to add that extra method for all cases where the non-const pointer is used). Would something similar work in Boost.Python, e.g. void extra_method(C& self, PyObject *obj) { } class_("C") > > Ralf > > P.S.: I'm using this seasoned file for all "list/tuple/iter <-> small C++ > array" conversions: > > http://cctbx.svn.sourceforge.net/viewvc/cctbx/trunk/scitbx/boost_python/container_conversions.h?view=markup > > Probably, all you need is > > tuple_mapping_fixed_capacity > ___ > Cplusplus-sig mailing list > Cplusplus-sig@python.org > http://mail.python.org/mailman/listinfo/cplusplus-sig > ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] Custom from-python converter (almost working)
Dang, my mailer got in the way and sent this before I finished it ... > Hi, > >>> void >>> p(vec3f *v) >>> { >>> printf("%f, %f, %f\n", v->x, v->y, v->z); >>> } >> >> This is indeed not supported, since it would require "converters with >> write-back". > > Ok, that makes sense. > >> vec3f const* v >> >> should work, but >> >> ve3f* v >> >> doesn't because the missing const indicates that you want to modify the >> pointee in place. > > Unfortunately I don't control the API. The actual use case I'm working on > (the vec3f was just a simplified example) is a class method that takes a > non-const pointer, but it does not modify the pointee. The pointee is > basically stored in the instance and is used as a data array. As such I > wanted a conversion from Python list of tuples to a C++ instance. > >> For a Python tuple this can definitely not work since tuples are >> immutable. >> It could in theory work for a Python list, but Boost.Python doesn't >> support this. >> A few years ago we had extensive discussions about this, but it was too >> hard to >> implement. > > I think I can imagine some obstacles :) > In SWIG it is possible to simply define an extra class method that takes a PyObject* and perform any conversion you want in that method (although this means having to add that extra method for all cases where the non-const pointer is used). Would something similar work in Boost.Python, e.g. class C { public: void set_data(data* d); }; void extra_method(C& self, PyObject *obj) { // if obj is list of tuples, convert to // data* and // call self.set_data(d) } class_("C") .def("set_data", &C::set_data) .def("set_data", &C::extra_method) ; Or will this completely muck up the way Python objects are handled on the interface? >> Ralf >> >> P.S.: I'm using this seasoned file for all "list/tuple/iter <-> small >> C++ >> array" conversions: >> >> http://cctbx.svn.sourceforge.net/viewvc/cctbx/trunk/scitbx/boost_python/container_conversions.h?view=markup >> >> Probably, all you need is >> >> tuple_mapping_fixed_capacity Thanks for the hint, Paul ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
[C++-sig] Getting address of wrapped instance?
Is there are way to get the address of the C++ instance pointed to by a given Boost.Python wrapper object? I don't need a real pointer, the address alone suffices. The use case is to deduce interrelations between C++ objects (think a DAG) from Python. As different Python wrapper objects might reference the same C++ instance I can't use id() or repr() of the Python object. Thanks, Paul ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig