Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #14987 > unrolled thread

Re: Strange classmethod mock behavior

Started byFabio Zadrozny <fabiofz@gmail.com>
First post2011-10-25 20:59 -0200
Last post2011-10-25 20:59 -0200
Articles 1 — 1 participant

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Strange classmethod mock behavior Fabio Zadrozny <fabiofz@gmail.com> - 2011-10-25 20:59 -0200

#14987 — Re: Strange classmethod mock behavior

FromFabio Zadrozny <fabiofz@gmail.com>
Date2011-10-25 20:59 -0200
SubjectRe: Strange classmethod mock behavior
Message-ID<mailman.2218.1319583589.27778.python-list@python.org>
On Tue, Oct 25, 2011 at 10:08 AM, Peter Otten <__peter__@web.de> wrote:
> Fabio Zadrozny wrote:
>
>> I'm trying to mock a classmethod in a superclass but when restoring it
>> a strange behavior happens in subclasses (tested on Python 2.5)
>>
>> Anyone knows why this happens? (see test case below for details)
>> Is there any way to restore that original method to have the original
>> behavior?
>>
>> import unittest
>>
>> class Test(unittest.TestCase):
>>
>>     def testClassmethod(self):
>>         class Super():
>>             @classmethod
>>             def GetCls(cls):
>>                 return cls
>>
>>         class Sub(Super):
>>             pass
>>
>>         self.assertEqual(Sub.GetCls(), Sub)
>>
>>         original = Super.GetCls
>>         #Mock Super.GetCls, and do tests...
>>         Super.GetCls = original #Restore the original classmethod
>>         self.assertEqual(Sub.GetCls(), Sub) #The call to the
>> classmethod subclass returns the cls as Super and not Sub as expected!
>>
>> if __name__ == '__main__':
>>     unittest.main()
>
> [Not related to your problem] When working with descriptors it's a good idea
> to use newstyle classes, i. e. have Super inherit from object.
>
> The Super.GetCls attribute access is roughly equivalent to
>
> Super.__dict___["GetCls"].__get__(classmethod_instance, None, Super)
>
> and returns an object that knows about its class. So when you think you are
> restoring the original method you are actually setting the GetCls attribute
> to something else. You can avoid the problem by accessing the attribute
> explicitly:
>
>>>> class Super(object):
> ...     @classmethod
> ...     def m(cls): return cls
> ...
>>>> bad = Super.m
>>>> good = Super.__dict__["m"]
>>>> class Sub(Super): pass
> ...
>>>> Sub.m()
> <class '__main__.Sub'>
>>>> Super.m = bad
>>>> Sub.m()
> <class '__main__.Super'>
>>>> Super.m = good
>>>> Sub.m()
> <class '__main__.Sub'>
>

Hi Peter, thanks for the explanation.

Printing it helped me understand it even better...

print(Super.__dict__['GetCls'])
print(Super.GetCls)

<classmethod object at 0x022AF210>
<bound method type.GetCls of <class '__main__.Super'>>

Cheers,

Fabio

[toc] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web