Python: decorator for mocking gettext during testing - python

I'm writing a Django app, and I wanted to write a decorator that will mock the _() function during testing, just adding '_translated' after the string to translate
I basically have my decorator to replace the following instruction within my test:
with mock.patch('module_which_is_being_tested._', lambda s: s+'_translated'):

I didn't find anything similar on the web, so I'm sharing it:
from unittest import mock
import functools
def mock_translation(tested_object):
"""
A decorator that mock the '_()' function during testing
just adds '_translated' after the string to translate
the class/function being tested needs to be passed as parameter
Use:
from my_module.sub_module import my_function_to_be_tested
#mock_translation(my_function_to_be_tested)
def test_my_function_to_be_tested():
pass
"""
def actual_decorator(func):
#functools.wraps(func)
def wrapper(*args, **kwargs):
module_name = tested_object.__module__
tested_obj = tested_object
breakpoint()
import_path = module_name + '._'
# with mock.patch('battletech.models._', lambda s: s+'_translated'):
with mock.patch(import_path, lambda s: s+'_translated'):
value = func(*args, **kwargs)
return value
return wrapper
return actual_decorator

Related

How to decorate a method that belongs to another class in my current class?

We have an internal library that returns a kafka consumer object. What I want to do is implement a decorator which uses this object to start the consumer (the method to start the consumer also comes from that internal library). The aim is to import this decorator and use it for any method which needs the consumer to be started before execution. Here's a snippet from a file say, utils.py:
from internal_library import KafkaMsgConsumer
class KafkaMessageConsumer(object):
def __init__(self, topic_name, kafka_host, kafka_port='some_port'):
self.topic_name = topic_name
self.kafka_host = kafka_host
self.kafka_port = kafka_port
self.consumer = KafkaMsgConsumer(kafka_host_name=(str(self.kafka_host) + ":" + str(self.kafka_port)),
topic_name=self.topic_name)
def consumer_required(self):
def decorator():
consumer = self.consumer.start_consumer()
return consumer
return decorator
Then there's my main script where I want to use this decorator. Contents from script.py:
mes = KafkaMessageConsumer(topic_name='some_topic', kafka_host='some_host',
kafka_port='some_port')
#mes.consumer_required()
def post_act():
''' some processing goes here before which I require the consumer to be started'''
import functools
def consumer_required(self):
def decorator(func):
#functools.wraps(func)
def wrapper(*args, **kwargs):
self.consumer.start_consumer()
return func(*args, **kwargs)
return wrapper
return decorator
Your decorator needs to accept the decorated function as an argument and you need to return a corresponding wrapper:
from functools import wraps
def consumer_required(self):
def decorator(func):
#wraps(func)
def wrapper(*args, **kwargs):
self.consumer.start_consumer()
return func(*args, **kwargs)
return wrapper
return decorator
Alternatively you can also inject the consumer into the decorated function via
kwargs.update(consumer=self.consumer.start_consumer())

Python: How do you intercept a method call to change function parameters?

What I am trying to do is write a wrapper around another module so that I can transform the parameters that are being passed to the methods of the other module. That was fairly confusing, so here is an example:
import somemodule
class Wrapper:
def __init__(self):
self.transforms = {}
self.transforms["t"] = "test"
# This next function is the one I want to exist
# Please understand the lines below will not compile and are not real code
def __intercept__(self, item, *args, **kwargs):
if "t" in args:
args[args.index("t")] = self.transforms["t"]
return somemodule.item(*args, **kwargs)
The goal is to allow users of the wrapper class to make simplified calls to the underlying module without having to rewrite all of the functions in the module. So in this case if somemodule had a function called print_uppercase then the user could do
w = Wrapper()
w.print_uppercase("t")
and get the output
TEST
I believe the answer lies in __getattr__ but I'm not totally sure how to use it for this application.
__getattr__ combined with defining a function on the fly should work:
# somemodule
def print_uppercase(x):
print(x.upper())
Now:
from functools import wraps
import somemodule
class Wrapper:
def __init__(self):
self.transforms = {}
self.transforms["t"] = "test"
def __getattr__(self, attr):
func = getattr(somemodule, attr)
#wraps(func)
def _wrapped(*args, **kwargs):
if "t" in args:
args = list(args)
args[args.index("t")] = self.transforms["t"]
return func(*args, **kwargs)
return _wrapped
w = Wrapper()
w.print_uppercase('Hello')
w.print_uppercase('t')
Output:
HELLO
TEST
I would approach this by calling the intercept method, and entering the desired method to execute, as a parameter for intercept. Then, in the intercept method, you can search for a method with that name and execute it.
Since your Wrapper object doesn't have any mutable state, it'd be easier to implement without a class. Example wrapper.py:
def func1(*args, **kwargs):
# do your transformations
return somemodule.func1(*args, **kwargs)
Then call it like:
import wrapper as w
print w.func1('somearg')

Mock python decorator in unit tests

