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


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

Re: Strange classmethod mock behavior

Started byPeter Otten <__peter__@web.de>
First post2011-10-25 14:08 +0200
Last post2011-10-25 14:08 +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 Peter Otten <__peter__@web.de> - 2011-10-25 14:08 +0200

#14962 — Re: Strange classmethod mock behavior

FromPeter Otten <__peter__@web.de>
Date2011-10-25 14:08 +0200
SubjectRe: Strange classmethod mock behavior
Message-ID<mailman.2205.1319544480.27778.python-list@python.org>
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'>

[toc] | [standalone]


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


csiph-web