I'm trying to build a nice base around py.test
Some of our tests needs certain test data to work.
Today we just specify a mock object as a function argument and do the setup in the generator, this is clearly not desirable.
Here is an example of how it could look today:
def test_something(self, some_data):
# some_data is unused in the test
I'd like to do something like this:
#uses_some_data
def test_something(self):
# The data is loaded when the test is run
Though I have not figured out how to do this properly.
I cannot use class setup because I want the data to be persistant over the entire session, not setup/torn down on every test class.
My first idea was to still use funcargs but instead of letting the test have the funcarg we let the decorator request the funcarg for the function, basically hiding the ugliness.
The problem with this is that I need a py.test object to request a funcarg.
Is there any way I can get such an object or is this the wrong approach all together?
It would be an awesome bonus if the data did not have to be loaded if none of the collected tests requires the data, this is the downside of using decorators seeing as they are always run no matter if the test will be run or not.
Here is something that may work as-is, and if not will hopefully point you in the right direction.
class TestData(object):
def __getattr__(self, name):
if name not in ('data1', 'data2', 'data3'):
raise AttributeError("TestData has no %s" % name)
if name == 'data1':
result = self._generate_data('data1')
setattr(self.__class__, name, result)
elif name == 'data2':
result = self._generate_data('data2')
setattr(self.__class__, name, result)
elif name == 'data3':
result = self._generate_data('data3')
setattr(self.__class__, name, result)
return result
def _generate_data(self, data_name):
return data_name * int(data_name[-1])
The TestData class uses the __getattr__ method to generate the data as it is needed, and by saving the generated date back to the class (not the instance!), the data is kept around for future use as well.
class uses_some_data(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
global test_data
test_data = TestData()
return self.func(*args, **kwargs)
A simple decorator to set the global name binding for test_data. In fact, this version of the decorator is so simple it can be easily replaced with a module level name binding of test_data = TestData().
#uses_some_data
def testing_test():
print(test_data.data2)
And a test function.
If you don't like the global level of test_data you could get fancier with the decorator and assign test_data to the function itself:
class uses_some_data(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
self.func.test_data = TestData()
return self.func(*args, **kwargs)
In this case, make sure your testing functions reference themselves
#uses_some_data
def testing_test():
print(testing_test.test_data.data2)
After playing around some I found that this works:
def pytest_funcarg__some_data(request):
def create():
# Load the test data here
print 'Test data loaded'
return request.cached_setup(
setup=create,
scope='session',
extrakey='some_data'
)
def uses_some_data(func):
# The funcarg is actually requested here
def wrapper(self, some_data):
return func
return wrapper
class TestSomething(object):
#uses_some_data
def test_something(self):
# "Some data" is now available
pass
Related
I have a python 2.7x Tornado application that when run serves up a handful of RESTful api endpoints.
My project folder includes numerous test cases that rely on the python mock module such as shown below.
from tornado.testing import AsyncHTTPTestCase
from mock import Mock, patch
import json
from my_project import my_model
class APITestCases(AsyncHTTPTestCase):
def setUp(self):
pass
def tearDown(self):
pass
#patch('my_project.my_model.my_method')
def test_something(
self,
mock_my_method
):
response = self.fetch(
path='http://localhost/my_service/my_endpoint',
method='POST',
headers={'Content-Type': 'application/json'},
body=json.dumps({'hello':'world'})
)
The RESTful endpoint http://localhost/my_service/my_endpoint has two internal calls to my_method respectively: my_method(my_arg=1) and my_method(my_arg=2).
I want to mock out my_method in this test-case such that it returns 0 if it is called with my_arg==2, but otherwise it should return what it would always normally return. How can I do it?
I know that I should do something like this:
mock_my_method.return_value = SOMETHING
But I don't know how to properly specify that something so that its behavior is conditional on the arguments that my_method is called with. Can someone show me or point me to an example??
I want to mock out my_method in this test-case such that it returns 0 if it is called with my_arg==2, but otherwise it should return what it would always normally return. How can I do it?
Write your own method mock calling the original one on condition:
from my_project import my_model
my_method_orig = my_project.my_model.my_method
def my_method_mocked(self, *args, my_arg=1, **kwargs):
if my_arg == 2: # fake call
return 0
# otherwise, dispatch to real method
return my_method_orig(self, *args, **kwargs, my_arg=my_arg)
For patching: if you don't need to assert how often the mocked method was called and with what args etc, it is sufficient to pass the mock via new argument:
#patch('my_project.my_model.my_method', new=my_method_mocked)
def test_something(
self,
mock_my_method
):
response = self.fetch(...)
# this will not work here:
mock_my_method.assert_called_with(2)
If you want to invoke the whole mock assertion machinery, use side_effect as suggested in the other answer. Example:
#patch('my_project.my_model.my_method', side_effect=my_method_mocked, autospec=True)
def test_something(
self,
mock_my_method
):
response = self.fetch(...)
# mock is assertable here
mock_my_method.assert_called_with(2)
you could use side_effect to change return value dynamically:
class C:
def foo(self):
pass
def drive():
o = C()
print(o.foo(my_arg=1))
print(o.foo(my_arg=2))
def mocked_foo(*args, **kwargs):
if kwargs.get('my_arg') == 2:
return 0
else:
return 1
#patch('__main__.C.foo')
def test(mock):
mock.side_effect = mocked_foo
drive()
update: as you want to run original my_method code under some condition, you may need a method proxy, Mock can't get back the real function object being patched.
from unittest.mock import patch
class MyClass:
def my_method(self, my_arg):
return 10000
def func_wrapper(func):
def wrapped(*args, **kwargs):
my_arg = kwargs.get('my_arg')
if my_arg == 2:
return 0
return func(*args, **kwargs)
return wrapped
def drive(o, my_arg):
print('my_arg', my_arg, 'ret', o.my_method(my_arg=my_arg))
def test():
with patch.object(MyClass, 'my_method', new=func_wrapper(MyClass.my_method)):
o = MyClass()
drive(o, 1)
drive(o, 2)
will outputs:
my_arg 1 ret 10000
my_arg 2 ret 0
I have this class:
class SomeClass(object):
def __init__(self):
self.cache = {}
def check_cache(method):
def wrapper(self):
if method.__name__ in self.cache:
print('Got it from the cache!')
return self.cache[method.__name__]
print('Got it from the api!')
self.cache[method.__name__] = method(self)
return self.cache[method.__name__]
return wrapper
#check_cache
def expensive_operation(self):
return get_data_from_api()
def get_data_from_api():
"This would call the api."
return 'lots of data'
The idea is that I can use the #check_cache decorator to keep the expensive_operation method from calling an api additional times if the result is already cached.
This works fine, it seems.
>>> sc.expensive_operation()
Got it from the api!
'lots of data'
>>> sc.expensive_operation()
Got it from the cache!
'lots of data'
But I would love to be able to test it with another decorator:
import unittest
class SomeClassTester(SomeClass):
def counted(f):
def wrapped(self, *args, **kwargs):
wrapped.calls += 1
return f(self, *args, **kwargs)
wrapped.calls = 0
return wrapped
#counted
def expensive_operation(self):
return super().expensive_operation()
class TestSomeClass(unittest.TestCase):
def test_api_is_only_called_once(self):
sc = SomeClassTester()
sc.expensive_operation()
self.assertEqual(sc.expensive_operation.calls, 1) # is 1
sc.expensive_operation()
self.assertEqual(sc.expensive_operation.calls, 1) # but this goes to 2
unittest.main()
The problem is that the counted decorator counts the number of times the wrapper function is called, not this inner function.
How do I count that from SomeClassTester?
There's no easy way to do this. Your current test applies the decorators in the wrong order. You want check_cache(counted(expensive_operation)), but you're getting the counted decorator on the outside instead: counted(check_cache(expensive_operation)).
There's no easy way to fix this within the counted decorator, because by the time it gets called, the original function is already wrapped up by the check_cache decorator, and there's no easy way to change the wrapper (it holds its reference to the original function in a closure cell, which is read-only from the outside).
One possible way to make it work is to rebuild the whole method with the decorators in the desired order. You can get a reference to the original method from the closure cell:
class SomeClassTester(SomeClass):
def counted(f):
def wrapped(self, *args, **kwargs):
wrapped.calls += 1
return f(self, *args, **kwargs)
wrapped.calls = 0
return wrapped
expensive_operation = SomeClass.check_cache(
counted(SomeClass.expensive_operation.__closure__[0].cell_value)
)
This is of course far from ideal, since you need to know exactly what decorators are being applied on the method in SomeClass in order to apply them again properly. You also need to know the internals of those decorators so that you can get the right closure cell (the [0] index may not be correct if the other decorator gets changed to differently).
Another (perhaps better) approach might be to change SomeClass in such a way that you can inject your counting code in between the changed method and the expensive bit you want to count. For example, you could have the real expensive part be in _expensive_method_implementation, while the decorated expensive_method is just a simple wrapper that calls it. The test class can override the _implementation method with its own decorated version (which might even skip the actually expensive part and just return dummy data). It doesn't need to override the regular method or mess with its decorators.
It is impossible to do this, without modifying the base class to provide hooks or changing the whole decorated function in derived class based on internal knowledge of base class. Though there is a third way based on internal working of cache decorator, basically change your cache dict so that it counts
class CounterDict(dict):
def __init__(self, *args):
super().__init__(*args)
self.count = {}
def __setitem__(self, key, value):
try:
self.count[key] += 1
except KeyError:
self.count[key] = 1
return super().__setitem__(key, value)
class SomeClassTester(SomeClass):
def __init__(self):
self.cache = CounterDict()
class TestSomeClass(unittest.TestCase):
def test_api_is_only_called_once(self):
sc = SomeClassTester()
sc.expensive_operation()
self.assertEqual(sc.cache.count['expensive_operation'], 1) # is 1
sc.expensive_operation()
self.assertEqual(sc.cache.count['expensive_operation'], 1) # is 1
I'm trying to monkeypatch how pandas Panel's slicing (__getitem__). This is straightforward to do with a basic function, foo.
from pandas import Panel
Panel.__getitem__ = ORIGINAL_getitem
def newgetitem(panel, *args, **kwargs):
""" Append a string to return of panel.__getitem__"""
out = super(Panel, panel).__getitem__(*args, **kwargs)
return out+'custom stuff added'
Panel.__getitem__ = newgetitem
WhereORIGINAL_getitem is storing the original Panel method. I'm trying to extend to the case where foo() is not a function, but an instance method of an object, Foo. For example:
class Foo:
name = 'some name'
def newgetitem(self, panel, *args, **kwargs):
""" Append a string to return of panel.__getitem__,
but take attributes from self, like self.name
"""
out = super(Panel, panel).__getitem__(*args, **kwargs)
return out+'custom stuff added including name' + self.name
Foo.foo() must access the attribute self.name. Therefore, the monkeypatched function would need a reference to the Foo instance somehow, in addition to the Panel. How can I monkepatch panel with Foo.foo() and make self.name accessible?
The switching between the monkey patched function happens in another method, Foo.set_backend()
class Foo:
name = 'some name'
def foo(self):
return 'bar, called by %s' % self.name
def set_backend(self, backend):
""" Swap between new or original slicing."""
if backend != 'pandas':
Panel.__getitem__ = newgetitem
else:
Panel.__getitem__ = ORIGINAL_getitem
What I really need is for newgetitem to maintain a reference to self.
Solution Attempts
So far I've tried taking making newgetitem() a pure function, and using partial functions to pass a reference to self in. This doesn't work. Something like:
import functools
def newgetitem(foo_instance, panel, *args, **kwargs):
....
class Foo:
...
def set_backend(self, backend):
""" Swap between new or original slicing."""
if backend != 'pandas':
partialfcn = functools.partial(newgetitem, self)
Panel.__getitem__ = partialfcn
else:
Panel.__getitem__ = ORIGINAL_getitem
But this doesn't work. A reference to self is passed, but no access from the calling Panel possible. That is:
panel['50']
Passes a reference to Foo, not to Panel.
Yes, I know this is bad practice, but it's just a workaround for the time-being.
You can use patch from mock framework to handle your case. Even it is designed for testing, its primary work is monkey patching in defined contex.
Your set_backend() method could be:
def set_backend(self, backend):
if backend != 'pandas' and self._patched_get_item is None:
self._patched_get_item = patch("pandas.Panel.__getitem__", autospec=True, side_effect=self._getitem)
self._patched_get_item.start()
elif backend == 'pandas' and self._patched_get_item is not None:
self._patched_get_item.stop()
self._patched_get_item = None
That will work either when self._getitem is a method or a reference to a function.
One way to do this is to create a closure (a function with reference to names other than locals or globals). A simple closure:
def g(x):
def f():
"""f has no global or local reference to x, but can refer to the locals of the
context it was created in (also known as nonlocals)."""
return x
return f
func = g(1)
assert func() == 1
I don't have pandas on my system, but it works much the same with a dict.
class MyDict(dict):
pass
d = MyDict(a=1, b=2)
assert d['a'] == 1
class Foo:
name = 'name'
def create_getitem(fooself, cls):
def getitem(self, *args, **kwargs):
out = super(cls, self).__getitem__(*args, **kwargs)
return out, 'custom', fooself.name
# Above references fooself, a name that is not defined locally in the
# function, but as part of the scope the function was created in.
return getitem
MyDict.__getitem__ = Foo().create_getitem(MyDict)
assert d['a'] == (1, 'custom', Foo.name)
print(d['a'])
The basics of monkey patching are straightforward but it can quickly become tricky and subtle, especially if you're aiming at finding a solution that would work for both Python 2 and Python 3.
Furthermore, quickly hacked solutions are usually not very readable/maintenable, unless you manage to wrap the monkey patching logic nicely.
That's why I invite you to have a look at a library that I wrote especially for this purpose. It is named Gorilla and you can find it on GitHub.
In short, it provides a cool set of features, it has a wide range of unit tests, and it comes with a fancy doc that should cover everything you need to get started. Make sure to also check the FAQ!
I am having trouble thinking of a way that's good python and consistent with oop principles as I've been taught to figure out how to create a family of related method decorators in python.
The mutually inconsistent goals seem to be that I want to be able to access both decorator attributes AND attributes of the instance on which the decorated method is bound. Here's what I mean:
from functools import wraps
class AbstractDecorator(object):
"""
This seems like the more natural way, but won't work
because the instance to which the wrapped function
is attached will never be in scope.
"""
def __new__(cls,f,*args,**kwargs):
return wraps(f)(object.__new__(cls,*args,**kwargs))
def __init__(decorator_self, f):
decorator_self.f = f
decorator_self.punctuation = "..."
def __call__(decorator_self, *args, **kwargs):
decorator_self.very_important_prep()
return decorator_self.f(decorator_self, *args, **kwargs)
class SillyDecorator(AbstractDecorator):
def very_important_prep(decorator_self):
print "My apartment was infested with koalas%s"%(decorator_self.punctuation)
class UsefulObject(object):
def __init__(useful_object_self, noun):
useful_object_self.noun = noun
#SillyDecorator
def red(useful_object_self):
print "red %s"%(useful_object_self.noun)
if __name__ == "__main__":
u = UsefulObject("balloons")
u.red()
which of course produces
My apartment was infested with koalas...
AttributeError: 'SillyDecorator' object has no attribute 'noun'
Note that of course there is always a way to get this to work. A factory with enough arguments, for example, will let me attach methods to some created instance of SillyDecorator, but I was kind of wondering whether there is a reasonable way to do this with inheritance.
#miku got the key idea of using the descriptor protocol. Here is a refinement that keeps the decorator object separate from the "useful object" -- it doesn't store the decorator info on the underlying object.
class AbstractDecorator(object):
"""
This seems like the more natural way, but won't work
because the instance to which the wrapped function
is attached will never be in scope.
"""
def __new__(cls,f,*args,**kwargs):
return wraps(f)(object.__new__(cls,*args,**kwargs))
def __init__(decorator_self, f):
decorator_self.f = f
decorator_self.punctuation = "..."
def __call__(decorator_self, obj_self, *args, **kwargs):
decorator_self.very_important_prep()
return decorator_self.f(obj_self, *args, **kwargs)
def __get__(decorator_self, obj_self, objtype):
return functools.partial(decorator_self.__call__, obj_self)
class SillyDecorator(AbstractDecorator):
def very_important_prep(decorator_self):
print "My apartment was infested with koalas%s"%(decorator_self.punctuation)
class UsefulObject(object):
def __init__(useful_object_self, noun):
useful_object_self.noun = noun
#SillyDecorator
def red(useful_object_self):
print "red %s"%(useful_object_self.noun)
>>> u = UsefulObject("balloons")
... u.red()
My apartment was infested with koalas...
red balloons
The descriptor protocol is the key here, since it is the thing that gives you access to both the decorated method and the object on which it is bound. Inside __get__, you can extract the useful object identity (obj_self) and pass it on to the __call__ method.
Note that it's important to use functools.partial (or some such mechanism) rather than simply storing obj_self as an attribute of decorator_self. Since the decorated method is on the class, only one instance of SillyDecorator exists. You can't use this SillyDecorator instance to store useful-object-instance-specific information --- that would lead to strange errors if you created multiple UsefulObjects and accessed their decorated methods without immediately calling them.
It's worth pointing out, though, that there may be an easier way. In your example, you're only storing a small amount of information in the decorator, and you don't need to change it later. If that's the case, it might be simpler to just use a decorator-maker function: a function that takes an argument (or arguments) and returns a decorator, whose behavior can then depend on those arguments. Here's an example:
def decoMaker(msg):
def deco(func):
#wraps(func)
def wrapper(*args, **kwargs):
print msg
return func(*args, **kwargs)
return wrapper
return deco
class UsefulObject(object):
def __init__(useful_object_self, noun):
useful_object_self.noun = noun
#decoMaker('koalas...')
def red(useful_object_self):
print "red %s"%(useful_object_self.noun)
>>> u = UsefulObject("balloons")
... u.red()
koalas...
red balloons
You can use the decoMaker ahead of time to make a decorator to reuse later, if you don't want to retype the message every time you make the decorator:
sillyDecorator = decoMaker("Some really long message about koalas that you don't want to type over and over")
class UsefulObject(object):
def __init__(useful_object_self, noun):
useful_object_self.noun = noun
#sillyDecorator
def red(useful_object_self):
print "red %s"%(useful_object_self.noun)
>>> u = UsefulObject("balloons")
... u.red()
Some really long message about koalas that you don't want to type over and over
red balloons
You can see that this is much less verbose than writing a whole class inheritance tree for different kinds of decoratorts. Unless you're writing super-complicated decorators that store all sorts of internal state (which is likely to get confusing anyway), this decorator-maker approach might be an easier way to go.
Adapted from http://metapython.blogspot.de/2010/11/python-instance-methods-how-are-they.html. Note that this variant sets attributes on the target instance, hence, without checks, it is possible to overwrite target instance attributes. The code below does not contain any checks for this case.
Also note that this example sets the punctuation attribute explicitly; a more general class could auto-discover it's attributes.
from types import MethodType
class AbstractDecorator(object):
"""Designed to work as function or method decorator """
def __init__(self, function):
self.func = function
self.punctuation = '...'
def __call__(self, *args, **kw):
self.setup()
return self.func(*args, **kw)
def __get__(self, instance, owner):
# TODO: protect against 'overwrites'
setattr(instance, 'punctuation', self.punctuation)
return MethodType(self, instance, owner)
class SillyDecorator(AbstractDecorator):
def setup(self):
print('[setup] silly init %s' % self.punctuation)
class UsefulObject(object):
def __init__(self, noun='cat'):
self.noun = noun
#SillyDecorator
def d(self):
print('Hello %s %s' % (self.noun, self.punctuation))
obj = UsefulObject()
obj.d()
# [setup] silly init ...
# Hello cat ...
I'd like to provide the capability for users of one of my modules to extend its capabilities by providing an interface to call a user's function. For example, I want to give users the capability to be notified when an instance of a class is created and given the opportunity to modify the instance before it is used.
The way I've implemented it is to declare a module-level factory function that does the instantiation:
# in mymodule.py
def factory(cls, *args, **kwargs):
return cls(*args, **kwargs)
Then when I need an instance of a class in mymodule, I do factory(cls, arg1, arg2) rather than cls(arg1, arg2).
To extend it, a programmer would write in another module a function like this:
def myFactory(cls, *args, **kwargs):
instance = myFactory.chain(cls, *args, **kwargs)
# do something with the instance here if desired
return instance
Installation of the above callback looks like this:
myFactory.chain, mymodule.factory = mymodule.factory, myFactory
This seems straightforward enough to me, but I was wondering if you, as a Python programmer, would expect a function to register a callback rather than doing it with an assignment, or if there were other methods you would expect. Does my solution seem workable, idiomatic, and clear to you?
I am looking to keep it as simple as possible; I don't think most applications will actually need to chain more than one user callback, for example (though unlimited chaining comes "for free" with the above pattern). I doubt they will need to remove callbacks or specify priorities or order. Modules like python-callbacks or PyDispatcher seem to me like overkill, especially the latter, but if there are compelling benefits to a programmer working with my module, I'm open to them.
Taking aaronsterling's idea a bit further:
class C(object):
_oncreate = []
def __new__(cls):
return reduce(lambda x, y: y(x), cls._oncreate, super(C, cls).__new__(cls))
#classmethod
def oncreate(cls, func):
cls._oncreate.append(func)
c = C()
print hasattr(c, 'spew')
#C.oncreate
def spew(obj):
obj.spew = 42
return obj
c = C()
print c.spew
Combining Aaron's idea of using a decorator and Ignacio's idea of a class that maintains a list of attached callbacks, plus a concept borrowed from C#, I came up with this:
class delegate(object):
def __init__(self, func):
self.callbacks = []
self.basefunc = func
def __iadd__(self, func):
if callable(func):
self.__isub__(func)
self.callbacks.append(func)
return self
def callback(self, func):
if callable(func):
self.__isub__(func)
self.callbacks.append(func)
return func
def __isub__(self, func):
try:
self.callbacks.remove(func)
except ValueError:
pass
return self
def __call__(self, *args, **kwargs):
result = self.basefunc(*args, **kwargs)
for func in self.callbacks:
newresult = func(result)
result = result if newresult is None else newresult
return result
Decorating a function with #delegate allows other functions to be "attached" to it.
#delegate
def intfactory(num):
return int(num)
Functions can be added to the delegate with += (and removed with -=). You can also decorate with funcname.callback to add a callback function.
#intfactory.callback
def notify(num):
print "notify:", num
def increment(num):
return num+1
intfactory += increment
intfactory += lambda num: num * 2
print intfactory(3) # outputs 8
Does this feel Pythonic?
I might use a decorator so that the user could just write.
#new_factory
def myFactory(cls, *args, **kwargs):
instance = myFactory.chain(cls, *args, **kwargs)
# do something with the instance here if desired
return instance
Then in your module,
import sys
def new_factory(f):
mod = sys.modules[__name__]
f.chain = mod.factory
mod.factory = f
return f