I am trying to test a function that is decorated. Is there a way to mock a decorator and test function in isolation, when decorator is already applied?
import mock
def decorator(func):
def wrapper(*args, **kwargs):
return 1
return wrapper
def mocked(func):
def wrapper(*args, **kwargs):
return 2
return wrapper
#decorator
def f():
return 0
with mock.patch('test.decorator') as d:
d.side_effect = mocked
assert f() == 2 # error
There is not a simple solution.
This is a similar question: How to strip decorators from a function in python
You can either modify the original code just for testing, or use something like this library: https://pypi.python.org/pypi/undecorated in order to write a helper function to switch from the original wrapper to the testing wrapper:
from undecorated import undecorated
mocked(undecorated(f))()

How to use python mock library and decorator with unittest lib?

I am trying to use mock python library, and decided to use a decorator to hide a few repetitive operations for setting mock side_effect vars with corresponding replacement methods.
So far I have the following code, which does not enter the tests, it basically does nothing. Any ideas on how to fix this? Thanks!
import unittest
from mock import patch
# Replacement method for requests.get call
def mock_requests_get(url=None, **kwargs):
if url == URL1:
return {'url':url, 'status_code':200, 'status':'success'}
if url == URL2: A
return {'url':url, 'status_code':403}
# Replacement method for requests.post call
def mock_requests_post(url, data=None, **kwargs):
if url == URL1 and data['data']=='go':
return {'url':url, 'status_code':200, 'status':'success'}
if url == URL2 and data['data']!='gogo':
return {'url':url, 'status_code':403}
# Decorator which sets mock replacement methods
def mock_type(method=''):
def _mock(func):
def _decorator(mock_get, mock_post, *args, **kwargs):
print method
if method == 'GET':
mock_get.side_effect = mock_requests_get
if method == 'POST':
mock_post.side_effect = mock_requests_post
func(mock_get, mock_post, *args, **kwargs)
return _decorator
return _mock
#patch('requests.post')
#patch('requests.get')
class TestKeywordsApi(unittest.TestCase):
def setUp(self):
self.ka = KeywordsApi()
#mock_type('GET')
def test_get(self, mock_get, mock_post):
# Replace this code in mock_type decorator:
#mock_get.side_effect=mock_requests_get
print self.ka.get(URL1)
print self.ka.get(URL2)
# Do asserts
#mock_type('POST')
def test_post(self, mock_get, mock_post):
# Replace this code in mock_type decorator:
#mock_post.side_effect=mock_requests_post
print self.ka.post(URL1, {'data':'go'})
print self.ka.post(URL2, {'data':'go'})
# Do asserts
Make sure to replace the functions in the execution namespace. Depending on the imports, your current code may or may not be replacing what you think it is replacing. The following does what I believe you were trying to do.
import kwmodule
import unittest, mock
def mock_requests_get(url=None, **kwargs):
"Replacement method for requests.get call"
pass
def mock_requests_post(url, data=None, **kwargs):
"Replacement method for requests.post call"
pass
#mock.patch('kwmodule.requests.post', mock_requests_post)
#mock.patch('kwmodule.requests.get', mock_requests_get)
class TestKeywordsApi(unittest.TestCase):
def setUp(self):
self.ka = kwmodule.KeywordsApi()
However, you may be more successful with replacing get & post with autospecced MagicMock objects. If that doesn't work for you, then use your own custom replacement.
For instance, the following patch decorator would work if you know the order of calls to "get."
return_values = [{'url':url, 'status_code':200, 'status':'success'},
{'url':url, 'status_code':403},
AssertionError('Unexpected call.')]
#mock.patch('kwmodule.requests.get', autospec=True, side_effect=return_values)
This will return a "success" condition the first time it is called, an error the second time, and it will raise an AssertionError if it is called a third time. Nine times out of ten, I use side_effect instead of writing my own return generating function.

Is it possible to use reflection to examine a function's decorators in Python 2.5?

This is what i want to do:
#MyDecorator
def f():
pass
for d in f.decorators:
print d
This is not generally possible without the cooperation of the decorators. For example,
def my_decorator(f):
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
wrapper.decorators = [wrapper]
if hasattr(f, 'decorators'):
wrapper.decorators.extend[f.decorators]
return wrapper
Essentially, all the decorator does is wrap the function as usual and then put a decorators attribute on the wrapper function. It then checks the wrapped function for a similar list and propagates it upwards.
This is pretty useless though
What I think you want is
def my_decorator(f):
def wrapper(args):
return f(args)
wrapper.decorated = f
return wrapper
This will allow you to do stuff like
#my_other_decorator # another decorator following the same pattern
#my_decorator
def foo(args):
print args
foo.decorated(args) # calls the function with the inner decorated function (my_decorator)
foo.decorated.decorated(args) # original function
You can actually abstract this pattern into a decorator
def reversable(decorator):
def wrapper(func):
ret = decorator(func) # manually apply the decorator
ret.decorated = func # save the original function
return ret
return wrapper
Now when you are writing your decorator:
#reversable
def my_decorator(f):
def wrapper(x):
return f(x + 1)
return wrapper
The #MyDecorator syntax is just shorthand for writing the following Python code:
def f():
pass
f = MyDecorator(f)
Written in this form, you can see that the decorators applied to the function are not kept track of in any way. You could make your decorators remember when they're applied (Aaron's answer has a couple good ideas on how to do this), but you'd have to wrap all third-party decorators with your own.

Categories