pygccxml-development Mailing List for C++ Python language bindings (Page 7)
Brought to you by:
mbaas,
roman_yakovenko
You can subscribe to this list here.
2006 |
Jan
|
Feb
(6) |
Mar
(160) |
Apr
(96) |
May
(152) |
Jun
(72) |
Jul
(99) |
Aug
(189) |
Sep
(161) |
Oct
(110) |
Nov
(9) |
Dec
(3) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(13) |
Feb
(48) |
Mar
(35) |
Apr
(7) |
May
(37) |
Jun
(8) |
Jul
(15) |
Aug
(8) |
Sep
(2) |
Oct
(1) |
Nov
(2) |
Dec
(38) |
2008 |
Jan
(11) |
Feb
(29) |
Mar
(17) |
Apr
(3) |
May
|
Jun
(64) |
Jul
(49) |
Aug
(51) |
Sep
(18) |
Oct
(22) |
Nov
(9) |
Dec
(9) |
2009 |
Jan
(28) |
Feb
(15) |
Mar
(2) |
Apr
(11) |
May
(6) |
Jun
(2) |
Jul
(3) |
Aug
(34) |
Sep
(5) |
Oct
(7) |
Nov
(13) |
Dec
(14) |
2010 |
Jan
(39) |
Feb
(3) |
Mar
(3) |
Apr
(14) |
May
(11) |
Jun
(8) |
Jul
(9) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2011 |
Jan
|
Feb
|
Mar
(7) |
Apr
|
May
|
Jun
(3) |
Jul
(3) |
Aug
(3) |
Sep
|
Oct
|
Nov
|
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
(2) |
2016 |
Jan
(1) |
Feb
(1) |
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
(1) |
Aug
(1) |
Sep
|
Oct
|
Nov
(1) |
Dec
|
2019 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
(1) |
2020 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
(1) |
2021 |
Jan
(1) |
Feb
(1) |
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(1) |
Nov
|
Dec
|
From: Roman Y. <rom...@gm...> - 2009-09-22 11:02:31
|
2009/9/22 Pertti Kellomäki <per...@tu...>: > Hi Roman et al, > > This is related to my questions on Python c++sig list, but I > thought this would be a more appropriate place. You are right. > It seems that function transformations do not apply to protected > members. The attached files illustrate the problem: I apply > an identical function transformation to a public member and > to a protected member, but it only seems to affect the public > member. Constness is removed from g's signature but not from > h's signature. This is an intentional behaviour. FT is a pretty complex feature and it took a lot of time to implement it for almost all public functions ( except constructors ). I am pretty sure, it is possible to implement the feature for "restricted" functions too, but this is really a big(may be I should use "long") project. If you have only few such functions may be you should consider creating the wrappers manually. If you have "write" access to the source code, consider to add new protected functions, so you will not have to use FT. My estimation could be erroneous, but I definitely cant commit myself to such task, sorry :-(. If you want to try to implement the missing feature, I definitely will help you. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Pertti K. <per...@tu...> - 2009-09-22 08:49:58
|
Hi Roman et al, This is related to my questions on Python c++sig list, but I thought this would be a more appropriate place. It seems that function transformations do not apply to protected members. The attached files illustrate the problem: I apply an identical function transformation to a public member and to a protected member, but it only seems to affect the public member. Constness is removed from g's signature but not from h's signature. -- Pertti |
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/ |
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-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-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-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-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-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-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-19 17:54:56
|
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: 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: 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-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: 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: 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: 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: Roman Y. <rom...@gm...> - 2009-08-17 19:35:21
|
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-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: Berserker <ber...@ho...> - 2009-08-12 08:37:26
|
>> 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... > Can you show the use case? Sure :) Let's suppose that we have two classes in C++: JobsManager (a "Singleton" class) and an interface class of a Job. class JobsManager : public Singleton<JobsManager> { // ... public: void addJob(boost::shared_ptr<Job> j) { m_jobs.push_back(j); } void runJobs() { for(Jobs::const_iterator i = m_jobs.begin(); i != m_jobs.end(); (*i)->run(), ++i); } }; class Job { // ... public: void run() { onInit(); onRun(); } protected: virtual void onInit() { // ... } virtual void onRun() = 0; }; The "C++ framework" will load at startup all the python scripts where we can implement and register our custom jobs, something like: class MyJob(Job): def onInit(self): # ... Job.onInit(self) def onRun(self): # ... JobsManager.instance().addJob( myJobInstance ) The last step in C++ is to call JobsManager::instance().runJobs() (after loading all the python scripts), but this function call will be from C++ to Python (not from Python to C++ as "usual"), so we need to restore the correct PyThreadState where MyJob has been created: that's why I need a custom "base wrapper class" (where I save the PyThreadState in the constructor). Since I'm not a Python expert (this is my first experience with Python :) ), can you please help me, as suggested, in customizing the mem_fun_protected_v_wrapper_t and mem_fun_protected_pv_wrapper_t so that they will "share" the virtual_mem_fun/pure_virtual_mem_fun templates like in public virtual functions? Isn't possible to write something like: mem_fun_protected_v_wrapper_t.create_virtual_body = mem_fun_public_v_wrapper_t.create_virtual_body mem_fun_protected_pv_wrapper_t.create_virtual_body = mem_fun_public_vp_wrapper_t.create_virtual_body I just need to share the same code (in this way I don't have to deal with Py++ internals). What about adding two more templates for protected functions instead? Bye _________________________________________________________________ Taglia i costi con Messenger! Chiama e videochiama da PC a PC! http://www.messenger.it/videoconversazioni.aspx |
From: Roman Y. <rom...@gm...> - 2009-08-11 18:39:28
|
2009/8/10 Berserker <ber...@ho...>: >> Right now I have some free time, I suggest you to verify that the >> committed code does what you want and report any problem with it. > > Hi again Roman :) > I'm testing right now the svn version (updated to revision 1751) but > I still have some problems in controlling the GIL (with virtual protected > functions in particular). > The "adaptors" implementations is working for me, Good > even if (because of my inexperience with Py++) I still don't understand why > I can't > define an adaptor in conjunction with a transformer (required to control the > GIL in virtual functions), The reason is ideological. A function transformation feature allows user to do virtually anything. If I will start to add to the feature something else, like adaptors, it will introduce constraints and thus will break the initial idea. > here it is the code I'm actually using: > > # This is code where I iterate over each exported "c" class >> for f in c.member_functions(allow_empty=True): >> f.adaptor = "allow_threads" >> if f.virtuality: >> f.add_transformation(allow_threading_transformer_creator()) >> > > # This code is still required since I need to "guard" the GIL > # for virtual functions (default_controller in particular) >> class allow_threading_transformer_t(transformer.transformer_t): >> def __init__(self, function): >> transformer.transformer_t.__init__(self, function) >> >> def __configure_sealed(self, controller): >> controller.add_pre_call_code("allow_threading_guard guard;") >> >> def configure_mem_fun(self, controller): >> self.__configure_sealed(controller) >> >> def configure_free_fun(self, controller): >> self.__configure_sealed(controller) >> >> def configure_virtual_mem_fun(self, controller): >> self.__configure_sealed(controller.default_controller) >> >> def required_headers(self): >> return [] > > # This code customizes the base wrapper class allowing to save a > # reference to "PyThreadState_Get" and to restore the correct > # interpreter later when the Python code in directly invoked from C++ >> def override_create_identifier(creator, full_name ): >> if full_name == "::boost::python::wrapper": >> return "osiris::PythonWrapper" >> >> return full_name > > # This is the templates customization code (getPythonThreadState > # is a method of PythonWrapper) >> templates.virtual_mem_fun.override = Template( os.linesep.join([ >> 'virtual $return_type $function_name( $arg_declarations )$constness >> $throw{' >> , ' osiris::PythonState state(getPythonThreadState());' >> , ' namespace bpl = boost::python;' >> , ' if( bpl::override $py_function_var = this->get_override( >> "$function_alias" ) ){' >> , ' $declare_py_variables' >> , ' $py_pre_call' >> , ' ${save_py_result}bpl::call<bpl::object>( >> $py_function_var.ptr()$py_arg_expressions );' >> , ' $py_post_call' >> , ' $py_return' >> , ' }' >> , ' else{' >> , ' state.leave();' #Release the lock since from here no >> CPython API will be called >> , ' $cpp_return$wrapped_class::$function_name( >> $cpp_arg_expressions );' >> , ' }' >> , '}' >> ])) This is only +- 20 lines of code :-) > # Pure virtual functions is a little more "tricky" since we need to hold the > GIL lock during > # the exception propagation: osiris::throw_locked_error_already_set is a > function just > # throw a derived boost::python::error_already_set's class holding the GIL > lock >>templates.pure_virtual_mem_fun.override = Template( os.linesep.join([ >> 'virtual $return_type $function_name( $arg_declarations )$constness >> $throw{' >> , ' boost::shared_ptr<osiris::PythonState> state(new >> osiris::PythonState(getPythonThreadState()));' >> , ' namespace bpl = boost::python;' >> , ' if( bpl::override $py_function_var = this->get_override( >> "$function_alias" ) ){' >> , ' $declare_py_variables' >> , ' $py_pre_call' >> , ' ${save_py_result}bpl::call<bpl::object>( >> $py_function_var.ptr()$py_arg_expressions );' >> , ' $py_post_call' >> , ' $py_return' >> , ' }' >> , ' else{' >> , ' PyErr_SetString(PyExc_NotImplementedError, "Attempted >> calling Pure Virtual function that is not implemented :$function_name");' >> , ' osiris::throw_locked_error_already_set(state);' >> , ' }' >> , '}' >> ])) And few more lines. In my opinion the Py++ design works. May be I need to think how to make templates "more" accessible. > And now problems :) > Is it possible to customize "virtual protected functions" and Depends. It depends on how much of Py++ internals you want to know. Function transformation feature can only work with public functions. ( hint: the "function wrapper" is free function without friendship ) What you can do is to to change mem_fun_protected_v_wrapper_t::create_virtual_body method. Take a look on it, I believe it will be easy to you to find out what should be changed. Of course you can do it without modifying Py++ code class H: def xyz( self ): .... def xyz( self ): <your code> H.xyz = xyz The only catch is that you are going to deal with internals and I don't promise to be backward compatible here. > "pure virtual protected functions" as above to have control of the GIL? Can you show the use case? > It seems that those templates are ignored in case of > protected methods or I'm maybe missing something... Yes as I explained FT feature works only for public functions. You can always to do #define private public and include all your code :-)))) > Thanks again for your help, You are welcome. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Berserker <ber...@ho...> - 2009-08-10 15:44:24
|
> Right now I have some free time, I suggest you to verify that the > committed code does what you want and report any problem with it. Hi again Roman :) I'm testing right now the svn version (updated to revision 1751) but I still have some problems in controlling the GIL (with virtual protected functions in particular). The "adaptors" implementations is working for me, even if (because of my inexperience with Py++) I still don't understand why I can't define an adaptor in conjunction with a transformer (required to control the GIL in virtual functions), here it is the code I'm actually using: # This is code where I iterate over each exported "c" class > for f in c.member_functions(allow_empty=True): > f.adaptor = "allow_threads" > if f.virtuality: > f.add_transformation(allow_threading_transformer_creator()) # This code is still required since I need to "guard" the GIL # for virtual functions (default_controller in particular) > class allow_threading_transformer_t(transformer.transformer_t): > def __init__(self, function): > transformer.transformer_t.__init__(self, function) > > def __configure_sealed(self, controller): > controller.add_pre_call_code("allow_threading_guard guard;") > > def configure_mem_fun(self, controller): > self.__configure_sealed(controller) > > def configure_free_fun(self, controller): > self.__configure_sealed(controller) > > def configure_virtual_mem_fun(self, controller): > self.__configure_sealed(controller.default_controller) > > def required_headers(self): > return [] # This code customizes the base wrapper class allowing to save a # reference to "PyThreadState_Get" and to restore the correct # interpreter later when the Python code in directly invoked from C++ > def override_create_identifier(creator, full_name ): > if full_name == "::boost::python::wrapper": > return "osiris::PythonWrapper" > > return full_name # This is the templates customization code (getPythonThreadState # is a method of PythonWrapper) > templates.virtual_mem_fun.override = Template( os.linesep.join([ > 'virtual $return_type $function_name( $arg_declarations )$constness $throw{' > , ' osiris::PythonState state(getPythonThreadState());' > , ' namespace bpl = boost::python;' > , ' if( bpl::override $py_function_var = this->get_override( "$function_alias" ) ){' > , ' $declare_py_variables' > , ' $py_pre_call' > , ' ${save_py_result}bpl::call<bpl::object>( $py_function_var.ptr()$py_arg_expressions );' > , ' $py_post_call' > , ' $py_return' > , ' }' > , ' else{' > , ' state.leave();' #Release the lock since from here no CPython API will be called > , ' $cpp_return$wrapped_class::$function_name( $cpp_arg_expressions );' > , ' }' > , '}' > ])) # Pure virtual functions is a little more "tricky" since we need to hold the GIL lock during # the exception propagation: osiris::throw_locked_error_already_set is a function just # throw a derived boost::python::error_already_set's class holding the GIL lock >templates.pure_virtual_mem_fun.override = Template( os.linesep.join([ > 'virtual $return_type $function_name( $arg_declarations )$constness $throw{' > , ' boost::shared_ptr<osiris::PythonState> state(new osiris::PythonState(getPythonThreadState()));' > , ' namespace bpl = boost::python;' > , ' if( bpl::override $py_function_var = this->get_override( "$function_alias" ) ){' > , ' $declare_py_variables' > , ' $py_pre_call' > , ' ${save_py_result}bpl::call<bpl::object>( $py_function_var.ptr()$py_arg_expressions );' > , ' $py_post_call' > , ' $py_return' > , ' }' > , ' else{' > , ' PyErr_SetString(PyExc_NotImplementedError, "Attempted calling Pure Virtual function that is not implemented :$function_name");' > , ' osiris::throw_locked_error_already_set(state);' > , ' }' > , '}' > ])) And now problems :) 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... Thanks again for your help, bye _________________________________________________________________ Taglia i costi con Messenger! Chiama e videochiama da PC a PC! http://www.messenger.it/videoconversazioni.aspx |
From: Roman Y. <rom...@gm...> - 2009-08-07 17:54:27
|
On Fri, Aug 7, 2009 at 1:17 PM, Berserker<ber...@ho...> wrote: > Thanks for your help! You are welcome. > At the moment I'm using the "stable" versione but soon I'll migrate to svn > (or maybe a new stable version ;) ) Right now I have some free time, I suggest you to verify that the committed code does what you want and report any problem with it. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Berserker <ber...@ho...> - 2009-08-07 10:17:54
|
> I commited the code and testers to SVN: > http://pygccxml.svn.sourceforge.net/viewvc/pygccxml?view=rev&revision=1741 > pyplusplus_dev/unittests/function_adaptor_tester.py files contains > usage example. Thanks for your help! At the moment I'm using the "stable" versione but soon I'll migrate to svn (or maybe a new stable version ;) ) P.S. (OT): I'm debugging the embedded python code with Winpdb ( http://winpdb.org/docs/embedded-debugging/ ), that's a very cool stuff :D _________________________________________________________________ Porta Hotmail in vacanza. Leggi la posta dal cellulare! http://new.windowslivemobile.msn.com/IT-IT/windows-live-hotmail/default.aspx |