Thread: Re: [pygccxml-development] Function adaptors
Brought to you by:
mbaas,
roman_yakovenko
From: Berserker <ber...@ho...> - 2009-08-17 15:21:54
|
>> Is it possible to customize "virtual protected functions" and >> "pure virtual protected functions" as above to have control of the GIL? >> It seems that those templates are ignored in case of >> protected methods or I'm maybe missing something... Hi Roman, any news about this? Bye _________________________________________________________________ Scarica i nuovi gadget per personalizzare Messenger! http://www.messenger.it/home_gadget.aspx |
From: Roman Y. <rom...@gm...> - 2009-08-17 19:35:21
Attachments:
function_adaptor.cpp
|
2009/8/17 Berserker <ber...@ho...>: >>> Is it possible to customize "virtual protected functions" and >>> "pure virtual protected functions" as above to have control of the GIL? >>> It seems that those templates are ignored in case of >>> protected methods or I'm maybe missing something... > > Hi Roman, any news about this? Actually yes: http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1754&view=rev I also attach a file, the Py++ tester generated. Follow the comments and I think you will be fine. No need to deal with Py++ internals. May I ask you to create an article or document, with examples, which explains how to use Py++ for embedding? I will put it on the site, so other users will be able to actually enjoy from using Py++ :-) Thanks -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Berserker <ber...@ho...> - 2009-08-18 10:04:38
|
> Actually yes: http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1754&view=rev > I also attach a file, the Py++ tester generated. Follow the comments > and I think you will be fine. No need to deal with Py++ internals. You really made my life easier with this patch, thanks! Unfortunately I still have a (little) problem with virtual protected methods :) Let's consider the "Foo" class: > class Foo() > { > public: > Foo(){} > virtual ~Foo(){} > public: > virtual void public_virtual(){} > protected: > virtual void protected_virtual(){} > }; Base on revision 1754, the wrapper's code generated for "public_virtual" is splitted in: - Foo_wrapper::default_public_virtual: this is the case of a Python to C++ function call, here I unlock the GIL allowing others interpreters to run Python code during the Foo::public_virtual execution where no CPython API will be called - Foo_wrapper::public_virtual (C++ to Python call): this is the case of a C++ to Python function call (as I the "JobsManager" sample that I've posted before) and here, as exaplained, I need to restore the correct PyThreadState. Everything works fine here :D, the problem is related to protected_virtual method where Py++ only generates Foo_wrapper::protected_virtual code (why?). Now consider this Python code: > class PyFoo(Foo): > def test_public_virtual(self): > self.public_virtual() > > def public_virtual(self): > Foo.public_virtual(self) > > def test_protected_virtual(self): > self.protected_virtual() > > def protected_virtual(self): > Foo.protected_virtual(self) > > foo = PyFoo() > foo.test_virtual_public() > foo.test_virtual_protected() foo.test_public_virtual() calls PyFoo.public_virtual() which calls Foo_wrapper::default_public_virtual() which calls Foo::public_virtual() (as expected) foo.test_protected_virtual() calls PyFoo.protected_virtual() which calls Foo_wrapper::protected_virtual() insted of a "Foo_wrapper::default_protected_virtual()", let's see the code of "Foo_wrapper::protected_virtual()" (without "customizations") > virtual void protected_virtual( ){ > if( ::boost::python::override func_protected_virtual = this->get_override( "protected_virtual" ) ) > func_protected_virtual( ); > else{ > this->::Foo::protected_virtual( ); > } > } Do you see the problem here? "func_protected_virtual" will always lead in a "true" condition because of our PyFoo.protected_virtual, so func_protected_virtual() invokes the Python code which in turn invokes the C++ wrapper code infinitely. I think that it will be easy to fix this problem (we just need to create a Foo_wrapper::default_protected_virtual as for the virtual public functions). > May I ask you to create an article or document, with examples, which > explains how to use Py++ for embedding? Sure, I'd like to help you in writing an "embedding tutorial" but I need to fix the last issues in my TODO, for example I noticed that in this release you make use of "boost::python::pure_virtual" which is correct but causes me lots of headaches :) , here is a short explanation of the problem: ""boost::python::pure_virtual" is a custom "visitor" that adds a default implementation (function "pure_virtual_called") which raises an exception. Here it is the code: > void BOOST_PYTHON_DECL pure_virtual_called() > { > PyErr_SetString(PyExc_RuntimeError, "Pure virtual function called"); > throw_error_already_set(); > } In the case of a C++ to Python calls, I would need, as usual, to restore the right PyThreadState before calling any CPython API (PyErr_SetString in the above's code), but I have no options here to customize "pure_virtual_called". Probably I'll ovverride in Py++ the identifier "::boost::python::pure_virtual" with a custom one, but I still need to think/work on this (I love the "override" feature in Py++ :) ). The last problem I want to report is in the files name generation: they follow the classes names (in the "Foo" example Py++ creates a "Foo.pypp.cpp" file) but in the registration code (where BOOST_PYTHON_MODULE is defined), the include code is always in lower case (#include "foo.pypp.cpp" in our example) and this causes problems when I compile the code under linux. Actually I'm using this workaround: > original_write_file = pyplusplus.file_writers.multiple_files.multiple_files_t.write_file > def make_lower_write_file(self, fpath, content): > splittedPath = os.path.split(fpath) > fpath = os.path.join(splittedPath[0], splittedPath[1].lower()) > original_write_file(self, fpath, content) > pyplusplus.file_writers.multiple_files.multiple_files_t.write_file = make_lower_write_file Thanks again for making my life easier, I hope to solve the "protected" issue (and others too...) soon :) Bye _________________________________________________________________ Scarica i nuovi gadget per personalizzare Messenger! http://www.messenger.it/home_gadget.aspx |
From: Berserker <ber...@ho...> - 2009-08-18 13:23:16
|
> for example I noticed that in this release you make use of "boost::python::pure_virtual" which is > correct but causes me lots of headaches :) , here is a short explanation of the problem: > ""boost::python::pure_virtual" is a custom "visitor" that adds a default implementation > (function "pure_virtual_called") which raises an exception. I noticed that boost::python::pure_virtual is only used for pure virtual public methods and not for pure virtual protected methods, is this intentional? I think that boost::python::pure_virtual should be used in pure virtual protected methods too. _________________________________________________________________ Porta Messenger in Vacanza! Scaricalo sul cellulare! http://new.windowslivemobile.msn.com/IT-IT/windows-live-messenger/default.aspx |
From: Roman Y. <rom...@gm...> - 2009-08-18 17:45:43
|
2009/8/18 Berserker <ber...@ho...>: > You really made my life easier with this patch, thanks! Okey, in this case we are moving in the right direction :-) > Unfortunately I still have a (little) problem with virtual protected methods > :) May I ask to you post C++ code and the generated code with comments where you want to insert your code? > Everything works fine here :D, Good. > the problem is related to protected_virtual > method where Py++ > only generates Foo_wrapper::protected_virtual code (why?). I don't remember. I think there were serious problems in that area. After all, it is impossible to access protected functions out side of the class and this is the main problem. > Now consider this > Python code: > >> class PyFoo(Foo): >> def test_public_virtual(self): >> self.public_virtual() >> >> def public_virtual(self): >> Foo.public_virtual(self) >> >> def test_protected_virtual(self): >> self.protected_virtual() >> >> def protected_virtual(self): >> Foo.protected_virtual(self) >> >> foo = PyFoo() >> foo.test_virtual_public() >> foo.test_virtual_protected() > > foo.test_public_virtual() calls PyFoo.public_virtual() which calls > Foo_wrapper::default_public_virtual() > which calls Foo::public_virtual() (as expected) > > foo.test_protected_virtual() calls PyFoo.protected_virtual() which calls > Foo_wrapper::protected_virtual() > insted of a "Foo_wrapper::default_protected_virtual()", let's see the code > of "Foo_wrapper::protected_virtual()" > (without "customizations") > >> virtual void protected_virtual( ){ >> if( ::boost::python::override func_protected_virtual = >> this->get_override( "protected_virtual" ) ) >> func_protected_virtual( ); >> else{ >> this->::Foo::protected_virtual( ); >> } >> } > > Do you see the problem here? "func_protected_virtual" will always lead in a > "true" condition because of > our PyFoo.protected_virtual, so func_protected_virtual() invokes the Python > code which in turn invokes > the C++ wrapper code infinitely. I think that it will be easy to fix this > problem (we just need to create a > Foo_wrapper::default_protected_virtual as for the virtual public Yes and I considered this problem in the past. Py++ support non public virtual functions is limited to "template method" design pattern. I mean it allows to replace\implement them in Python, but not to access their implementation in C++. You are welcome to try to play with those problem and come up with solution. If you can modify source code - I suggest you to do this. Another possible solution is to create adaptors in C++ code and expose them, instead of the library classes. >> May I ask you to create an article or document, with examples, which >> explains how to use Py++ for embedding? > > Sure, I'd like to help you in writing an "embedding tutorial" but I need to > fix the last issues in > my TODO, for example I noticed that in this release you make use of > "boost::python::pure_virtual" which is > correct but causes me lots of headaches :) , here is a short explanation of > the problem: > ""boost::python::pure_virtual" is a custom "visitor" that adds a default > implementation (function "pure_virtual_called") > which raises an exception. Here it is the code: > >> void BOOST_PYTHON_DECL pure_virtual_called() >> { >> PyErr_SetString(PyExc_RuntimeError, "Pure virtual function called"); >> throw_error_already_set(); >> } > > In the case of a C++ to Python calls, I would need, as usual, to restore the > right PyThreadState > before calling any CPython API (PyErr_SetString in the above's code), but I > have no options here to customize > "pure_virtual_called". Probably I'll ovverride in Py++ the identifier > "::boost::python::pure_virtual" with a > custom one, but I still need to think/work on this (I love the "override" > feature in Py++ :) ). This one is fixed. I will commit the code soon. > The last problem I want to report is in the files name generation: they > follow the classes names (in the "Foo" > example Py++ creates a "Foo.pypp.cpp" file) but in the registration code > (where BOOST_PYTHON_MODULE > is defined), the include code is always in lower case (#include > "foo.pypp.cpp" in our example) and this > causes problems when I compile the code under linux. > Actually I'm using this workaround: > >> original_write_file = >> pyplusplus.file_writers.multiple_files.multiple_files_t.write_file >> def make_lower_write_file(self, fpath, content): >> splittedPath = os.path.split(fpath) >> fpath = os.path.join(splittedPath[0], splittedPath[1].lower()) >> original_write_file(self, fpath, content) >> pyplusplus.file_writers.multiple_files.multiple_files_t.write_file = >> make_lower_write_file I think, I fixed this problem. Try to generate code on Linux, don't take it as is from Windows. File names is not the only problem. HTH -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Roman Y. <rom...@gm...> - 2009-08-18 18:10:08
|
2009/8/18 Berserker <ber...@ho...>: >> for example I noticed that in this release you make use of >> "boost::python::pure_virtual" which is >> correct but causes me lots of headaches :) , here is a short explanation >> of the problem: >> ""boost::python::pure_virtual" is a custom "visitor" that adds a default >> implementation >> (function "pure_virtual_called") which raises an exception. > > I noticed that boost::python::pure_virtual is only used for pure virtual > public methods and not for > pure virtual protected methods, is this intentional? I think that > boost::python::pure_virtual > should be used in pure virtual protected methods too. Yes, you forget that in C++ it is illegal to take address of non-public member. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Berserker <ber...@ho...> - 2009-08-19 10:01:27
|
> >> for example I noticed that in this release you make use of > >> "boost::python::pure_virtual" which is > >> correct but causes me lots of headaches :) , here is a short explanation > >> of the problem: > >> ""boost::python::pure_virtual" is a custom "visitor" that adds a default > >> implementation > >> (function "pure_virtual_called") which raises an exception. > > > > I noticed that boost::python::pure_virtual is only used for pure virtual > > public methods and not for > > pure virtual protected methods, is this intentional? I think that > > boost::python::pure_virtual > > should be used in pure virtual protected methods too. > > Yes, you forget that in C++ it is illegal to take address of non-public member. That's true but, as I reported in my previous post, that's not the case when we have a wrapper class, right? Could it be added only in this case? _________________________________________________________________ Scarica i nuovi gadget per personalizzare Messenger! http://www.messenger.it/home_gadget.aspx |
From: Berserker <ber...@ho...> - 2009-08-19 08:51:00
|
> > the problem is related to protected_virtual > > method where Py++ > > only generates Foo_wrapper::protected_virtual code (why?). > > I don't remember. I think there were serious problems in that area. > After all, it is impossible to access protected functions out side of > the class and this is the main problem. Not with wrapper class, right? This is the "problematic" code (actually) generated from Py++ > ::boost::python::class_< Foo_wrapper, ::boost::noncopyable >( "Foo", ::boost::python::init< >() ) > .def( > "public_virtual" > , (void ( ::Foo::* )( ) )(&::Foo::public_virtual) > , (void ( Foo_wrapper::* )( ) )(&Foo_wrapper::default_public_virtual) ) > .def( > "protected_virtual" > , (void ( Foo_wrapper::* )( ) )(&Foo_wrapper::protected_virtual) ) ); I manually added the "Foo_wrapper::default_protected_virtual" like "Foo_wrapper::default_public_virtual": > void Foo_wrapper::default_protected_virtual( ) > { > // my custom code... > ::Foo::protected_virtual( ); > } and I changed the previous code in this way: > ::boost::python::class_< Foo_wrapper, ::boost::noncopyable >( "Foo", ::boost::python::init< >() ) > .def( > "public_virtual" > , (void ( ::Foo::* )( ) )(&::Foo::public_virtual) > , (void ( Foo_wrapper::* )( ) )(&Foo_wrapper::default_public_virtual) ) > .def( > "protected_virtual" > , (void ( ::Foo::* )( ) )(&::Foo_wrapper::protected_virtual) > , (void ( Foo_wrapper::* )( ) )(&Foo_wrapper::default_protected_virtual) ) ); The only "hack" is the bad cast in the line "(void ( ::Foo::* )( ) )(&::Foo_wrapper::protected_virtual)" but I tested the code from Python to C++ and from C++ to Python and now it works as I expected! I absolutely need to call a "base virtual protected method" in Python, what about this solution? Plz this is my "last" obstacle and I really don't know how to change the python scripts... > > In the case of a C++ to Python calls, I would need, as usual, to restore the > > right PyThreadState > > before calling any CPython API (PyErr_SetString in the above's code), but I > > have no options here to customize > > "pure_virtual_called". Probably I'll ovverride in Py++ the identifier > > "::boost::python::pure_virtual" with a > > custom one, but I still need to think/work on this (I love the "override" > > feature in Py++ :) ). > > This one is fixed. I will commit the code soon. Sorry but I didn't understand well what was fixed here. My idea (not yet tested) for this problem doesn't involve any change in Py++, here is a short description of it: - Disable the ::boost::python::pure_virtual exposition overriding the identifier with "" - Create a custom class based on "::boost::python::override" which holds a reference to PyThreadState and don't release it in the case of a pure virtual function call (which raises an exception) _________________________________________________________________ Porta Hotmail in vacanza. Leggi la posta dal cellulare! http://new.windowslivemobile.msn.com/IT-IT/windows-live-hotmail/default.aspx |
From: Roman Y. <rom...@gm...> - 2009-08-19 17:52:11
|
2009/8/19 Berserker <ber...@ho...>: >> > the problem is related to protected_virtual >> > method where Py++ >> > only generates Foo_wrapper::protected_virtual code (why?). >> >> I don't remember. I think there were serious problems in that area. >> After all, it is impossible to access protected functions out side of >> the class and this is the main problem. > > Not with wrapper class, right? > This is the "problematic" code (actually) generated from Py++ > >> ::boost::python::class_< Foo_wrapper, ::boost::noncopyable >( "Foo", >> ::boost::python::init< >() ) >> .def( >> "public_virtual" >> , (void ( ::Foo::* )( ) )(&::Foo::public_virtual) >> , (void ( Foo_wrapper::* )( ) >> )(&Foo_wrapper::default_public_virtual) ) >> .def( >> "protected_virtual" >> , (void ( Foo_wrapper::* )( ) >> )(&Foo_wrapper::protected_virtual) ) ); > > I manually added the "Foo_wrapper::default_protected_virtual" > like "Foo_wrapper::default_public_virtual": > >> void Foo_wrapper::default_protected_virtual( ) >> { >> // my custom code... >> ::Foo::protected_virtual( ); >> } > > and I changed the previous code in this way: > >> ::boost::python::class_< Foo_wrapper, ::boost::noncopyable >( "Foo", >> ::boost::python::init< >() ) >> .def( >> "public_virtual" >> , (void ( ::Foo::* )( ) )(&::Foo::public_virtual) >> , (void ( Foo_wrapper::* )( ) >> )(&Foo_wrapper::default_public_virtual) ) >> .def( >> "protected_virtual" >> , (void ( ::Foo::* )( ) )(&::Foo_wrapper::protected_virtual) >> , (void ( Foo_wrapper::* )( ) >> )(&Foo_wrapper::default_protected_virtual) ) ); > > The only "hack" is the bad cast in the line "(void ( ::Foo::* )( ) > )(&::Foo_wrapper::protected_virtual)" > but I tested the code from Python to C++ and from C++ to Python and now it > works as I expected! I am pretty sure this is illegal. Today, Py++ generates valid code for wide range of compilers and os. I think this change will break some of them. > I absolutely need to call a "base virtual protected method" in Python, what > about this solution? Plz > this is my "last" obstacle and I really don't know how to change the python > scripts... Sorry, I don't want such hacks in Py++. I believe that the generated code quality should be very very high, otherwise people will not trust the code and will not use Py++. I am not going to change this policy. As an alternative I propose you to use other Py++ feature: http://language-binding.net/pyplusplus/documentation/inserting_code.html Replace code generated by Py++ with your own one. >> > In the case of a C++ to Python calls, I would need, as usual, to restore >> > the >> > right PyThreadState >> > before calling any CPython API (PyErr_SetString in the above's code), >> > but I >> > have no options here to customize >> > "pure_virtual_called". Probably I'll ovverride in Py++ the identifier >> > "::boost::python::pure_virtual" with a >> > custom one, but I still need to think/work on this (I love the >> > "override" >> > feature in Py++ :) ). >> >> This one is fixed. I will commit the code soon. > > Sorry but I didn't understand well what was fixed here. I attached the generated file - please take a look on it. I hope it will clarify my answer. > My idea (not yet tested) for this problem doesn't involve any change in > Py++, Please test your ideas :-) > here is a short description of it: > - Disable the ::boost::python::pure_virtual exposition overriding the > identifier with "" > - Create a custom class based on "::boost::python::override" which holds a > reference to > PyThreadState and don't release it in the case of a pure virtual function > call (which > raises an exception) Without changing\replacing some internal code you will not be able to do this :-(. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Roman Y. <rom...@gm...> - 2009-08-19 17:54:56
Attachments:
function_adaptor.cpp
|
I forgot to attach file. The C++ source and Py++ script could be found hee: http://pygccxml.svn.sourceforge.net/viewvc/pygccxml?view=rev&revision=1755 -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Berserker <ber...@ho...> - 2009-08-20 08:15:48
|
> >> ::boost::python::class_< Foo_wrapper, ::boost::noncopyable >( "Foo", > >> ::boost::python::init< >() ) > >> .def( > >> "public_virtual" > >> , (void ( ::Foo::* )( ) )(&::Foo::public_virtual) > >> , (void ( Foo_wrapper::* )( ) > >> )(&Foo_wrapper::default_public_virtual) ) > >> .def( > >> "protected_virtual" > >> , (void ( ::Foo::* )( ) )(&::Foo_wrapper::protected_virtual) > >> , (void ( Foo_wrapper::* )( ) > >> )(&Foo_wrapper::default_protected_virtual) ) ); > > > > The only "hack" is the bad cast in the line "(void ( ::Foo::* )( ) > > )(&::Foo_wrapper::protected_virtual)" > > but I tested the code from Python to C++ and from C++ to Python and now it > > works as I expected! > > I am pretty sure this is illegal. Today, Py++ generates valid code for > wide range of compilers and os. I think this change will break some of > them. I made some other tests :) If I simply declare (assuming that we always have a wrapper class): > ::boost::python::class_< Foo_wrapper, ::boost::noncopyable >( "Foo", > ::boost::python::init< >() ) > .def( > "public_virtual" > , (void ( Foo_wrapper::* )( )) (&Foo_wrapper::default_public_virtual) ) > .def( > "protected_virtual" > , (void ( Foo_wrapper::* )( )(&Foo_wrapper::default_protected_virtual) ) ); virtual public/protected functions (with "base" call from Python) works as expected with no "hacks" (tested from Python<->C++). Why Py++ declares virtual public/protected functions as: > .def("public_virtual", (void ( ::Foo::* )( ) )(&::Foo::public_virtual), > (void ( Foo_wrapper::* )( )(&Foo_wrapper::default_public_virtual) ) insted of simply: > .def("public_virtual", (void ( Foo_wrapper::* )( )(&Foo_wrapper::default_public_virtual) ) when we have a wrapper class? I hope that this change seems reasonable to you. P.S.: Thanks for your patience :D :D :D _________________________________________________________________ Scarica i nuovi gadget per personalizzare Messenger! http://www.messenger.it/home_gadget.aspx |
From: Roman Y. <rom...@gm...> - 2009-08-21 08:14:39
|
2009/8/20 Berserker <ber...@ho...>: > I made some other tests :) > If I simply declare (assuming that we always have a wrapper class): In case of exported non-public virtual member function the wrapper always exists >> ::boost::python::class_< Foo_wrapper, ::boost::noncopyable >( "Foo", >> ::boost::python::init< >() ) >> .def( >> "public_virtual" >> , (void ( Foo_wrapper::* )( )) >> (&Foo_wrapper::default_public_virtual) ) >> .def( >> "protected_virtual" >> , (void ( Foo_wrapper::* )( >> )(&Foo_wrapper::default_protected_virtual) ) ); > > virtual public/protected functions (with "base" call from Python) works as > expected > with no "hacks" (tested from Python<->C++). I will try to integrate this soon ( +- 2days ). > Why Py++ declares virtual public/protected functions as: > >> .def("public_virtual", (void ( ::Foo::* )( ) )(&::Foo::public_virtual), >> (void ( Foo_wrapper::* )( )(&Foo_wrapper::default_public_virtual) ) > > insted of simply: >> .def("public_virtual", (void ( Foo_wrapper::* )( >> )(&Foo_wrapper::default_public_virtual) ) > > when we have a wrapper class? > > I hope that this change seems reasonable to you. It is. I have many tests in this area so will find out whether it works or have some other problems. > P.S.: Thanks for your patience :D :D :D :-), just keep testing what you propose and will be fine -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Berserker <ber...@ho...> - 2009-08-21 08:46:42
|
> >> ::boost::python::class_< Foo_wrapper, ::boost::noncopyable >( "Foo", > >> ::boost::python::init< >() ) > >> .def( > >> "public_virtual" > >> , (void ( Foo_wrapper::* )( )) > >> (&Foo_wrapper::default_public_virtual) ) > >> .def( > >> "protected_virtual" > >> , (void ( Foo_wrapper::* )( > >> )(&Foo_wrapper::default_protected_virtual) ) ); > > > > virtual public/protected functions (with "base" call from Python) works as > > expected > > with no "hacks" (tested from Python<->C++). > > I will try to integrate this soon ( +- 2days ). Thanks! I'll wait for your feedback :D > > > Why Py++ declares virtual public/protected functions as: > > > >> .def("public_virtual", (void ( ::Foo::* )( ) )(&::Foo::public_virtual), > >> (void ( Foo_wrapper::* )( )(&Foo_wrapper::default_public_virtual) ) > > > > insted of simply: > >> .def("public_virtual", (void ( Foo_wrapper::* )( > >> )(&Foo_wrapper::default_public_virtual) ) > > > > when we have a wrapper class? > > > > I hope that this change seems reasonable to you. > > It is. I have many tests in this area so will find out whether it > works or have some other problems. I really hope it works so that we can solve this problem ;) Bye _________________________________________________________________ Porta Messenger in Vacanza! Scaricalo sul cellulare! http://new.windowslivemobile.msn.com/IT-IT/windows-live-messenger/default.aspx |
From: Roman Y. <rom...@gm...> - 2009-08-23 18:17:04
|
2009/8/21 Berserker <ber...@ho...>: >> >> ::boost::python::class_< Foo_wrapper, ::boost::noncopyable >( "Foo", >> >> ::boost::python::init< >() ) >> >> .def( >> >> "public_virtual" >> >> , (void ( Foo_wrapper::* )( )) >> >> (&Foo_wrapper::default_public_virtual) ) >> >> .def( >> >> "protected_virtual" >> >> , (void ( Foo_wrapper::* )( >> >> )(&Foo_wrapper::default_protected_virtual) ) ); >> > >> > virtual public/protected functions (with "base" call from Python) works >> > as >> > expected >> > with no "hacks" (tested from Python<->C++). >> >> I will try to integrate this soon ( +- 2days ). > > Thanks! I'll wait for your feedback :D > >> >> > Why Py++ declares virtual public/protected functions as: >> > >> >> .def("public_virtual", (void ( ::Foo::* )( ) >> >> )(&::Foo::public_virtual), >> >> (void ( Foo_wrapper::* )( )(&Foo_wrapper::default_public_virtual) ) >> > >> > insted of simply: >> >> .def("public_virtual", (void ( Foo_wrapper::* )( >> >> )(&Foo_wrapper::default_public_virtual) ) >> > >> > when we have a wrapper class? >> > >> > I hope that this change seems reasonable to you. >> >> It is. I have many tests in this area so will find out whether it >> works or have some other problems. > > I really hope it works so that we can solve this problem ;) Hi. I started to work on this and it seems I am missing something. Can you post a small and complete example: * C++ code original * Boost.Python code * Python code, which derives from the C++ class Thank you. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Berserker <ber...@ho...> - 2009-08-24 09:26:09
|
> Hi. I started to work on this and it seems I am missing something. > Can you post a small and complete example: > * C++ code original > * Boost.Python code > * Python code, which derives from the C++ class Sure, here it is :) C++ code: > class Foo > { > public: > Foo() { } > virtual ~Foo() { } > > public: > virtual void virtual_public() > { > std::cout << "Foo::virtual_public" << std::endl; > } > > protected: > virtual void virtual_protected() > { > std::cout << "Foo::virtual_protected" << std::endl; > } > }; Boost.Python generated code (without "embedding" changes): > struct Foo_wrapper : ::Foo, ::boost::python::wrapper< ::Foo > { > > Foo_wrapper(::Foo const & arg ) > : ::Foo( arg ) > , ::boost::python::wrapper< ::Foo >(){ > // copy constructor > } > > Foo_wrapper( ) > : ::Foo( ) > , ::boost::python::wrapper< ::Foo >(){ > // null constructor > } > > virtual void virtual_protected( ){ > if( ::boost::python::override func_virtual_protected = this->get_override( "virtual_protected" ) ) > func_virtual_protected( ); > else > this->::Foo::virtual_protected( ); > } > > virtual void virtual_public( ) { > if( ::boost::python::override func_virtual_public = this->get_override( "virtual_public" ) ) > func_virtual_public( ); > else > this->::Foo::virtual_public( ); > } > > void default_virtual_public( ) { > ::Foo::virtual_public( ); > } > > }; > > void register_Foo_class(){ > > ::boost::python::class_< Foo_wrapper >( "Foo", ::boost::python::init< >() ) > .def( > "virtual_protected" > , (void ( Foo_wrapper::* )( ) )(&Foo_wrapper::virtual_protected) ) > .def( > "virtual_public" > , (void ( ::Foo::* )( ) )(&::Foo::virtual_public) > , (void ( Foo_wrapper::* )( ) )(&Foo_wrapper::default_virtual_public) ); > > } Python code (the "Foo" class is exported into a module called "osiris"): > import osiris > > class PyFoo(osiris.Foo): > def test_public(self): > print 'PyFoo::test_public' > self.virtual_public() > > def virtual_public(self): > print 'PyFoo::virtual_public' > osiris.Foo.virtual_public(self) > > def test_protected(self): > print 'PyFoo::test_protected' > self.virtual_protected() > > def virtual_protected(self): > print 'PyFoo::virtual_protected' > osiris.Foo.virtual_protected(self) > > foo = PyFoo() > foo.test_public() > foo.test_protected() "foo.test_public()" works as expected becase PyFoo.virtual_public invokes the base method on Foo_wrapper::default_virtual_public, instead "foo.test_protected()" causes an infinite loop because it invokes PyFoo.virtual_protected which invokes Foo_wrapper::virtual_protected (which invokes PyFoo.virtual_protected and so on...). As I proposed before, I think that it is necessary to generate a "Foo_wrapper::default_virtual_protected" function in the same way of "Foo_wrapper::default_virtual_public" and to change the "exposition" part in this way: > void register_Foo_class(){ > > ::boost::python::class_< Foo_wrapper >( "Foo", ::boost::python::init< >() ) > .def( > "virtual_protected" > , (void ( Foo_wrapper::* )( ) )(&Foo_wrapper::default_virtual_protected)) > .def( > "virtual_public" > , (void ( Foo_wrapper::* )( ) )(&Foo_wrapper::default_virtual_public) ); > > } Hope it helps :) _________________________________________________________________ Porta Hotmail in vacanza. Leggi la posta dal cellulare! http://new.windowslivemobile.msn.com/IT-IT/windows-live-hotmail/default.aspx |
From: Roman Y. <rom...@gm...> - 2009-08-24 20:02:06
|
2009/8/24 Berserker <ber...@ho...>: > "foo.test_public()" works as expected becase PyFoo.virtual_public invokes > the base method on Foo_wrapper::default_virtual_public, instead > "foo.test_protected()" causes an infinite loop because it invokes > PyFoo.virtual_protected > which invokes Foo_wrapper::virtual_protected (which invokes > PyFoo.virtual_protected and so on...). > As I proposed before, I think that it is necessary to generate a > "Foo_wrapper::default_virtual_protected" function in the same way of > "Foo_wrapper::default_virtual_public" and to change the "exposition" part in > this way: > >> void register_Foo_class(){ >> >> ::boost::python::class_< Foo_wrapper >( "Foo", ::boost::python::init< >> >() ) >> .def( >> "virtual_protected" >> , (void ( Foo_wrapper::* )( ) >> )(&Foo_wrapper::default_virtual_protected)) >> .def( >> "virtual_public" >> , (void ( Foo_wrapper::* )( ) >> )(&Foo_wrapper::default_virtual_public) ); >> >> } > > Hope it helps :) Yes and me too: http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1756&view=rev Let me know whether it solved your problem or not and what compiler you used. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Berserker <ber...@ho...> - 2009-08-25 09:05:07
|
> Yes and me too: http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1756&view=rev > Let me know whether it solved your problem or not and what compiler you used. It works perfectly :) At the moment I'm working on windows with vc8, but I tested the code (without this patch yet) on Linux too (gcc 4.4). I see that in case of virtual public methods, the exposition code hasn't been changed: is there a reason for that? I mean: .def( > "virtual_public" > , (void ( ::Foo::* )( ) )(&::Foo::virtual_public) > , (void ( Foo_wrapper::* )( ) )(&Foo_wrapper::default_virtual_public) ) hasn't been changed to: > .def( > "virtual_public" > , (void ( Foo_wrapper::* )( ) )(&Foo_wrapper::default_virtual_public) ) This only a "curiosity" of mine, I don't have any problems with that. I'm still fighting with GIL (devil inside :D ) for some special cases that I need to solve (no Py++ problems here ;) ), I'll keep you informed of my results :) (if you are interested in...) Thanks again, bye _________________________________________________________________ Porta Hotmail in vacanza. Leggi la posta dal cellulare! http://new.windowslivemobile.msn.com/IT-IT/windows-live-hotmail/default.aspx |
From: Roman Y. <rom...@gm...> - 2009-08-25 17:43:42
|
2009/8/25 Berserker <ber...@ho...>: > It works perfectly :) > At the moment I'm working on windows with vc8, but I tested the code > (without > this patch yet) on Linux too (gcc 4.4). Okey. These are the good news. I am working on Ubuntu 9.04 and it is important to me not to break the code on Windows. > I see that in case of virtual public methods, the exposition code hasn't > been changed: > is there a reason for that? Yes, http://www.boost.org/doc/libs/1_39_0/libs/python/doc/tutorial/doc/html/python/exposing.html#python.virtual_functions_with_default_implementations I followed the tutorials, but I think I will change it. > This only a "curiosity" of mine, I don't have any problems with that. > I'm still fighting with GIL (devil inside :D ) for some special cases that > I need to solve (no Py++ problems here ;) ), I'll keep you informed of my > results :) > (if you are interested in...) Yes of course. I am more interested in complete article :-). -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |