Exposing c++ classes with static arrays using Boost.Python and py++
While running py++ on a class with a static array inside it, py++ generates Boost.Python bindings using a derived class for the original C++ class. Let me illustrate with the help of the following example: class AttributesTest { public: int staticIntArray[10]; }; Notice this class has an array inside it Running py++ generates the following code, with a wrapper class that derives from the AttributesTest class. struct AttributesTest_wrapper : AttributesTest, bp::wrapper< AttributesTest
{
AttributesTest_wrapper(AttributesTest const & arg ) : AttributesTest( arg ) , bp::wrapper< AttributesTest >() {} AttributesTest_wrapper( ) : AttributesTest( ) , bp::wrapper< AttributesTest >() {} pyplusplus::containers::static_sized::array_1_t< int, 10 > pyplusplus_staticIntArray_wrapper(){ return pyplusplus::containers::static_sized::array_1_t< int, 10 >( staticIntArray ); } }; and BOOST_PYTHON_MODULE(PYPP_YodaPacketCommon){ if( true ){ typedef bp::class_< AttributesTest_wrapper > AttributesTest_exposer_t; AttributesTest_exposer_t AttributesTest_exposer = AttributesTest_exposer_t( "AttributesTest" ); bp::scope AttributesTest_scope( AttributesTest_exposer ); AttributesTest_exposer.def( bp::init<
()[bp::default_call_policies()] );
pyplusplus::containers::static_sized::register_array_1< int, 10, bp::default_call_policies >( "__array_1_int_10" ); AttributesTest_exposer.add_property( "staticIntArray" , bp::make_function( (pyplusplus::containers::static_sized::array_1_t< int, 10 > ( AttributesTest_wrapper::* )( ) )(&AttributesTest_wrapper::pyplusplus_staticIntArray_wrapper) , bp::with_custodian_and_ward_postcall< 0, 1, bp::default_call_policies >() ) );; Note that it maps the python name "AttributesTest" to the derived class AttributesTest_wrapper. Why not just keep it simple and rather than creating a derived class just map the variable "staticIntArray" via a global method, such as: .add_property( "staticIntArray" , bp::make_function( (&::someglobal_staticIntArray_wrapper) , bp::with_custodian_and_ward_postcall< 0, 1, bp::default_call_policies >() ) );; and define the someglobal_staticIntArray_wrapper method as: pyplusplus::containers::static_sized::array_1_t< int, 10 > someglobal_staticIntArray_wrapper(){ return pyplusplus::containers::static_sized::array_1_t< int, 10 >( staticIntArray ); } Is there any drawback with just mapping the array variable to a global method rather than mapping the whole class. thanks - Abhi
On 5/4/06, Abhi <abhi@qualcomm.com> wrote:
While running py++ on a class with a static array inside it, py++ generates Boost.Python bindings using a derived class for the original C++ class.
pyplusplus::containers::static_sized::array_1_t< int, 10 > pyplusplus_staticIntArray_wrapper(){ return pyplusplus::containers::static_sized::array_1_t< int, 10 >( staticIntArray ); }
I should make this function static and to take an instance as the first argument. Then generated code will work for derived classes too. I will fix it in few days
Is there any drawback with just mapping the array variable to a global method rather than mapping the whole class.
Obviously, the generated code represents my understanding, preferences and personal taste of how it should be done. In this specific case py++ should mangle into function name: namespace name, class name, variable name. Or it should create some scope/namespace where IntArray will be unique name. Such scope already exists - class wrapper, so I reused it. Also the approach I choose, simplifies py++ code ( == less bugs ). I will re-think my approach, if you will give 3 good reasons, why it should be changed. :-)
thanks - Abhi
-- Roman Yakovenko C++ Python language binding http://www.language-binding.net/
Hi Roman, A similar question was posted sometime ago: ------------------------------------------------------------------------ ---- While running Py++ on a class which contains a static array inside it, Py++ generates Boost.Python bindings using a derived class for the original C++ class. Let me illustrate with the help of the following example: ------------------------------------------------------------------------ ---- class AttributesTest { public: int staticIntArray[10]; }; Notice this class has an array inside it Running Py++ generates the following code, with a wrapper class that derives from the AttributesTest class. struct AttributesTest_wrapper : AttributesTest, bp::wrapper< AttributesTest> { AttributesTest_wrapper(AttributesTest const & arg ) : AttributesTest( arg ) , bp::wrapper< AttributesTest >() {} AttributesTest_wrapper( ) : AttributesTest( ) , bp::wrapper< AttributesTest >() {} pyplusplus::containers::static_sized::array_1_t< int, 10 > pyplusplus_staticIntArray_wrapper(){ return pyplusplus::containers::static_sized::array_1_t< int, 10
( staticIntArray ); }
}; and BOOST_PYTHON_MODULE(PYPP_Test){ if( true ){ typedef bp::class_< AttributesTest_wrapper > AttributesTest_exposer_t; AttributesTest_exposer_t AttributesTest_exposer = AttributesTest_exposer_t( "AttributesTest" ); bp::scope AttributesTest_scope( AttributesTest_exposer ); AttributesTest_exposer.def( bp::init<
()[bp::default_call_policies()] );
pyplusplus::containers::static_sized::register_array_1< int, 10, bp::default_call_policies >( "__array_1_int_10" ); AttributesTest_exposer.add_property( "staticIntArray", bp::make_function((pyplusplus::containers::static_sized::array_1_t< int, 10>(AttributesTest_wrapper::* )( )) &AttributesTest_wrapper::pyplusplus_staticIntArray_wrapper), bp::with_custodian_and_ward_postcall< 0, 1, bp::default_call_policies >() ) );; ------------------------------------------------------------------------ -- Note that it maps the python name "AttributesTest" to the derived class AttributesTest_wrapper. Also, let's say we have another class that looks like this and it is exposed to Python using Py++ as well: class NestedAttributesTest{ public: AttributesTest data[10]; } In Python we want to be able to do this:
import PYPP_Test nested = PYPP_Test.NestedAttributesTest() nested.data.staticIntArray[0] = 1
This gives the following error: ArgumentError: Python argument types in None(AttributesTest) did not match C++ signature: None(AttributesTest_wrapper {lvalue}) Why not just keep it simple and rather than creating a derived class just create a namespace(for extra uniqueness) instead and map the variable "staticIntArray" via some method defined in that namespace, such as: .add_property( "staticIntArray", bp::make_function( (&AttributesTest_NSwrapper::pyplusplus_staticIntArray_wrapper), bp::with_custodian_and_ward_postcall< 0, 1, bp::default_call_policies >() ) );; and define the pyplusplus_staticIntArray_wrapper method in the namespace: namespace AttributesTest_NSwrapper{ pyplusplus::containers::static_sized::array_1_t< int, 10 > pyplusplus_staticIntArray_wrapper(){ return pyplusplus::containers::static_sized::array_1_t< int, 10 >( staticIntArray ); } } This solves the above mentioned problem that occurs when you use derived classes as wrappers instead. Any comments? Thanks, -Meghana. -----Original Message----- From: c++-sig-bounces+mharidev=qualcomm.com@python.org [mailto:c++-sig-bounces+mharidev=qualcomm.com@python.org] On Behalf Of Roman Yakovenko Sent: Wednesday, May 03, 2006 10:25 PM To: Abhi; Development of Python/C++ integration Subject: Re: [C++-sig] Exposing c++ classes with static arrays usingBoost.Python and py++ On 5/4/06, Abhi <abhi@qualcomm.com> wrote:
While running py++ on a class with a static array inside it, py++ generates Boost.Python bindings using a derived class for the original C++ class.
pyplusplus::containers::static_sized::array_1_t< int, 10 > pyplusplus_staticIntArray_wrapper(){ return pyplusplus::containers::static_sized::array_1_t< int,
10 >(
staticIntArray ); }
I should make this function static and to take an instance as the first argument. Then generated code will work for derived classes too. I will fix it in few days
Is there any drawback with just mapping the array variable to a global method rather than mapping the whole class.
Obviously, the generated code represents my understanding, preferences and personal taste of how it should be done. In this specific case py++ should mangle into function name: namespace name, class name, variable name. Or it should create some scope/namespace where IntArray will be unique name. Such scope already exists - class wrapper, so I reused it. Also the approach I choose, simplifies py++ code ( == less bugs ). I will re-think my approach, if you will give 3 good reasons, why it should be changed. :-)
thanks - Abhi
-- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ _______________________________________________ C++-sig mailing list C++-sig@python.org http://mail.python.org/mailman/listinfo/c++-sig
On 10/3/06, Haridev, Meghana <mharidev@qualcomm.com> wrote:
Hi Roman, Why not just keep it simple and rather than creating a derived class just create a namespace(for extra uniqueness) instead and map the variable "staticIntArray" via some method defined in that namespace, such as: .add_property( "staticIntArray", bp::make_function(
(&AttributesTest_NSwrapper::pyplusplus_staticIntArray_wrapper), bp::with_custodian_and_ward_postcall< 0, 1, bp::default_call_policies >() ) );;
and define the pyplusplus_staticIntArray_wrapper method in the namespace:
namespace AttributesTest_NSwrapper{ pyplusplus::containers::static_sized::array_1_t< int, 10 > pyplusplus_staticIntArray_wrapper(){ return pyplusplus::containers::static_sized::array_1_t< int, 10 >( staticIntArray ); } }
This solves the above mentioned problem that occurs when you use derived classes as wrappers instead.
It smells like a problem in Boost.Python, also I can not say this for sure without creating small test case that reproduce the problem.
Any comments?
I think Py++ should use "range" functionality to expose static arrays. I will try to find how to implement this. It will take some time so. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/
Hi Roman, I don't think it is a Boost.Python problem because I am able to expose the arrays successfully using namespaces. I think it is more to do with how Py++ exposes arrays (using derived classes). I have attached code to illustrate this by exposing arrays (of both simple and complex types) using namespaces instead of derived classes and how they can be successfully accessed in python. Please let me know what you think about this solution and if something similar can be incorporated into Py++ Thanks, -Meghana. -----Original Message----- From: c++-sig-bounces@python.org [mailto:c++-sig-bounces@python.org] On Behalf Of Roman Yakovenko Sent: Tuesday, October 03, 2006 1:10 PM To: Development of Python/C++ integration Subject: Re: [C++-sig] Exposing c++ classes with static arrays usingBoost.Python and py++ On 10/3/06, Haridev, Meghana <mharidev@qualcomm.com> wrote:
Hi Roman, Why not just keep it simple and rather than creating a derived class just create a namespace(for extra uniqueness) instead and map the variable "staticIntArray" via some method defined in that namespace, such as: .add_property( "staticIntArray", bp::make_function(
(&AttributesTest_NSwrapper::pyplusplus_staticIntArray_wrapper), bp::with_custodian_and_ward_postcall< 0, 1, bp::default_call_policies >() ) );;
and define the pyplusplus_staticIntArray_wrapper method in the namespace:
namespace AttributesTest_NSwrapper{ pyplusplus::containers::static_sized::array_1_t< int, 10 > pyplusplus_staticIntArray_wrapper(){ return pyplusplus::containers::static_sized::array_1_t< int, 10 >( staticIntArray ); } }
This solves the above mentioned problem that occurs when you use derived classes as wrappers instead.
It smells like a problem in Boost.Python, also I can not say this for sure without creating small test case that reproduce the problem.
Any comments?
I think Py++ should use "range" functionality to expose static arrays. I will try to find how to implement this. It will take some time so. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ _______________________________________________ C++-sig mailing list C++-sig@python.org http://mail.python.org/mailman/listinfo/c++-sig
On 10/4/06, Haridev, Meghana <mharidev@qualcomm.com> wrote:
Hi Roman,
I don't think it is a Boost.Python problem because I am able to expose the arrays successfully using namespaces. I think it is more to do with how Py++ exposes arrays (using derived classes).
I was wrong. Py++ generated wrong code.
I have attached code to illustrate this by exposing arrays (of both simple and complex types) using namespaces instead of derived classes and how they can be successfully accessed in python. Please let me know what you think about this solution and if something similar can be incorporated into Py++
There is nothing wrong with your solution. For few reasons I prefer to user wrapper for such things. I just comitted a fix to your problem to SVN. Please try it and let me know what do you think and whether it fix your bug. I created a unit tests based on your input and now it passes. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/
participants (3)
-
Abhi -
Haridev, Meghana -
Roman Yakovenko