[C++-sig] Custom from-python converter (almost working)

2008-12-05 Thread pyplusplus
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)

2008-12-08 Thread pyplusplus
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)

2008-12-08 Thread pyplusplus
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?

2008-12-08 Thread pyplusplus
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