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


Groups > comp.lang.python > #14962

Re: Strange classmethod mock behavior

From Peter Otten <__peter__@web.de>
Subject Re: Strange classmethod mock behavior
Date 2011-10-25 14:08 +0200
Organization None
References <CANXBEFpDykfb2j0VxZCLwm1HP3KUDBfyN_fHTOa2Wt=UknT7Zw@mail.gmail.com>
Newsgroups comp.lang.python
Message-ID <mailman.2205.1319544480.27778.python-list@python.org> (permalink)

Show all headers | View raw


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'>

Back to comp.lang.python | Previous | Next | Find similar | Unroll thread


Thread

Re: Strange classmethod mock behavior Peter Otten <__peter__@web.de> - 2011-10-25 14:08 +0200

csiph-web