Thread: [pygccxml-development] mdecl and methods that return values
Brought to you by:
mbaas,
roman_yakovenko
From: Allen B. <al...@vr...> - 2006-05-29 23:48:25
|
I just ran into an interesting limitation on the current API. Namely, when you call methods on mdecl_wrappers and those methods return decls for further processing, the return values are ignored. I ran into in the following case: my_class = my_namespace["MyClass"] my_class["mymethod"].exclude() It could also come up in something else like this though: similar_classes = my_namespace.classes(re_matcher(".*Proxies")) similar_classes.member_functions["bad_function"].exclude() The point is that that the call_redirector_t for mdecl_wrapper doesn't return any values from the methods it calls. I propose that we refactor this method to build up a list of decls returned from all the calls it makes and return them wrapped as a mdecl_wrapper_t if there are values returned and if they make sense to combine (ie. if they are all decl wrappers). This should allow functionality like above and would add quite a bit of flexibility to finding groups of matches within other groups of matches. (ex: find groups of similar methods inside groups of similar classes) Any comments? -Allen |
From: Roman Y. <rom...@gm...> - 2006-05-30 05:12:14
|
On 5/30/06, Allen Bierbaum <al...@vr...> wrote: > I just ran into an interesting limitation on the current API. > > Namely, when you call methods on mdecl_wrappers and those methods return > decls for further processing, the return values are ignored. > > I ran into in the following case: > > my_class = my_namespace["MyClass"] > my_class["mymethod"].exclude() exclude does not have return value > It could also come up in something else like this though: > > similar_classes = my_namespace.classes(re_matcher(".*Proxies")) > similar_classes.member_functions["bad_function"].exclude() > > The point is that that the call_redirector_t for mdecl_wrapper doesn't > return any values from the methods it calls. > > I propose that we refactor this method to build up a list of decls > returned from all the calls it makes and return them wrapped as a > mdecl_wrapper_t if there are values returned and if they make sense to > combine (ie. if they are all decl wrappers). This should allow > functionality like above and would add quite a bit of flexibility to > finding groups of matches within other groups of matches. (ex: find > groups of similar methods inside groups of similar classes) > Any comments? Allen, I am sorry but I don't understand you. Do you want to know what declarations has been [in|ex]cluded? Or you want something more general: to define return values for mdecl_wrapper_t for "get" and "call" functionality, as a list of returned values? Also, can you modify mdec_wrapper.py file and send it? Thanks -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Allen B. <al...@vr...> - 2006-05-30 15:01:52
|
Roman Yakovenko wrote: > On 5/30/06, Allen Bierbaum <al...@vr...> wrote: > >> I just ran into an interesting limitation on the current API. >> >> Namely, when you call methods on mdecl_wrappers and those methods return >> decls for further processing, the return values are ignored. >> >> I ran into in the following case: >> >> my_class = my_namespace["MyClass"] >> my_class["mymethod"].exclude() > > > exclude does not have return value The part that causes the problem is the return from ["mymethod"]. It doesn't return anything, so the code above ends up calling exclude() on NoneType. > >> It could also come up in something else like this though: >> >> similar_classes = my_namespace.classes(re_matcher(".*Proxies")) >> similar_classes.member_functions["bad_function"].exclude() >> >> The point is that that the call_redirector_t for mdecl_wrapper doesn't >> return any values from the methods it calls. >> >> I propose that we refactor this method to build up a list of decls >> returned from all the calls it makes and return them wrapped as a >> mdecl_wrapper_t if there are values returned and if they make sense to >> combine (ie. if they are all decl wrappers). This should allow >> functionality like above and would add quite a bit of flexibility to >> finding groups of matches within other groups of matches. (ex: find >> groups of similar methods inside groups of similar classes) > > >> Any comments? > > > Allen, I am sorry but I don't understand you. Do you want to know what > declarations > has been [in|ex]cluded? No. I want to be able to call methods like decls(), member_functions(), classes(), etc on an mdecl_wrapper and have it return another mdecl_wrapper. Right now these would be called but the return values would be silently ignored. > Or you want something more general: to define > return values > for mdecl_wrapper_t for "get" and "call" functionality, as a list of > returned values? I don't know the answer to this one. I am interested in getting feedback on how other people think this code should function. > > Also, can you modify mdec_wrapper.py file and send it? Maybe. I am not sure if I understand everything going on in there so I didn't want to take a stab at it and implement it incorrectly. -Allen > > Thanks > > |
From: Roman Y. <rom...@gm...> - 2006-05-30 17:14:27
|
On 5/30/06, Allen Bierbaum <al...@vr...> wrote: > Roman Yakovenko wrote: > > > On 5/30/06, Allen Bierbaum <al...@vr...> wrote: > > > >> I just ran into an interesting limitation on the current API. > >> > >> Namely, when you call methods on mdecl_wrappers and those methods return > >> decls for further processing, the return values are ignored. > >> > >> I ran into in the following case: > >> > >> my_class = my_namespace["MyClass"] > >> my_class["mymethod"].exclude() > > > > > > exclude does not have return value > > The part that causes the problem is the return from ["mymethod"]. It > doesn't return anything, so the code above ends up calling exclude() on > NoneType. I will check this and will try to fix. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Roman Y. <rom...@gm...> - 2006-05-30 18:41:16
|
> On 5/30/06, Allen Bierbaum <al...@vr...> wrote: > > Roman Yakovenko wrote: > > >> my_class = my_namespace["MyClass"] > > >> my_class["mymethod"].exclude() > > > > > > > > > exclude does not have return value > > > > The part that causes the problem is the return from ["mymethod"]. It > > doesn't return anything, so the code above ends up calling exclude() on > > NoneType. > > I will check this and will try to fix. Allan, I am sure I am doing something wrong. I created new test case to check the code: http://tinyurl.com/nlama . ( Please take a look on test__getitem__ method. ) I can not reproduce the bug you are talking about :-) May be you have scopedef_t.ALLOW_EMPTY_MDECL_WRAPPER set to True? In this case, if query returns empty exception is not raised. Can you try and reproduce the bug, thanks ? -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Allen B. <al...@vr...> - 2006-05-30 18:58:34
|
Roman Yakovenko wrote: >> On 5/30/06, Allen Bierbaum <al...@vr...> wrote: >> > Roman Yakovenko wrote: >> > >> my_class = my_namespace["MyClass"] >> > >> my_class["mymethod"].exclude() >> > > >> > > >> > > exclude does not have return value >> > >> > The part that causes the problem is the return from ["mymethod"]. It >> > doesn't return anything, so the code above ends up calling >> exclude() on >> > NoneType. >> >> I will check this and will try to fix. > > > Allan, I am sure I am doing something wrong. > I created new test case to check the code: http://tinyurl.com/nlama . > ( Please take a look on test__getitem__ method. ) > I can not reproduce the bug you are talking about :-) > > May be you have scopedef_t.ALLOW_EMPTY_MDECL_WRAPPER set to True? > In this case, if query returns empty exception is not raised. > > Can you try and reproduce the bug, thanks ? > I think you are talking about this part of the test: mb.global_ns[ *'public_base_t'* ].exclude() Change it to something like this: mb.global_ns[ *'public_base_t'* ]['myFunction'].exclude() OR mb.global_ns[ *'public_base_t'* ].member_functions('myFunction').exclude() There should be a failure when calling exclude on the value returned from the member function lookup because there is nothing returned. When a mdecl_wrapper has a method called upon it, it never returns a value. Your test works because the only place a mdecl_wrapper comes in is the value returned from the ['public_base_t'] call. This will function fine with something like exclude that doesn't return values. But it will not work when you need values returned. -Allen |
From: Roman Y. <rom...@gm...> - 2006-05-30 19:22:30
|
On 5/30/06, Allen Bierbaum <al...@vr...> wrote: > I think you are talking about this part of the test: > > mb.global_ns[ *'public_base_t'* ].exclude() Right > Change it to something like this: > > mb.global_ns[ *'public_base_t'* ]['myFunction'].exclude() > > OR > > mb.global_ns[ *'public_base_t'* ].member_functions('myFunction').exclude() Now, I don't need unit test. I see why this does not work. Thanks. Now I know that you want redefine call_redirector_t.__call__ method in next way: #now def __call__( self, *arguments, **keywords ): for d in self.decls: callable_ = getattr(d, self.name) callable_( *arguments, **keywords ) #you want: def __call__( self, *arguments, **keywords ): results = [] for d in self.decls: callable_ = getattr(d, self.name) answer = callable_( *arguments, **keywords ) results.append( answer ) #I assume that all functions will return same type: if not results: return if isinstance( results[0], declaration_t ): return mdecl_wrapper_t( results ) elif isinstance( results[0], mdecl_wrapper_t ): temp_decls = [] for mdecl_wrapper in results: temp_decls.extend( mdecl_wrapper.decls ) return mdecl_wrapper_t( temp_decls ) else: return results Can you test whether this code will work for you or not? Thanks -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Allen B. <al...@vr...> - 2006-05-30 19:54:13
Attachments:
mdecl_diff.txt
|
Roman Yakovenko wrote: > On 5/30/06, Allen Bierbaum <al...@vr...> wrote: > >> I think you are talking about this part of the test: >> >> mb.global_ns[ *'public_base_t'* ].exclude() > > > Right > >> Change it to something like this: >> >> mb.global_ns[ *'public_base_t'* ]['myFunction'].exclude() >> >> OR >> >> mb.global_ns[ *'public_base_t'* >> ].member_functions('myFunction').exclude() > > > Now, I don't need unit test. I see why this does not work. Thanks. > > Now I know that you want redefine call_redirector_t.__call__ method in > next way: > > #now > def __call__( self, *arguments, **keywords ): > for d in self.decls: > callable_ = getattr(d, self.name) > callable_( *arguments, **keywords ) > > #you want: > def __call__( self, *arguments, **keywords ): > results = [] > for d in self.decls: > callable_ = getattr(d, self.name) > answer = callable_( *arguments, **keywords ) > results.append( answer ) > #I assume that all functions will return same type: > if not results: > return > if isinstance( results[0], declaration_t ): > return mdecl_wrapper_t( results ) > elif isinstance( results[0], mdecl_wrapper_t ): > temp_decls = [] > for mdecl_wrapper in results: > temp_decls.extend( mdecl_wrapper.decls ) > return mdecl_wrapper_t( temp_decls ) > else: > return results > > Can you test whether this code will work for you or not? This is close, but not quite all the code is there. I have attached a diff where I fixed up the implementation and added code to the mdecl_wrapper.__getitem__ method to allow calls like I wanted to make. See attached... -Allen > |
From: Roman Y. <rom...@gm...> - 2006-05-30 20:00:52
|
On 5/30/06, Allen Bierbaum <al...@vr...> wrote: > Roman Yakovenko wrote: > > > On 5/30/06, Allen Bierbaum <al...@vr...> wrote: > > > >> I think you are talking about this part of the test: > >> > >> mb.global_ns[ *'public_base_t'* ].exclude() > > > > > > Right > > > >> Change it to something like this: > >> > >> mb.global_ns[ *'public_base_t'* ]['myFunction'].exclude() > >> > >> OR > >> > >> mb.global_ns[ *'public_base_t'* > >> ].member_functions('myFunction').exclude() > > > > > > Now, I don't need unit test. I see why this does not work. Thanks. > > > > Now I know that you want redefine call_redirector_t.__call__ method in > > next way: > > > > #now > > def __call__( self, *arguments, **keywords ): > > for d in self.decls: > > callable_ = getattr(d, self.name) > > callable_( *arguments, **keywords ) > > > > #you want: > > def __call__( self, *arguments, **keywords ): > > results = [] > > for d in self.decls: > > callable_ = getattr(d, self.name) > > answer = callable_( *arguments, **keywords ) > > results.append( answer ) > > #I assume that all functions will return same type: > > if not results: > > return > > if isinstance( results[0], declaration_t ): > > return mdecl_wrapper_t( results ) > > elif isinstance( results[0], mdecl_wrapper_t ): > > temp_decls = [] > > for mdecl_wrapper in results: > > temp_decls.extend( mdecl_wrapper.decls ) > > return mdecl_wrapper_t( temp_decls ) > > else: > > return results > > > > Can you test whether this code will work for you or not? > > This is close, but not quite all the code is there. I have attached a > diff where I fixed up the implementation and added code to the > mdecl_wrapper.__getitem__ method to allow calls like I wanted to make. > > See attached... > > > -Allen > > > > > > > Index: pygccxml_dev/pygccxml/declarations/mdecl_wrapper.py > =================================================================== > --- pygccxml_dev/pygccxml/declarations/mdecl_wrapper.py (revision 156) > +++ pygccxml_dev/pygccxml/declarations/mdecl_wrapper.py (working copy) > @@ -2,6 +2,7 @@ > # Distributed under the Boost Software License, Version 1.0. (See > # accompanying file LICENSE_1_0.txt or copy at > # http://www.boost.org/LICENSE_1_0.txt) > +import declaration > > class call_redirector_t( object ): > """Internal class used to call some function of objects""" > @@ -11,9 +12,23 @@ > self.decls = decls > > def __call__( self, *arguments, **keywords ): > - for d in self.decls: > - callable_ = getattr(d, self.name) > - callable_( *arguments, **keywords ) > + results = [] > + for d in self.decls: > + callable_ = getattr(d, self.name) > + answer = callable_( *arguments, **keywords ) > + results.append( answer ) > + #I assume that all functions will return same type: > + if not results: > + return > + if isinstance( results[0], declaration.declaration_t ): > + return mdecl_wrapper_t( results ) > + elif isinstance( results[0], mdecl_wrapper_t ): > + temp_decls = [] > + for mdecl_wrapper in results: > + temp_decls.extend( mdecl_wrapper.decls ) > + return mdecl_wrapper_t( temp_decls ) > + else: > + return results > > class mdecl_wrapper_t( object ): > """Multiple declarations wrapper. > @@ -44,8 +59,14 @@ > return len( self.decls ) > > def __getitem__( self, index ): > - """provides access to declaration""" > - return self.decls[index] > + """provides access to declaration. > + If passed a standard index, then return contained decl. > + Else call the getitem method of contained decls. > + """ > + if isinstance(index, int): > + return self.decls[index] > + else: > + return call_redirector_t( '__getitem__', self.decls)(index) > > def __ensure_attribute( self, name ): > invalid_decls = filter( lambda d: not hasattr( d, name ), self.decls ) > @@ -64,4 +85,4 @@ > def __getattr__( self, name ): > """@param name: name of method > """ > - return call_redirector_t( name, self.decls ) > \ No newline at end of file > + return call_redirector_t( name, self.decls ) > Allen, can you send me the whole file? Thanks -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Roman Y. <rom...@gm...> - 2006-05-30 20:49:56
|
Allen, I tried the patch and there are some errors in unit tests. I will try to fix it tommorrow and commit. I will let you know. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Roman Y. <rom...@gm...> - 2006-05-31 04:22:10
|
On 5/30/06, Roman Yakovenko <rom...@gm...> wrote: > Allen, I tried the patch and there are some errors in unit tests. > I will try to fix it tommorrow and commit. I will let you know. 1. __getitem__ has been changed a little: def __getitem__( self, index ): """provides access to declaration. If passed a standard index, then return contained decl. Else call the getitem method of contained decls. """ if isinstance(index, ( int, slice ) ): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ return self.decls[index] else: return call_redirector_t( '__getitem__', self.decls)(index) slice has been added. But still patch does not work: class X{ X(){} }; global_ns['X'].meber_functions() Will raise an error: AttributeError: 'constructor_t' object has no attribute '__getitem__' The query breaks precondition of call_redirector_t.__call__ : I assume that all functions will return same type We don't have list of same objects. So mdecl_wrapper_t.__getitem__ can not return call_redirector_t( '__getitem__', self.decls)(index) :-(. Without good definition I don't know how to fix this. So, if you don't mind I will not apply the patch. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: Allen B. <al...@vr...> - 2006-05-31 14:11:21
|
Roman Yakovenko wrote: > On 5/30/06, Roman Yakovenko <rom...@gm...> wrote: > >> Allen, I tried the patch and there are some errors in unit tests. >> I will try to fix it tommorrow and commit. I will let you know. > > > 1. __getitem__ has been changed a little: > > def __getitem__( self, index ): > """provides access to declaration. > If passed a standard index, then return contained decl. > Else call the getitem method of contained decls. > """ > if isinstance(index, ( int, slice ) ): > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > return self.decls[index] > else: > return call_redirector_t( '__getitem__', self.decls)(index) > > slice has been added. > > But still patch does not work: > > class X{ X(){} }; > > global_ns['X'].meber_functions() > > Will raise an error: AttributeError: 'constructor_t' object has no > attribute '__getitem__' I would have to look into this further, but what is calling __getitem__ on a constructor_t object? It looks like __getitem__ is being called on a namespace, but that should be allowed since a namespace is a scopedef_t. > The query breaks precondition of > call_redirector_t.__call__ : I assume that all functions will return > same type > We don't have list of same objects. So mdecl_wrapper_t.__getitem__ can > not > return call_redirector_t( '__getitem__', self.decls)(index) :-(. > Maybe the precondition should be modified slightly. Maybe the precondition should be that all objects returned can be wrapped with in a mdecl. So the preconditions would be the same as those for creating an mdecl. And unless I am missing something, an mdecl can wrap objects of different types. For example a call like: mfs = my_class.member_functions() Will return an mdecl that wraps constructors, calldefs, and any other types of members. -Allen > Without good definition I don't know how to fix this. So, if you don't > mind I will not apply > the patch. > |
From: Roman Y. <rom...@gm...> - 2006-05-31 17:46:52
|
On 5/31/06, Allen Bierbaum <al...@vr...> wrote: > > class X{ X(){} }; > > > > global_ns['X'].meber_functions() > > > > Will raise an error: AttributeError: 'constructor_t' object has no > > attribute '__getitem__' > > I would have to look into this further, but what is calling __getitem__ > on a constructor_t object? call_redirector_t.__call__, because: global_ns['X'] is equivalent to get all declarations that have name 'X' class and its constructors match the query I suggest you to debug small example and see what happens. > > The query breaks precondition of > > call_redirector_t.__call__ : I assume that all functions will return > > same type > > We don't have list of same objects. So mdecl_wrapper_t.__getitem__ can > > not > > return call_redirector_t( '__getitem__', self.decls)(index) :-(. > > > Maybe the precondition should be modified slightly. Maybe the > precondition should be that all objects returned can be wrapped with in > a mdecl. So the preconditions would be the same as those for creating > an mdecl. And unless I am missing something, an mdecl can wrap objects > of different types. > > For example a call like: > > mfs = my_class.member_functions() > > Will return an mdecl that wraps constructors, calldefs, and any other > types of members. This is how it works right now. The main problem is how to define precondition. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |