Replacing / Mocking all new instances of class - python

I have the following situation.
class Class1():
def __init__(self, param1):
self.param = param1
def my_func_1(self):
return "Hello " + self.param1
class Class2():
def __init__(self):
self.instance_of_class_1 = Class1('Real')
def do_it(self):
return self.instance_of_class_1.my_func_1()
class Class3():
def __init__(self):
self.instace_of_class_2 = Class2()
def do_it(self):
return self.instace_of_class_2.do_it()
I have a test that initiates a Class3 object but I want to mock the new instance of Class1 inside the constructor of Class2. This is what i did so far:
def test_my_classes():
with patch('my.module.Class1') as class_1_mock:
class_1_mock.my_func_1.return_value = "Hello Fake"
class_3 = Class3()
assert class_3.do_it() == 'Hello Fake' #fails
I'm guessing because Class1 constructor takes params - its not a simple patch.

You are mocking Class1 correctly, but forgot to take into account it is called to produce an instance. The my_func_1 would be looked up on the call result (on the instance):
def test_my_classes():
with patch('my.module.Class1') as class_1_mock:
class_1_mock.return_value.my_func_1.return_value = "Hello Fake"
Mock doesn't care that you produced an instance or that my_func_1 is a bound method, only that you call Class1.
You can then make assertions if the class was called with the correct parameters, if you so desire:
class_1_mock.assert_called_once_with('Real')
Demo:
>>> from mock import patch
>>> class Class1():
... def __init__(self, param1):
... self.param = param1
... def my_func_1(self):
... return "Hello " + self.param1
...
>>> class Class2():
... def __init__(self):
... self.instance_of_class_1 = Class1('Real')
... def do_it(self):
... return self.instance_of_class_1.my_func_1()
...
>>> class Class3():
... def __init__(self):
... self.instace_of_class_2 = Class2()
... def do_it(self):
... return self.instace_of_class_2.do_it()
...
>>> with patch('__main__.Class1') as class_1_mock:
... class_1_mock.return_value.my_func_1.return_value = "Hello Fake"
... class_3 = Class3()
... print class_3.do_it() == 'Hello Fake'
...
True
>>> class_1_mock.mock_calls
[call('Real'), call().my_func_1()]
I included class_1_mock.mock_calls to show that call().my_func_1() is included; that's the Class1('Real') instance being used to provide the my_func_1() method call.

Related

python mock class instance in unittest

I do not see the actual mock object created for the class instance which I am trying to mock in the following code.
class_to_be_mocked.py
class ClassToBeMocked():
def __init__(self):
pass
def method(self):
return "abc"
class_under_test.py
class ClassUnderTest():
def __init__(self):
self.api = ClassToBeMocked()
def method(self):
return self.api.method()
test.py
class TestClass(unittest.Testcase):
def setUp(self):
with patch('class_to_be_mocked.ClassToBeMocked') as mocked_class:
self.mocked_class_instance = mocked_class.return_value
def test_method(self):
instance = ClassUnderTest()
self.mocked_class_instance.method.return_value = "abc"
instance.method()

Influencing class variables with functions that are method's variables

Say I have a class with a method that takes a function as an argument. Is there any way to make this function change inclass variables?
def f():
# something here to change MyClass.var
class MyClass:
def __init__():
self.var = 1
def method(self, func):
#does something
func()
obj = MyClass()
obj.method(f)
print(obj.var)
Simply pass the internal reference of your class - self - into the function:
>>> class Class:
def __init__(self):
self.var = 1
def method(self, func):
func(self)
>>> def func(inst):
inst.var = 0
>>> cls = Class()
>>> cls.var
1
>>> cls.method(func)
>>> cls.var
0
>>>
On a related side note, I'd argue that it'd be cleaner and clearer to actually make your function a method of your class:
>>> from types import MethodType
>>>
>>> def func(self):
self.var = 0
>>> class Class:
def __init__(self):
self.var = 1
>>> cls = Class()
>>> cls.var
1
>>> cls.func = MethodType(func, cls)
>>> cls.func()
>>> cls.var
0
>>>
This should work:
def f(obj):
obj.var = 2
class MyClass:
def __init__(self):
self.var = 1
def method(self, func):
# does something
func(self)
obj = MyClass()
obj.method(f)
print(obj.var) # --> 2
Since the function f is defined outside the scope of the class, it can not access the class variable. However you can pass the class variable as an argument to f, and in that case it will be able to do any operation on it.
def f(x):
return x**2 # just for the demonstration. Will square the existing value\\
# of the class variable
class MyClass:
def __init__(self):
self.var = 2
def method(self, func):
#does something
self.var = func(self.var)
obj = MyClass()
obj.method(f)
print(obj.var)
>>> 4

Automatically create (and keep) an object when accessed

I would like to do something like this:
class A:
def hello(): print "Hello"
# I do not want to explicitly setup a:
a = A()
# a = A() -> I want this to happen automatically when I access a
# My first try is this:
def a():
return A()
# Also, I do not want to call a as a function a(): it must be an object
# And it must stay alive and initialized
a.hello() # a is created, as object of class A
a.hello() # I do not want a second instantiation
How can I implement this? properties? cached-properties? They are only for classes: a is a module-level object.
Maybe something like this:
class A(object):
def hello(self):
print "Hello"
class LazyA(object):
def __init__(self):
self.instance = None
def __getattr__(self, k):
if self.instance is None:
self.instance = A()
return getattr(self.instance, k)
a = LazyA()
def lazyinit(cls):
class p(object):
def __init__(self, *args, **kws):
self._init = lambda: cls(*args, **kws)
self._obj = None
def __getattr__(self, k):
if not self._obj:
self._obj = self._init()
return getattr(self._obj, k)
return p
Example:
#lazyinit
class A(object):
def __init__(self, a, b):
print("initializing...")
self.x = a + b + 2
def foo(self):
return self.x
x = A(39, 1)
print x
print x.foo()
print x.foo()
Generalization of the answer by Pavel:
class LazyClass(object):
def __init__(self, myclass, *args, **kwargs):
self.instance = None
self.myclass = myclass
self.args = args
self.kwargs = kwargs
def __getattr__(self, k):
if self.instance is None:
self.instance = self.myclass(*self.args, **self.kwargs)
return getattr(self.instance, k)
class A(object):
def __init__ (self, name):
self.name = name
print "Created"
def hello(self):
print "Hello " + self.name
import unittest
class TestLazyClass(unittest.TestCase):
def setUp(self):
self.a = LazyClass(A, 'Daniel')
def test_it(self):
self.a.hello()
self.a.hello()

Decorate a class in Python by defining the decorator as a class

What is a simple example of decorating a class by defining the decorator as a class?
I'm trying to achieve what has been implemented in Python 2.6 using PEP 3129 except using classes not functions as Bruce Eckel explains here.
The following works:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
def wrappedClass(*args):
return cls(*args)
return type("TestClass", (cls,), dict(newMethod=self.newMethod, classattr=self.arg))
def newMethod(self, value):
return value * 2
#Decorator("decorated class")
class TestClass(object):
def __init__(self):
self.name = "TestClass"
print "init %s"%self.name
def TestMethodInTestClass(self):
print "test method in test class"
def newMethod(self, value):
return value * 3
Except, in the above, wrappedClass is not a class, but a function manipulated to return a class type. I would like to write the same callable as follows:
def __call__(self, cls):
class wrappedClass(cls):
def __init__(self):
... some code here ...
return wrappedClass
How would this be done?
I'm not entirely sure what goes into """... some code here ..."""
If you want to overwrite new_method(), just do it:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
class Wrapped(cls):
classattr = self.arg
def new_method(self, value):
return value * 2
return Wrapped
#Decorator("decorated class")
class TestClass(object):
def new_method(self, value):
return value * 3
If you don't want to alter __init__(), you don't need to overwrite it.
After this, the class NormalClass becomes a ClassWrapper instance:
def decorator(decor_arg):
class ClassWrapper:
def __init__(self, cls):
self.other_class = cls
def __call__(self,*cls_ars):
other = self.other_class(*cls_ars)
other.field += decor_arg
return other
return ClassWrapper
#decorator(" is now decorated.")
class NormalClass:
def __init__(self, name):
self.field = name
def __repr__(self):
return str(self.field)
Test:
if __name__ == "__main__":
A = NormalClass('A');
B = NormalClass('B');
print A
print B
print NormalClass.__class__
Output:
A is now decorated. <br>
B is now decorated. <br>
\__main__.classWrapper

How can a python base class tell whether a sub class has overridden its methods?

Here is my guess, which doesn't work:
class BaseClass(object):
def foo(self):
return 'foo'
def bar(self):
return 'bar'
def methods_implemented(self):
"""This doesn't work..."""
overriden = []
for method in ('foo', 'bar'):
this_method = getattr(self, method)
base_method = getattr(BaseClass, method)
if this_method is not base_method:
overriden.append(method)
return overriden
class SubClass(BaseClass):
def foo(self):
return 'override foo'
o = SubClass()
o.methods_implemented()
Ideally, methods_implemented() would return ['foo'].
How?
(Why would I want to do this? My base class is an HTTP Resource class which has methods GET, POST etc. By default they return 405 Method Not Implemented. It also has a method OPTIONS which should return a 200 response with the header Allow set to the methods which any subclass implements.)
Perhaps this?
>>> class BaseClass(object):
... def foo(self):
... return 'foo'
... def bar(self):
... return 'bar'
... def methods_implemented(self):
... """This does work."""
... overriden = []
... for method in ('foo', 'bar'):
... this_method = getattr(self, method)
... base_method = getattr(BaseClass, method)
... if this_method.__func__ is not base_method.__func__:
... overriden.append(method)
... return overriden
...
>>> class SubClass(BaseClass):
... def foo(self):
... return 'override foo'
...
>>> o = SubClass()
>>> o.methods_implemented()
['foo']
This checks whether the function objects behind the bound methods are the same.
Note, prior to Python 2.6, the __func__ attribute was named im_func.
The methods, even though calling the same object, are NOT the same object. You must test to see if the functions wrapped in the unbound method are the same object.
I'm using 2.6 over here, so I also changed the class to inherit from object.
>>> class BaseClass(object):
... def foo(self):
... return 'foo'
... def bar(self):
... return 'bar'
... def methods_implemented(self):
... """This doesn't work..."""
... overriden = []
... for method in ('foo', 'bar'):
... this_method = getattr(self, method).__func__
... base_method = getattr(BaseClass, method).__func__
... if this_method is base_method:
... overriden.append(method)
... return overriden
...
>>> class SubClass(BaseClass):
... def foo(self):
... return 'override foo'
...
>>> o = SubClass()
>>> o.methods_implemented()
['bar']

Categories