So, the problem exists with both enableMaintenance and cancelMaintenance for hosts and with enableMaintenance for storage (not with cancelMaintenance for storage).
A bunch of UI scripts use those class methods (I didn't see us trying to use the instance methods anywhere). I believe those class methods exist because the test scripts already have the UUIDs of the host or storage and those class methods provide a faster means of performing the action in question (when compared to having to retrieve a host or storage object from the applicable UUID and then invoke the method on it). That being the case, I think we should just keep the class methods. ________________________________________ From: Will Stevens <williamstev...@gmail.com> Sent: Sunday, May 1, 2016 12:15 PM To: dev@cloudstack.apache.org Subject: Re: Python Question (with regards to Marvin) Ya. Let's see how prevalent the class method is to start with and we will cross that bridge after. On May 1, 2016 2:07 PM, "Tutkowski, Mike" <mike.tutkow...@netapp.com> wrote: > I was just "concerned" that those who have their own Marvin tests that are > not checked in might be broken if I don't keep the class method. > ________________________________________ > From: Will Stevens <williamstev...@gmail.com> > Sent: Sunday, May 1, 2016 12:03 PM > To: dev@cloudstack.apache.org > Subject: Re: Python Question (with regards to Marvin) > > It will be easy to grep if there class methods, so we should start there. > If not, then I agree that an instance method is probably the best way to > go. > On May 1, 2016 12:41 PM, "Tutkowski, Mike" <mike.tutkow...@netapp.com> > wrote: > > > However, from a design standpoint, I prefer the instance method here as > it > > would be nice to ask the object itself to place itself in maintenance > mode. > > > > So, it's really a question of just staying backward compatible (the class > > method) or a possibly better design (the instance method). > > ________________________________________ > > From: Tutkowski, Mike <mike.tutkow...@netapp.com> > > Sent: Sunday, May 1, 2016 10:18 AM > > To: dev@cloudstack.apache.org > > Subject: Re: Python Question (with regards to Marvin) > > > > The question then becomes, do we want to keep the instance or the class > > method? > > > > There exists the same problem for at least one other pair of methods. > > > > Since the class method is listed second in the file currently, it is the > > only one of the two that can be utilized. That being the case, we might > > just want to keep the class method and remove the instance method. > > > > > On May 1, 2016, at 5:43 AM, Will Stevens <williamstev...@gmail.com> > > wrote: > > > > > > Yep. Looking like there is a bug in that file. Thanks for testing. :) > > >> On May 1, 2016 1:40 AM, "Tutkowski, Mike" <mike.tutkow...@netapp.com> > > wrote: > > >> > > >> Here are my tests (run from http://ideone.com/). > > >> > > >> The short story is that having multiple methods with the same name > (even > > >> if one is an instance method and one is a class method) should > probably > > not > > >> be done. > > >> > > >> If you try to invoke the instance method (ex. test.run()), the last > > method > > >> by that name in the source file is invoked (which could be the class > > >> method). If the number of parameters don't match, that's an error. > > >> > > >> If you try to invoke the class method (ex. Test.run()), the last > method > > by > > >> that name in the source file is invoked. If this is not a class method > > or > > >> if the number of parameters don't match, that's an error. > > >> > > >> class Test: > > >> @classmethod > > >> def run(cls): > > >> print "class hi" > > >> > > >> def run(self): > > >> print "instance hi" > > >> > > >> test = Test() > > >> > > >> test.run() > > >> > > >> What gets printed: > > >> instance hi > > >> > > >> class Test: > > >> def run(self): > > >> print "instance hi" > > >> > > >> @classmethod > > >> def run(cls): > > >> print "class hi" > > >> > > >> test = Test() > > >> > > >> test.run() > > >> > > >> What gets printed: > > >> class hi > > >> > > >> class Test: > > >> @classmethod > > >> def run(cls): > > >> print "class hi" > > >> > > >> def run(self): > > >> print "instance hi" > > >> > > >> # test = Test() > > >> > > >> Test.run() > > >> > > >> Runtime error > > >> > > >> class Test: > > >> @classmethod > > >> def run(cls): > > >> print "class hi" > > >> > > >> # test = Test() > > >> > > >> Test.run() > > >> > > >> What gets printed: > > >> class hi > > >> > > >> class Test: > > >> def run(self): > > >> print "instance hi" > > >> > > >> @classmethod > > >> def run(cls): > > >> print "class hi" > > >> > > >> # test = Test() > > >> > > >> Test.run() > > >> > > >> What gets printed: > > >> class hi > > >> > > >> class Test: > > >> @classmethod > > >> def run(cls): > > >> print "class hi" > > >> > > >> # test = Test() > > >> > > >> Test.run() > > >> > > >> What gets printed: > > >> class hi > > >> ________________________________________ > > >> From: Tutkowski, Mike > > >> Sent: Saturday, April 30, 2016 6:58 PM > > >> To: dev@cloudstack.apache.org > > >> Subject: Re: Python Question (with regards to Marvin) > > >> > > >> I can play around with it later tonight. I'm not home at the moment. > > >> > > >> When I did invoke it as Test.run(), it invoked the class method (the > > class > > >> method was listed after the instance method for that test, so I wasn't > > >> surprised that the class method did, in fact, get executed there). > > >> > > >> What I did not try was to list the class method first, then list the > > >> instance method, and then try to invoke the class method. > > >> > > >> As mentioned in my prior e-mail, when I did try to invoke the instance > > >> version of run, it was only successful if the instance version was the > > >> second one declared in the file. If the class method was declared > > second, > > >> then it was invoked even when I was trying to invoke the instance one. > > >> > > >>>> On Apr 30, 2016, at 6:06 PM, Will Stevens <williamstev...@gmail.com > > > > >>> wrote: > > >>> > > >>> That's strange. That means the @classmethod decorator is not working. > > You > > >>> should have gotten the instance method in both cases. > > >>> > > >>> What if you don't instantiate Test and only do the following. > > >>> > > >>> Test.run() > > >>> > > >>> In both cases. > > >>> On Apr 30, 2016 6:04 PM, "Tutkowski, Mike" < > mike.tutkow...@netapp.com> > > >>> wrote: > > >>> > > >>>> I ran this with an online Python tool and it calls the class method: > > >>>> > > >>>> 1 class Test: > > >>>> 2 def run(self): > > >>>> 3 print 'instance hi' > > >>>> 4 > > >>>> 5 @classmethod > > >>>> 6 def run(cls): > > >>>> 7 print 'class hi' > > >>>> 8 > > >>>> 9 test = Test() > > >>>> 10 > > >>>> 11 test.run() > > >>>> > > >>>> If I reverse the order of the methods, the instance method is > invoked: > > >>>> > > >>>> 1 class Test: > > >>>> 2 @classmethod > > >>>> 3 def run(cls): > > >>>> 4 print 'class hi' > > >>>> 5 > > >>>> 6 def run(self): > > >>>> 7 print 'instance hi' > > >>>> 8 > > >>>> 9 test = Test() > > >>>> 10 > > >>>> 11 test.run() > > >>>> > > >>>> As I suspected, I think this means we have a problem in base.py. > > >>>> ________________________________________ > > >>>> From: Will Stevens <williamstev...@gmail.com> > > >>>> Sent: Saturday, April 30, 2016 1:46 PM > > >>>> To: dev@cloudstack.apache.org > > >>>> Subject: Re: Python Question (with regards to Marvin) > > >>>> > > >>>> I am on my phone so I have not been able to research this for you. I > > >> think > > >>>> you are right for the most part. Instead of multiple methods, > python > > >> kind > > >>>> of fakes overloading by being to have named function arguments which > > can > > >>>> have default values, so you can call the method with a dynamic > number > > of > > >>>> arguments making it appear like you are overloading, but you are > > >> actually > > >>>> calling the same function. > > >>>> > > >>>> I think in this case the two methods are actually in different > scopes > > >> (even > > >>>> though they are next to each other). The decorator actually wraps > the > > >>>> method, so I believe in the actual runtime the to methods are in > > >> different > > >>>> scopes. > > >>>> > > >>>> I would have to look into this more to know for sure. I am taking a > > few > > >>>> minute break from building garden boxes right now. :) > > >>>> On Apr 30, 2016 3:31 PM, "Tutkowski, Mike" < > mike.tutkow...@netapp.com > > > > > >>>> wrote: > > >>>> > > >>>>> Will - You can override a method in Python, but can you overload > it? > > >> > > > http://stackoverflow.com/questions/10202938/how-do-i-use-method-overloading-in-python > > >>>>> > > >>>>>>> On Apr 30, 2016, at 6:23 AM, Will Stevens < > > williamstev...@gmail.com> > > >>>>>> wrote: > > >>>>>> > > >>>>>> Here is a pretty good explanation. > > >> > > > http://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python > > >>>>>> > > >>>>>> I am guessing that both exist because the function is called both > > with > > >>>> a > > >>>>>> host instance and with the class itself. > > >>>>>> > > >>>>>> Class instance example: `h.enableMaintenance(client)` > > >>>>>> > > >>>>>> Class example: `Host.enableMaintenance(client, 1)` > > >>>>>> > > >>>>>> In both cases the first parameter is implicitly `h` and `Host` > > >>>>>> respectively. > > >>>>>> > > >>>>>> I am not sure why we need both (because I am not familiar with how > > >> this > > >>>>>> code is called), but method overloading is definitely valid in > > python. > > >>>>>> > > >>>>>> On Apr 30, 2016 1:08 AM, "Tutkowski, Mike" < > > mike.tutkow...@netapp.com > > >>> > > >>>>>> wrote: > > >>>>>>> > > >>>>>>> Hi everyone, > > >>>>>>> > > >>>>>>> > > >>>>>>> I received an error when trying to invoke the instance version of > > >>>>>> enableMaintenance (below). > > >>>>>>> > > >>>>>>> > > >>>>>>> 'TypeError: enableMaintenance() takes exactly 3 arguments (2 > > >>>> given)\n'] > > >>>>>>> > > >>>>>>> > > >>>>>>> I looked at base.py and it has the following with regards to > > >>>> maintenance > > >>>>>> mode for hosts: > > >>>>>>> > > >>>>>>> > > >>>>>>> def enableMaintenance(self, apiclient): > > >>>>>>> > > >>>>>>> """enables maintenance mode Host""" > > >>>>>>> > > >>>>>>> > > >>>>>>> cmd = > prepareHostForMaintenance.prepareHostForMaintenanceCmd() > > >>>>>>> > > >>>>>>> cmd.id = self.id > > >>>>>>> > > >>>>>>> return apiclient.prepareHostForMaintenance(cmd) > > >>>>>>> > > >>>>>>> > > >>>>>>> @classmethod > > >>>>>>> > > >>>>>>> def enableMaintenance(cls, apiclient, id): > > >>>>>>> > > >>>>>>> """enables maintenance mode Host""" > > >>>>>>> > > >>>>>>> > > >>>>>>> cmd = > prepareHostForMaintenance.prepareHostForMaintenanceCmd() > > >>>>>>> > > >>>>>>> cmd.id = id > > >>>>>>> > > >>>>>>> return apiclient.prepareHostForMaintenance(cmd) > > >>>>>>> > > >>>>>>> > > >>>>>>> Now, I definitely have a lot more Java experience than Python, > but > > - > > >>>> as > > >>>>>> far as I know - having two methods with the same name such as this > > >>>> (even > > >>>>> if > > >>>>>> one is an instance method and the other is a class method) is not > > >>>> really > > >>>>>> "permitted" in Python. > > >>>>>>> > > >>>>>>> > > >>>>>>> I mean, technically it's permitted, but the second one will > > override > > >>>> the > > >>>>>> first one. > > >>>>>>> > > >>>>>>> > > >>>>>>> Can any of our Python people comment on this? > > >>>>>>> > > >>>>>>> > > >>>>>>> I was thinking I'd remove the class method (assuming my knowledge > > >> here > > >>>>>> regarding this topic is correct). > > >>>>>>> > > >>>>>>> > > >>>>>>> Thanks! > > >>>>>>> > > >>>>>>> Mike > > >> > > >