If a couple people could review this (it should be fast), I opened the following PR:
https://github.com/apache/cloudstack/pull/1528 Thanks! Mike ________________________________________ From: Tutkowski, Mike Sent: Sunday, May 1, 2016 7:16 PM To: dev@cloudstack.apache.org Subject: Re: Python Question (with regards to Marvin) "A bunch of UI scripts use those class methods (I didn't see us trying to use the instance methods anywhere)." I meant that a bunch of test scripts use those methods (not UI scripts). > On May 1, 2016, at 5:24 PM, Tutkowski, Mike <mike.tutkow...@netapp.com> wrote: > > 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 >>