pygccxml-development Mailing List for C++ Python language bindings (Page 36)
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...> - 2006-09-26 18:27:40
|
On 9/26/06, Matthias Baas <ba...@ir...> wrote: > Kevin Bluck wrote: > > Now that there's two errors I don't really understand, I thought I'd > > better just report them. > > Are you using a cache? Have you removed the cache file/directory prior > to running the updated version of Py++? > The cache contains old objects that might not yet have attributes > introduced in a newer version. > > (I regularly stumble across that one myself... ;) I think we should introduce some solution to the problem. Ideas? -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Roman Y. <rom...@gm...> - 2006-09-26 18:26:00
|
On 9/26/06, Brian OBrien <bob...@ya...> wrote: > If I gave you an account on my system... Do you think > you could help to get this running? To tell you the true I never used MAC computer. More over I fill better when I use Windows than Linux. So, sorry I can help you. May be you can ask for help at Boost.Python mailing list. I am sure there are few MAC users there. > Is this even the > right group to be dicussing py++ Yes this is a right group to discuss Py++, actually this is the only thing we do in this group :-) -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Matthias B. <ba...@ir...> - 2006-09-26 16:56:59
|
Kevin Bluck wrote: > Now that there's two errors I don't really understand, I thought I'd > better just report them. Are you using a cache? Have you removed the cache file/directory prior to running the updated version of Py++? The cache contains old objects that might not yet have attributes introduced in a newer version. (I regularly stumble across that one myself... ;) - Matthias - |
From: Kevin B. <kev...@gm...> - 2006-09-26 16:48:23
|
Using SVN HEAD, I've encountered AttributeError exceptions during the usual call to mb.build_code_creator(). It seems to involve member function declaration objects. The relevant Py++ code is pretty simple: def force_no_init(class_): for c in [ c for c in class_.constructors() if not c.is_copy_constructor ]: class_.remove_declaration( c ) TestNS = builder.namespace('TestNS') TestNS.exclude() TestClass = builder.class_('TestClass') # C++ is TestNS::TestClass TestClass.include() TestClass.decls().exclude() force_no_init(TestClass) TestClass.member_function('getValue').include() builder.build_code_creator(module_name='test') This worked with version 0.8.1 The first traceback was: File "generate_code.py", line 19, in <module> builder.build_code_creator(module_name='test') File "C:\Program Files\Python\lib\site-packages\pyplusplus\module_builder\builder.py", line 247, in build_code_creator self.__code_creator = creator.create() File "C:\Program Files\Python\lib\site-packages\pyplusplus\module_creator\creator.py", line 524, in create declarations.apply_visitor( self, decl ) File "C:\Program Files\Python\Lib\site-packages\pygccxml\declarations\algorithm.py", line 263, in apply_visitor getattr( visitor, fname )() File "C:\Program Files\Python\lib\site-packages\pyplusplus\module_creator\creator.py", line 717, in visit_class if self._is_wrapper_needed( self.curr_decl, exportable_members ): File "C:\Program Files\Python\lib\site-packages\pyplusplus\module_creator\creator.py", line 318, in _is_wrapper_needed if member.function_transformers: File "C:\Program Files\Python\lib\site-packages\pyplusplus\decl_wrappers\calldef_wrapper.py", line 124, in _get_function_transformers if None is self._function_transformers: AttributeError: 'member_function_t' object has no attribute '_function_transformers' Just to experiment I changed line 124 of decl_wrappers\calldef_wrapper.py to: if not hasattr(self, '_function_transformers' ) or None is self._function_transformers: ... although this is just a hack; I don't understand why the attribute is missing, so this is probably the wrong thing to do. It did eliminate the exception. Patching that exposed a second AttributeError: File "generate_code.py", line 19, in <module> builder.build_code_creator(module_name='test') File "C:\Program Files\Python\lib\site-packages\pyplusplus\module_builder\builder.py", line 247, in build_code_creator self.__code_creator = creator.create() File "C:\Program Files\Python\lib\site-packages\pyplusplus\module_creator\creator.py", line 524, in create declarations.apply_visitor( self, decl ) File "C:\Program Files\Python\Lib\site-packages\pygccxml\declarations\algorithm.py", line 263, in apply_visitor getattr( visitor, fname )() File "C:\Program Files\Python\lib\site-packages\pyplusplus\module_creator\creator.py", line 740, in visit_class exposed = self.expose_overloaded_mem_fun_using_macro( cls_decl, cls_cc ) File "C:\Program Files\Python\lib\site-packages\pyplusplus\module_creator\creator.py", line 687, in expose_overloaded_mem_fun_using_macro overloads = filter( lambda decl: decl.use_overload_macro, overloads ) File "C:\Program Files\Python\lib\site-packages\pyplusplus\module_creator\creator.py", line 687, in <lambda> overloads = filter( lambda decl: decl.use_overload_macro, overloads ) File "C:\Program Files\Python\lib\site-packages\pyplusplus\decl_wrappers\calldef_wrapper.py", line 205, in get_use_overload_macro return self._use_overload_macro AttributeError: 'member_function_t' object has no attribute '_use_overload_macro' _use_overload_macro is assigned to False in calldef_wrapper.member_function_t.__init__(), so the only thing I can think of is that apply_visitor() is working with a class object rather than an instance. Now that there's two errors I don't really understand, I thought I'd better just report them. Thanks, --- Kevin |
From: Kevin B. <kev...@gm...> - 2006-09-26 16:12:27
|
At line 206 of module_builder/buildper.py, argument create_castinig_constructor is defaulted to True. I see at line 234 a deprecation warning: "create_castinig_constructor argument is deprecated and should not be used." Shouldn't that argument be defaulted to False, to force users to explicitly set the allow_implicit_conversion constructor property if they want that behavior? Also, if you didn't notice, the argument should be spelled: 'create_casting_constructor'. Thanks, --- Kevin |
From: Kevin B. <kev...@gm...> - 2006-09-26 15:26:32
|
In general, I think it would be helpful if methods that modify an object instance would return a reference to the modified instance instead of 'None'. This would allow calls to be chained if desired rather than having to assign an explicit named reference whenever more than one operation is desired. For example, I think it would be great if in addition to writing this: myclass = mb.class_('myclass') ... myclass_foo = myclass.member_function('goo') myclass_foo.rename('foo') myclass_foo.include() ... you could also write this: myclass = mb.class_('myclass') ... myclass.member_function('goo').rename('foo').include() Thanks, --- Kevin |
From: Brian O. <bob...@ya...> - 2006-09-26 14:42:59
|
If I gave you an account on my system... Do you think you could help to get this running? Is this even the right group to be dicussing py++ __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com |
From: Roman Y. <rom...@gm...> - 2006-09-26 11:00:34
|
Hi. I think that the first draft of "properties" functionality is ready. Usage example: struct data_t{ data_t() : m_count( 0 ) {} int count() const { return m_count; } void set_count( int x ) { m_count = x; } int m_count; }; mb = module_builder_t(...) data = mb.class_( 'data_t' ) count = data.member_function( 'count' ) set_count = data.member_function( 'set_count' ) data.add_property( "count", count, set_count ) #also exists but untested add_static_property 1. Py++ will not exclude count and set_count by default. ( Is this expected behaviour? ) 2. Call policies for property functions should be set on relevant functions 3. add_[static]_property as arguments takes references to member function declaration This is initial implementation and I will extend it to take other type of arguments. Feedback's and bugs are welcome. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Roman Y. <rom...@gm...> - 2006-09-26 05:04:48
|
On 9/26/06, Kevin Bluck <kev...@gm...> wrote: > > If you use SVN version, than split_module returns list of generated > > files and provides you a way to tell what should be done with "no more > > in use" generated files. By default Py++ will delete them. > > User would have to regenerate the build script (makefile, jamfile, whatever) > every Py++ run to make use of that, though. > > > mb = module_builder_t( ... ) > > mb.build_code_creator( ... ) > > my_dir = os.path.abspath('.') #for example > > mb.code_creator.user_defined_directories.append( my_dir ) > > Thanks, this strips the leading path cruft from the #include directives, which > is quite acceptable. > > It's not actually necessary to do the os.path.abspath() call. It works with > the relative paths as well. os.path.abspath was just an example, you can replace it with whatever you want. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Kevin B. <kev...@gm...> - 2006-09-25 21:11:14
|
> If you use SVN version, than split_module returns list of generated > files and provides you a way to tell what should be done with "no more > in use" generated files. By default Py++ will delete them. User would have to regenerate the build script (makefile, jamfile, whatever) every Py++ run to make use of that, though. > mb = module_builder_t( ... ) > mb.build_code_creator( ... ) > my_dir = os.path.abspath('.') #for example > mb.code_creator.user_defined_directories.append( my_dir ) Thanks, this strips the leading path cruft from the #include directives, which is quite acceptable. It's not actually necessary to do the os.path.abspath() call. It works with the relative paths as well. Naturally, you have to append *both* the lib include *and* the destination source folders to user_defined_directories to get both categories of #include directives stripped. --- Kevin |
From: Roman Y. <rom...@gm...> - 2006-09-25 20:29:06
|
On 9/25/06, Kevin Bluck <kev...@gm...> wrote: > If I do something like this: > > sandbox_root = '../../../../' > foo_inc_root = sandbox_root + 'lib/foolib/include/' > foolib_h = foo_inc_root + 'foolib.h' > gccxml_exe = sandbox_root + 'build/gccxml/gccxml.exe' > builder_args = { 'files' : [foolib_h] > , 'gccxml_path' : gccxml_exe > , 'working_directory' : foo_inc_root > , 'include_paths' : [foo_inc_root] > , 'define_symbols' : None > , 'undefine_symbols' : None > , 'compilation_mode' : None > , 'cache' : file_cache_t('./cache/foolib_h') > , 'optimize_queries' : True > , 'ignore_gccxml_output' : False > , 'cflags' : "" > } > builder = module_builder_t(**builder_args) > # ... Generate code > builder.build_code_creator(module_name='_foo_base') > builder.split_module('../cpp/_foo_base/') > > Notice the last line. I've added a subfolder. The reason for this is > that the 'foolib' library has multiple namespaces, and I want each to be > represented by a different .pyd. '_foo_base.pyd', '_foo_advanced.pyd', > etc. Each namespace's .cpp filess should be generated into their own > subfolder so that they can easily be globbed by the build script. Due to > the nature of split_module() its hard to predict from the build system's > point of view exactly what cpp files are going to be generated, so > globbing whatever happens to be in each subfolder is the most > maintainable strategy. If you use SVN version, than split_module returns list of generated files and provides you a way to tell what should be done with "no more in use" generated files. By default Py++ will delete them. > However, Py++ doesn't adjust for the extra subfolder when it writes the > relative path to the header. Each .pypp.cpp file still shows '#include > '../../../../lib/foolib/include/foolib.h' when it actually ought to have > another ../ stuck on the front because its being generated into one more > level down. This also applies to the .pypp.hpp includes. Py++ writes > '#include ../cpp/foolib.pypp.hpp' when it ought to be '#include > ../../cpp/foolib.pypp.hpp' Naturally, this breaks the build. > > Should Py++ adjust relative paths to account for the actual destination > of generated files? Or am I failing to configure something properly here? Py++ does not generate "relative" includes. I remember I had some problems with relative includes. I don't remember what are they. May I propose another solution? mb = module_builder_t( ... ) mb.build_code_creator( ... ) my_dir = os.path.abspath('.') #for example mb.code_creator.user_defined_directories.append( my_dir ) This should tell Py++ to generate include directives and take into account some directories. Now from build script you can add the path to directory to search header files in. I think this solution should work. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Kevin B. <kev...@gm...> - 2006-09-25 19:37:31
|
If I do something like this: sandbox_root = '../../../../' foo_inc_root = sandbox_root + 'lib/foolib/include/' foolib_h = foo_inc_root + 'foolib.h' gccxml_exe = sandbox_root + 'build/gccxml/gccxml.exe' builder_args = { 'files' : [foolib_h] , 'gccxml_path' : gccxml_exe , 'working_directory' : foo_inc_root , 'include_paths' : [foo_inc_root] , 'define_symbols' : None , 'undefine_symbols' : None , 'compilation_mode' : None , 'cache' : file_cache_t('./cache/foolib_h') , 'optimize_queries' : True , 'ignore_gccxml_output' : False , 'cflags' : "" } builder = module_builder_t(**builder_args) # ... Generate code builder.build_code_creator(module_name='_foo_base') builder.split_module('../cpp/_foo_base/') Notice the last line. I've added a subfolder. The reason for this is that the 'foolib' library has multiple namespaces, and I want each to be represented by a different .pyd. '_foo_base.pyd', '_foo_advanced.pyd', etc. Each namespace's .cpp filess should be generated into their own subfolder so that they can easily be globbed by the build script. Due to the nature of split_module() its hard to predict from the build system's point of view exactly what cpp files are going to be generated, so globbing whatever happens to be in each subfolder is the most maintainable strategy. However, Py++ doesn't adjust for the extra subfolder when it writes the relative path to the header. Each .pypp.cpp file still shows '#include '../../../../lib/foolib/include/foolib.h' when it actually ought to have another ../ stuck on the front because its being generated into one more level down. This also applies to the .pypp.hpp includes. Py++ writes '#include ../cpp/foolib.pypp.hpp' when it ought to be '#include ../../cpp/foolib.pypp.hpp' Naturally, this breaks the build. Should Py++ adjust relative paths to account for the actual destination of generated files? Or am I failing to configure something properly here? Thanks, --- Kevin |
From: Roman Y. <rom...@gm...> - 2006-09-25 12:34:21
|
On 9/25/06, Matthias Baas <ba...@ir...> wrote: > Before, you said I'm violating the design by adding the > get_required_headers() method, now you say the design doesn't specify a > particular way how to obtain header files and I can do it as I want. > Pardon me, but this sounds like a contradiction to me. No. User does not run it's code from the factory, you do. So you are not free to do it as you want. > Besides that, I regard it as a design flaw that the API doesn't handle > this properly and that I have to introduce dependencies among seemingly > unrelated locations in my code. This is already built-in in C++ language: #include <iostream> //200 lines bellow using namespace std; //300 lines below cout << "x"; //100 lines below cout << y; >In my opinion, this makes maintenance more difficult. I don't think so. > I would have preferred a truly object-oriented/modular > solution where all "information" can be kept in one place and where an > object can encapsulate all its implementation details. You are welcome: 1. to propose one. 2. to write a constructive critic I am pretty happy with Py++ design. > >> And where do the decl_wrapper classes come into play here? > > > > decl_wrapper does not come into play here. > > Sorry, but that's again a contradiction to what you said above ("all > this information creator_t takes from decl_wrappers classes.". It's > still quoted above). creator_t takes all information from the decl_wrappers classes. User that externally modifies the tree not. I don't see the contradiction. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Matthias B. <ba...@ir...> - 2006-09-25 12:19:44
|
Roman Yakovenko wrote: > On 9/25/06, Matthias Baas <ba...@ir...> wrote: >> Roman Yakovenko wrote: >> > Because when user will try to add new transformation, he will need to >> > understand code creators >> >> Why do you think this is the case? It's not. If a transformer creates >> code that requires a particular header, it has to declare so by calling >> the require_header() method on the corresponding code manager object. > > Why creator_t can not ask the code manager required headers? It gets those headers via the code creator object. >> >> So how does the current design deal with the problem that a code >> creator >> >> might generate code that requires a particular header file? >> > >> > Very very simple - all this information creator_t takes from >> > decl_wrappers classes. >> >> Could you provide an explanation using the following example scenario: >> >> A user implements a custom code creator in his generation script. The >> code creator can be parameterized and can produce slightly different >> code depending on those parameters. Each code variation has its own set >> of required header files, some of which are written by the user, some >> are part of the project he's creating wrappers for and some might be >> from the Py++ code repository. >> After the Py++ code creator tree has been built, the user adds several >> of his custom creators at appropriate places into the tree. >> >> Now the question is, what else has to be done to include the required >> header files and who's actually including them? > > User should modify the code creators tree and add "include" creators to it. > Now, how he finds out what "include"s are needed is up to him. He is > free to implement this as he wants. Before, you said I'm violating the design by adding the get_required_headers() method, now you say the design doesn't specify a particular way how to obtain header files and I can do it as I want. Pardon me, but this sounds like a contradiction to me. Besides that, I regard it as a design flaw that the API doesn't handle this properly and that I have to introduce dependencies among seemingly unrelated locations in my code. In my opinion, this makes maintenance more difficult. I would have preferred a truly object-oriented/modular solution where all "information" can be kept in one place and where an object can encapsulate all its implementation details. >> And where do the decl_wrapper classes come into play here? > > decl_wrapper does not come into play here. Sorry, but that's again a contradiction to what you said above ("all this information creator_t takes from decl_wrappers classes.". It's still quoted above). - Matthias - |
From: Roman Y. <rom...@gm...> - 2006-09-25 10:39:08
|
On 9/25/06, Matthias Baas <ba...@ir...> wrote: > Roman Yakovenko wrote: > > Because when user will try to add new transformation, he will need to > > understand code creators > > Why do you think this is the case? It's not. If a transformer creates > code that requires a particular header, it has to declare so by calling > the require_header() method on the corresponding code manager object. Why creator_t can not ask the code manager required headers? > >> So how does the current design deal with the problem that a code creator > >> might generate code that requires a particular header file? > > > > Very very simple - all this information creator_t takes from > > decl_wrappers classes. > > Could you provide an explanation using the following example scenario: > > A user implements a custom code creator in his generation script. The > code creator can be parameterized and can produce slightly different > code depending on those parameters. Each code variation has its own set > of required header files, some of which are written by the user, some > are part of the project he's creating wrappers for and some might be > from the Py++ code repository. > After the Py++ code creator tree has been built, the user adds several > of his custom creators at appropriate places into the tree. > > Now the question is, what else has to be done to include the required > header files and who's actually including them? User should modify the code creators tree and add "include" creators to it. Now, how he finds out what "include"s are needed is up to him. He is free to implement this as he wants. This is because he implements this functionality "out of the factory". > And where do the > decl_wrapper classes come into play here? decl_wrapper does not come into play here. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Matthias B. <ba...@ir...> - 2006-09-25 10:17:14
|
Roman Yakovenko wrote: > Because when user will try to add new transformation, he will need to > understand code creators Why do you think this is the case? It's not. If a transformer creates code that requires a particular header, it has to declare so by calling the require_header() method on the corresponding code manager object. >> So how does the current design deal with the problem that a code creator >> might generate code that requires a particular header file? > > Very very simple - all this information creator_t takes from > decl_wrappers classes. Could you provide an explanation using the following example scenario: A user implements a custom code creator in his generation script. The code creator can be parameterized and can produce slightly different code depending on those parameters. Each code variation has its own set of required header files, some of which are written by the user, some are part of the project he's creating wrappers for and some might be from the Py++ code repository. After the Py++ code creator tree has been built, the user adds several of his custom creators at appropriate places into the tree. Now the question is, what else has to be done to include the required header files and who's actually including them? And where do the decl_wrapper classes come into play here? - Matthias - |
From: Roman Y. <rom...@gm...> - 2006-09-25 06:16:47
|
On 9/24/06, Matthias Baas <ba...@ir...> wrote: > Roman Yakovenko wrote: > > Hi Matthias. Next code is cut-and-paste from creator_t.visit_member_function > > > > required_headers = getattr(fwrapper, "get_required_headers", lambda : [])() > > > > This code is problematic for next reasons: > > > > 1. When we talked about [FT], we thought that user will be able to add > > custom > > function transformation, without understanding of code creators, right? > > I think, that putting "get_required_headers" on code creator is a > > little bit problematic. > > (This point didn't contain any reason why the above code is problematic, > you just say that you think it is problematic...?) Because when user will try to add new transformation, he will need to understand code creators, this is not what we want. > > 2. There is small design violation: creator_t should not talk to code > > creators. > > creator_t is a factory. As such it should ask for required headers from > > function transformation. > > I was asking about that in an earlier mail: > > Roman Yakovenko wrote: > >> The responsibility of a code creator object is to create a piece of C++ > >> source code that will be written into one or more output files, right? > >> Now my actual question probably boils down to the following question: > >> Whose responsibility is it to make sure that the code that was generated > >> by a particular code creator object can also be compiled without errors? > > > > File writer + code creator. File writer answer the question: where to > > put the > > code, while code creator "what code to put". creator_t defines > > "logical" place of the code creator, by placing it in the right place > > within the tree. File writers insure that the "logical" > > place of code creator is preserved. > > I interpret this as it is the code creator's responsibility to make sure > that the code it generates can be compiled. > This means that if the code > creator generates code that requires a particular header file it must > make sure that this header file gets included. This is a mistake! You are assigning too much responicibilites to code creators. Code creator in only responcible to generate valid code, the one that could be compiled if you put it in a right "environment". > And because there's no > way for a code creator to do that directly, This is by design. > I did it indirectly by > providing a method that returns the required header files (which then > have to be added by whoever is in the position to do so, I decided for > the visit_member_function method). This is a mistake. Factory design pattern does not work this way. > Your suggestion to have a transformation group object that returns a > list of header files would be less flexible than the above. The > transformers only add code to a function but they do not know the entire > function and as such they cannot know about the requirements of code > that was not added by themselves. Yes, but they will report only their parts and "transformation group object" will remove a duplicated items. > Have a look at the current code, the code creator for transformed > virtual functions requests the gil guard header file because it may > create code that uses this header. This code is not handled by a > function transformer, so a transformer group couldn't know about that. This is because you decided that "thread safe" is not function transformation but something else. You did not defined what it is. From my point of view "thread safe" is do function transformation. This is a special case for Py++ and it should deal with it. > So how does the current design deal with the problem that a code creator > might generate code that requires a particular header file? Very very simple - all this information creator_t takes from decl_wrappers classes. I will try to explain the architecture one more time. We are talking about complex code generator. Every class or package share some logic with others, but they don't share the details. Every package defines it's own details: decl_wrappers - does not have details at all. This is because this package is "one big interface" code creators - the details are "how piece of code will look like" For example: decl_wrappers.class_t knows that when user expose some class it could set HeldType, so it has "held_type" property. But this class does not know where the actual held type will be generated. Another example: array member variable. creator_t knows that the way to export array is to use array_1_registrator_t creator. It also knows that in order to use, it have to "include" __array_1.pypp.hpp header. But the creator_t has 0 ( zero ) knowledge how the generated code will look like. I hope this will help you better understand the design. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Matthias B. <ba...@ir...> - 2006-09-24 20:50:48
|
Roman Yakovenko wrote: > Hi Matthias. Next code is cut-and-paste from creator_t.visit_member_function > > required_headers = getattr(fwrapper, "get_required_headers", lambda : [])() > > This code is problematic for next reasons: > > 1. When we talked about [FT], we thought that user will be able to add > custom > function transformation, without understanding of code creators, right? > I think, that putting "get_required_headers" on code creator is a > little bit problematic. (This point didn't contain any reason why the above code is problematic, you just say that you think it is problematic...?) > 2. There is small design violation: creator_t should not talk to code > creators. > creator_t is a factory. As such it should ask for required headers from > function transformation. I was asking about that in an earlier mail: Roman Yakovenko wrote: >> The responsibility of a code creator object is to create a piece of C++ >> source code that will be written into one or more output files, right? >> Now my actual question probably boils down to the following question: >> Whose responsibility is it to make sure that the code that was generated >> by a particular code creator object can also be compiled without errors? > > File writer + code creator. File writer answer the question: where to > put the > code, while code creator "what code to put". creator_t defines > "logical" place of the code creator, by placing it in the right place > within the tree. File writers insure that the "logical" > place of code creator is preserved. I interpret this as it is the code creator's responsibility to make sure that the code it generates can be compiled. This means that if the code creator generates code that requires a particular header file it must make sure that this header file gets included. And because there's no way for a code creator to do that directly, I did it indirectly by providing a method that returns the required header files (which then have to be added by whoever is in the position to do so, I decided for the visit_member_function method). Your suggestion to have a transformation group object that returns a list of header files would be less flexible than the above. The transformers only add code to a function but they do not know the entire function and as such they cannot know about the requirements of code that was not added by themselves. Have a look at the current code, the code creator for transformed virtual functions requests the gil guard header file because it may create code that uses this header. This code is not handled by a function transformer, so a transformer group couldn't know about that. So how does the current design deal with the problem that a code creator might generate code that requires a particular header file? - Matthias - |
From: Roman Y. <rom...@gm...> - 2006-09-24 18:45:44
|
Hi Matthias. Next code is cut-and-paste from creator_t.visit_member_function required_headers = getattr(fwrapper, "get_required_headers", lambda : [])() This code is problematic for next reasons: 1. When we talked about [FT], we thought that user will be able to add custom function transformation, without understanding of code creators, right? I think, that putting "get_required_headers" on code creator is a little bit problematic. 2. There is small design violation: creator_t should not talk to code creators. creator_t is a factory. As such it should ask for required headers from function transformation. 3. I don't "getattr(fwrapper, "get_required_headers", lambda : [])()" this code. In my opinion if you right such code, it means that there is a problem with the design and I think this is true in our case. The solution to the problem is to introduce base class for all transformations and a class that aggregates all these transformations. I don't understand why you don't want to introduce these classes? -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Matthias B. <ba...@ir...> - 2006-09-24 07:13:36
|
Roman Yakovenko wrote: > On 9/23/06, Matthias Baas <ba...@ir...> wrote: >> Roman Yakovenko wrote: >> > They should. Can you give me few good reasons to not create wrappers? >> >> I've just stumbled over another problem as I compiled the bindings on >> Linux. Compilation fails because of a class that has a private >> destructor. This class only provides static members and a few enums, it >> isn't meant to be instantiated (let alone sub-classed). > > Sometimes static members need wrapper, for example arrays. > Can you post small code that reproduce the problem? class Foo { public: static void get_value(int& n) { n = 12; } private: ~Foo() {} }; In your generation script you have to assign the output transformer to get_value: Foo.member_function("get_value").function_transformers.append(output_t(1)) Compilation will then produce the following error: testlib.h: In constructor `Foo_wrapper::Foo_wrapper()': testlib.h:14: error: `Foo::~Foo()' is private testlib/Foo.pypp.cpp:13: error: within this context error: command 'gcc' failed with exit status 1 Tested on Linux with gcc 3.3.4 (whereas MSVC 7.1 obviously ignores that the destructor is private and compiles the above code without problems, so you have to test with gcc as well). - Matthias - |
From: Roman Y. <rom...@gm...> - 2006-09-23 07:53:06
|
On 9/23/06, Matthias Baas <ba...@ir...> wrote: > Roman Yakovenko wrote: > > They should. Can you give me few good reasons to not create wrappers? > > I've just stumbled over another problem as I compiled the bindings on > Linux. Compilation fails because of a class that has a private > destructor. This class only provides static members and a few enums, it > isn't meant to be instantiated (let alone sub-classed). Sometimes static members need wrapper, for example arrays. Can you post small code that reproduce the problem? -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Roman Y. <rom...@gm...> - 2006-09-23 07:50:40
|
Hi Matthias. I spent some time investigating your problem. // testlib.h struct Vector { double x; static const Vector one; Vector(double ax) : x(ax) {} Vector operator+(const Vector& other) { return Vector(x+other.x); } virtual void trigger_wrapper() {} }; // testlib.cpp #include "testlib.h" const Vector Vector::one = Vector(1); As I suspected there is a bug in Boost.Python library. I asked Py++ to generate wrapper using old Boost.Python interface: struct vector_wrapper : operators_bug::vector, bp::wrapper< operators_bug::vector > { vector_wrapper(PyObject*, operators_bug::vector const & arg ) : operators_bug::vector( arg ) , bp::wrapper< operators_bug::vector >(){ // copy constructor } vector_wrapper(PyObject*, double ax ) : operators_bug::vector( ax ) , bp::wrapper< operators_bug::vector >() { // Normal constructor } virtual void trigger_wrapper( ) { if( bp::override func_trigger_wrapper = this->get_override( "trigger_wrapper" ) ) func_trigger_wrapper( ); else operators_bug::vector::trigger_wrapper( ); } void default_trigger_wrapper( ) { operators_bug::vector::trigger_wrapper( ); } }; And vector registration: bp::class_< operators_bug::vector, vector_wrapper >( "vector", "documentation", bp::init< double >(( bp::arg("ax") ), "documentation") ) .def( bp::self + bp::self ) .def( "trigger_wrapper" , &::operators_bug::vector::trigger_wrapper , &vector_wrapper::default_trigger_wrapper ) .def_readonly( "one", operators_bug::vector::one, "documentation" ) .def_readwrite( "x", &operators_bug::vector::x, "documentation" ); The test code you posted v = Vector(3)+Vector.one now works as expected. It could be nice if you can post the description of the bug to boost.pythonmailing list. I suppose it will be not too difficult to solve it. In file operators_bug_tester.py you will find work around to your problem. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Matthias B. <ba...@ir...> - 2006-09-22 21:59:02
|
Roman Yakovenko wrote: > They should. Can you give me few good reasons to not create wrappers? I've just stumbled over another problem as I compiled the bindings on Linux. Compilation fails because of a class that has a private destructor. This class only provides static members and a few enums, it isn't meant to be instantiated (let alone sub-classed). - Matthias - |
From: Matthias B. <ba...@ir...> - 2006-09-22 13:27:17
|
Roman Yakovenko wrote: > On 9/21/06, Roman Yakovenko <rom...@gm...> wrote: >> > a = Vector(1,2,3) # this will be a Vector_wrapper instance >> > b = Vector.zero # this will be a Vector instance >> > c = a+b # fails >> > >> > I don't know exactly what happens here inside Boost.Python, but my >> guess >> > would be that the addition is only defined between two *wrapper* >> classes >> > and not between a wrapper class and the original class. >> > >> > I've experienced such things before with other libraries which is why >> > I'm only creating wrapper classes when it is absolutely necessary. >> >> This is a valid point, that I should check. > > Do you mind to post small test case that reproduce the error? > Also, before you do this, can you check whether redefine_operators = True > solves the problem? This flag hasn't had an influence on the generated code. Here is an example that demonstrates the problem: // testlib.h struct Vector { double x; static const Vector one; Vector(double ax) : x(ax) {} Vector operator+(const Vector& other) { return Vector(x+other.x); } virtual void trigger_wrapper() {} }; // testlib.cpp #include "testlib.h" const Vector Vector::one = Vector(1); Then, in Python the following line fails: v = Vector(3)+Vector.one This produces the following TypeError exception: TypeError: unsupported operand type(s) for +: 'Vector' and 'Vector' If you comment out the trigger_wrapper() method everything works fine. - Matthias - |
From: Kevin B. <kev...@gm...> - 2006-09-21 20:20:14
|
> I know it is not as simple as you expect. If you can wait I plan to > add support for properties in a week or two > ... > foo.property_( foo.member_function( 'get_x' ), foo.member_function( > 'set_x' ) ) > #or may be next interface > foo.property_( 'get_x', 'set_x' ) I can wait. I think it would be preferable to accept either type of parameter, since sometimes you may already have a reference to a member_function_t available and just passing it would be convenient, but if you don't having to make a temporary via the query API seems unnecessarily verbose. --- Kevin |