Thread: [pygccxml-development] How to manage wrapper classes?
Brought to you by:
mbaas,
roman_yakovenko
From: Matthias B. <ba...@ir...> - 2006-03-24 17:02:33
|
Hi, let me first state the problem I'm currently trying to solve. The Maya SDK defines its own string class MString which is part of my bindings. Any function that expects a string as input actually expects a MString object. But for the Python version I would also like the functions to accept regular Python strings as well (and maybe even return Python strings instead of MStrings but I leave that up for later). I tried to use the implicitly_convertible construct but it didn't work. I could get it to work with a string class that also accepts a std::string in its constructor but the MString class only accepts const char* which didn't work for me. My conclusion was that I need to write wrappers for those functions that expect an MString as input so that they also accept a str object. I'm not liking the idea of having to do that manually on each function, so I wonder if there's an easy way to specify that in my script and have pyplusplus do the real work. I think it's easy to identify the functions that need those wrappers as I can just inspect the argument list of those functions. But what then? If I could add new C++ functions to a generated source file then I think I could create automatic wrappers and use cdef to add those "overloaded" functions to the original object. But what if a function already has a wrapper generated by pyplusplus? How are they concatenated? Could pyplusplus handle that automatically? Any ideas? - Matthias - |
From: Roman Y. <rom...@gm...> - 2006-03-24 18:42:09
|
On 3/24/06, Matthias Baas <ba...@ir...> wrote: > Hi, > > let me first state the problem I'm currently trying to solve. The Maya > SDK defines its own string class MString which is part of my bindings. > Any function that expects a string as input actually expects a MString > object. But for the Python version I would also like the functions to > accept regular Python strings as well (and maybe even return Python > strings instead of MStrings but I leave that up for later). I tried to > use the implicitly_convertible construct but it didn't work. I could get > it to work with a string class that also accepts a std::string in its > constructor but the MString class only accepts const char* which didn't > work for me. Lets skip the rest. Here is what I propouse to you: http://boost.org/libs/python/doc/v2/faq.html#custom_string and take a look on pyplusplus QtXML example. If it does not help you then we will discuss the rest. If you decide to use this solution, than you have few choices how to integr= ate that solution with pyplusplus. Hope this was helpful. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Matthias B. <ba...@ir...> - 2006-03-26 14:11:22
|
Roman Yakovenko wrote: > Lets skip the rest. Here is what I propouse to you: > http://boost.org/libs/python/doc/v2/faq.html#custom_string Oops, I missed that one! I've just tried it out and it works like a charm. Thanks! Now that this problem is solved there's already the next one which is somewhat related and which, I believe, needs a different solution. In the Maya SDK error handling is done with MStatus objects which carry error information (C++ exceptions are never used). There are two possibilities how a SDK function returns a result object. It either returns a MStatus object as in the following example: MStatus select(MObject& object); or it expects an optional pointer to a MStatus object as input which it uses to set its status information: bool isSelected(MObject& object, MStatus* ReturnStatus=NULL); So far, the Python bindings just work like the C++ version. But what I would actually like to have is that the Python version may raise an exception when an error occurs, no matter if the user provided a MStatus object or not. I suppose in the first case where the function returns a MStatus object I could probably "abuse" a result converter to check for an error instead of converting the value (I haven't tried that out yet). But for the second case I think it requires a wrapper because I need to place code before and after the actual function call, something like: bool isSelected_wrapped(MObject& object, MStatus* ReturnStatus=NULL) { MStatus internalstat; MStatus* finalstat=&internalstat; // If the user provided a MStatus object then use this one... if (ReturnStatus!=NULL) { finalstat = ReturnStatus; } // Call the original function... bool res = isSelected(object, finalstat); // Check for errors... if (exceptions_enabled && finalstat->error()) { throw AnAppropriateException(); } return res; } So how should that be accomplished? (and how can it be guaranteed that the user's wrapper code doesn't interfere with the wrapper code that might already get generated by pyplusplus?) - Matthias - |
From: Roman Y. <rom...@gm...> - 2006-03-26 20:37:25
|
On 3/26/06, Matthias Baas <ba...@ir...> wrote: > Roman Yakovenko wrote: > > Lets skip the rest. Here is what I propouse to you: > > http://boost.org/libs/python/doc/v2/faq.html#custom_string > > Oops, I missed that one! > I've just tried it out and it works like a charm. Thanks! My pleasure. > In the Maya SDK error handling is done with MStatus objects which carry > error information (C++ exceptions are never used). There are two > possibilities how a SDK function returns a result object. It either > returns a MStatus object as in the following example: > > MStatus select(MObject& object); > > or it expects an optional pointer to a MStatus object as input which it > uses to set its status information: > > bool isSelected(MObject& object, MStatus* ReturnStatus=3DNULL); > > So far, the Python bindings just work like the C++ version. But what I > would actually like to have is that the Python version may raise an > exception when an error occurs, no matter if the user provided a MStatus > object or not. > I suppose in the first case where the function returns a MStatus object > I could probably "abuse" a result converter to check for an error > instead of converting the value (I haven't tried that out yet). But for > the second case I think it requires a wrapper because I need to place > code before and after the actual function call, something like: > > bool isSelected_wrapped(MObject& object, MStatus* ReturnStatus=3DNULL) > { > MStatus internalstat; > MStatus* finalstat=3D&internalstat; > // If the user provided a MStatus object then use this one... > if (ReturnStatus!=3DNULL) > { > finalstat =3D ReturnStatus; > } > > // Call the original function... > bool res =3D isSelected(object, finalstat); > > // Check for errors... > if (exceptions_enabled && finalstat->error()) > { > throw AnAppropriateException(); > } > return res; > } First of all I think you should be able to create custom call policies. Take a look on this link: http://boost.org/libs/python/doc/v2/CallPolicies.html#CallPolicies-concept May be, this will be enough, I am not sure. > So how should that be accomplished? There are 2 other ways to solve this problem. 1. Create small wrappers in Python. I do not know exactly how it should be = done. But, I feel that this is the right way to go. I hope some days pyplusplus will have 3'rd tree - Python code creators ( they will generate Python code ). 2. Create small wrapper in C++, in the way you did it. Just put that declar= ation in some namespace and add it to using add_code functions. Using this approach you should be carefull. There are so many cases, while exporti= ng some function to Python. By the way, do we talk about pure virtual functions or overloaded ones? >(and how can it be guaranteed that > the user's wrapper code doesn't interfere with the wrapper code that > might already get generated by pyplusplus?) 1. Do you still want to expose functions that returns, take by reference MStatus object? If the answer is not then we can add replace_code function to decl_wrapper_= t class. Then pyplusplus will generate that code. If the answer is yes, then you have a problem. It seems to me that pypluspl= us contains all tools in order to solve this problem, may be it does not expose good interface ( we will find out, right :-) ). If I were you I'd ask on boost.python mailing list about this problem and it's solution using call policies. > - Matthias - -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Matthias B. <ba...@ir...> - 2006-03-27 08:14:55
|
Roman Yakovenko wrote: > First of all I think you should be able to create custom call policies. > Take a look on this link: > http://boost.org/libs/python/doc/v2/CallPolicies.html#CallPolicies-concept > > May be, this will be enough, I am not sure. Interesting idea. From reading the above page I couldn't say if it is possible or not. precall() and postcall() are supposed to manage Python tuples which might indicate that they cannot access the original arguments....? Well, anyway, I posted a message to the c++-sig list, let's see what the "experts" have to say about this. >> So how should that be accomplished? > > There are 2 other ways to solve this problem. > 1. Create small wrappers in Python. I do not know exactly how it should be done. > But, I feel that this is the right way to go. I hope some days > pyplusplus will have > 3'rd tree - Python code creators ( they will generate Python code ). I have also thought about that and I might even get away with this for the Maya SDK, but in general, I think the problem would be that those Python wrappers would only be active when the object was created on the Python side and not on the C++ side. > 2. Create small wrapper in C++, in the way you did it. Just put that declaration > in some namespace and add it to using add_code functions. But as I don't want to create the wrappers manually, how could I add wrappers that I generate automatically to the generated source files (not the main file)? > Using this > approach you should be carefull. There are so many cases, while exporting > some function to Python. By the way, do we talk about pure virtual > functions or overloaded ones? What do you mean? The functions are not pure virtual, they are already implemented in the Maya SDK and I only need to access them. They are neither overloaded.... maybe I didn't understand the actual question...? >> (and how can it be guaranteed that >> the user's wrapper code doesn't interfere with the wrapper code that >> might already get generated by pyplusplus?) > > 1. Do you still want to expose functions that returns, take by > reference MStatus object? Uhm, yes? (that's what my mail was about...?) > If the answer is not then we can add replace_code function to decl_wrapper_t > class. Then pyplusplus will generate that code. What code would replace_code() replace? > If the answer is yes, then you have a problem. It seems to me that pyplusplus > contains all tools in order to solve this problem, may be it does not > expose good interface ( we will find out, right :-) ). I hope so. :) Well, I hope I'll get an answer to my mail on the c++-sig list so that we'll see if explicit wrappers are definitely required or not. - Matthias - |
From: Roman Y. <rom...@gm...> - 2006-03-27 08:31:20
|
On 3/27/06, Matthias Baas <ba...@ir...> wrote: > Roman Yakovenko wrote: > > First of all I think you should be able to create custom call policies. > > Take a look on this link: > > http://boost.org/libs/python/doc/v2/CallPolicies.html#CallPolicies-conc= ept > > > > May be, this will be enough, I am not sure. > > Interesting idea. From reading the above page I couldn't say if it is > possible or not. precall() and postcall() are supposed to manage Python > tuples which might indicate that they cannot access the original > arguments....? Well, anyway, I posted a message to the c++-sig list, > let's see what the "experts" have to say about this. > > >> So how should that be accomplished? > > > > There are 2 other ways to solve this problem. > > 1. Create small wrappers in Python. I do not know exactly how it should= be done. > > But, I feel that this is the right way to go. I hope some days > > pyplusplus will have > > 3'rd tree - Python code creators ( they will generate Python code )= . > > I have also thought about that and I might even get away with this for > the Maya SDK, but in general, I think the problem would be that those > Python wrappers would only be active when the object was created on the > Python side and not on the C++ side. > > > 2. Create small wrapper in C++, in the way you did it. Just put that de= claration > > in some namespace and add it to using add_code functions. > > But as I don't want to create the wrappers manually, how could I add > wrappers that I generate automatically to the generated source files > (not the main file)? You don't have to create them manually. pygccxml is your friend. You can find those functions and generate 2 files: header and source with wrappers for them. You just build your own small code generator. > > Using this > > approach you should be carefull. There are so many cases, while exp= orting > > some function to Python. By the way, do we talk about pure virtual > > functions or overloaded ones? > > What do you mean? The functions are not pure virtual, they are already > implemented in the Maya SDK and I only need to access them. They are > neither overloaded.... maybe I didn't understand the actual question...? If you would deal with pure virtual or overloaded function the solution would be much complex. > >> (and how can it be guaranteed that > >> the user's wrapper code doesn't interfere with the wrapper code that > >> might already get generated by pyplusplus?) > > > > 1. Do you still want to expose functions that returns, take by > > reference MStatus object? > > Uhm, yes? (that's what my mail was about...?) Sorry, I meant whether you want to expose original functions and wrappers, or you want to expose only wrappers? > > If the answer is not then we can add replace_code function to decl_wrap= per_t > > class. Then pyplusplus will generate that code. > > What code would replace_code() replace? pyplusplus generates code from declaration, right. We could add next feature: instead of creating code from declaration it will generate code provided by user. Example: instead of doing next steps my_class =3D mb.class_( 'X' ) mstatus_funcs =3D my_class.member_functions( all functions that has MStatus= ) for func in mstatus_funcs: func.exclude() my_class.add_code( wrapper function reference ) You would write something like: my_class =3D mb.class_( 'X' ) mstatus_funcs =3D my_class.member_functions( all functions that has MStatus= ) for func in mstatus_funcs: func.replace_code( wrapper function reference ) This approach has few advances over first one. I hope now I was clear. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |