I am programming in Python, and I am wondering if i can test if a function has been called in my code
def example():
pass
example()
#Pseudocode:
if example.has_been_called:
print("foo bar")
How would I do this?
If it's OK for the function to know its own name, you can use a function attribute:
def example():
example.has_been_called = True
pass
example.has_been_called = False
example()
#Actual Code!:
if example.has_been_called:
print("foo bar")
You could also use a decorator to set the attribute:
import functools
def trackcalls(func):
#functools.wraps(func)
def wrapper(*args, **kwargs):
wrapper.has_been_called = True
return func(*args, **kwargs)
wrapper.has_been_called = False
return wrapper
#trackcalls
def example():
pass
example()
#Actual Code!:
if example.has_been_called:
print("foo bar")
A minimal example using unittest.mock.Mock from the standard library:
from unittest.mock import Mock
def example():
pass
example_mock = Mock(side_effect=example)
example_mock()
#Pseudocode:
if example_mock.called:
print("foo bar")
Console output after running the script:
foo bar
This approach is nice because it doesn't require you to modify the example function itself, which is useful if you want to perform this check in some unit-testing code, without modifying the source code itself (EG to store a has_been_called attribute, or wrap the function in a decorator).
Explanation
As described in the documentation for the unittest.mock.Mock class, the side_effect argument to the Mock() constructor specifies "a function to be called whenever the Mock is called".
The Mock.called attribute specifies "a boolean representing whether or not the mock object has been called".
The Mock class has other attributes you may find useful, EG:
call_count: An integer telling you how many times the mock object has been called
call_args: This is either None (if the mock hasn’t been called), or the arguments that the mock was last called with
call_args_list: This is a list of all the calls made to the mock object in sequence (so the length of the list is the number of times it has been called). Before any calls have been made it is an empty list
The Mock class also has convenient methods for making assert statements based on how many times a Mock object was called, and what arguments it was called with, EG:
assert_called_once_with(*args, **kwargs): Assert that the mock was called exactly once and that that call was with the specified arguments
We can use mock.Mock
from unittest import mock
def check_called(func):
return mock.Mock(side_effect=func)
#check_called
def summator(a, b):
print(a + b)
summator(1, 3)
summator.assert_called()
assert summator.called == True
assert summator.call_count > 0
summator.assert_called_with(1, 3)
summator.assert_called_with(1, 5) # error
# AssertionError: Expected call: mock(1, 5)
# Actual call: mock(1, 3)
Memoization functions have been around since the 1960s. In python you can use them as decorators on your example() function.
The standard memoization function looks something like this:
def memoize(func):
memo = {}
def wrapper(*args):
if not args in memo:
memo[args] = func(*args)
return memo[args]
return wrapper
and you decorate your function like this:
#memoize
def example():
pass
In python3.2, you can use the functools.lru_cache instead of the memoziation function.
import functools
#functools.lru_cache(maxsize=None)
def example():
pass
Here's a decorator that will watch all your functiona, using colorama, and return a nice output.
try:
import colorama
except ImportError:
class StdClass: pass
def passer(*args, **kwargs): pass
colorama = StdClass()
colorama.init = passer
colorama.Fore = StdClass()
colorama.Fore.RED = colorama.Fore.GREEN = ''
def check_for_use(show=False):
if show:
try:
check_for_use.functions
except AttributeError:
return
no_error = True
for function in check_for_use.functions.keys():
if check_for_use.functions[function][0] is False:
print(colorama.Fore.RED + 'The function {!r} hasn\'t been called. Defined in "{}" '.format(function, check_for_use.functions[function][1].__code__.co_filename))
no_error = False
if no_error:
print(colorama.Fore.GREEN + 'Great! All your checked function are being called!')
return check_for_use.functions
try:
check_for_use.functions
except AttributeError:
check_for_use.functions = {}
if colorama:
colorama.init(autoreset=True)
def add(function):
check_for_use.functions[function.__name__] = [False, function]
def func(*args, **kwargs):
check_for_use.functions[function.__name__] = [True, function]
function(*args, **kwargs)
return func
return add
#check_for_use()
def hello():
print('Hello world!')
#check_for_use()
def bonjour(nb):
print('Bonjour tout le monde!')
# hello(); bonjour(0)
hello()
check_for_use(True) # outputs the following
Output:
Hello world!
The function 'bonjour' hasn't been called. Defined in "path_to_file.py"
You can also create a variable and increment it in the function. Later you can check if it's 1 or >= 0.
Related
I'm trying to learn some advanced decorator usage. Specifically, I'm trying to to monkey patch a class's method via a decorator within a function.
This is a basic example to illustrate what I'm trying to do. I have a function something that does some stuff; and within that function there's an instance of a class. That instance I would like to monkey patch.
from functools import update_wrapper
class Foobar:
def get_something(self):
return "apple"
class FakeFoobar:
def get_something(self):
return "orange"
class my_decorator:
def __init__(self, original_function):
self._original_function = original_function
update_wrapper(self, original_function)
def __call__(self, *args, **kwargs):
# some magic here?
return self._original_function(*args, **kwargs)
#my_decorator
def something():
f = Foobar()
return f.get_something()
if __name__ == '__main__':
print(something())
I'm trying either trying to do a 1 to 1 replacement with Foobar to FakeFoobar or, monkey patch Foobar's get_something method to FakeFoobar's get_something method.
When I run the code above, I get the following:
>>> something()
'apple'
>>>
I would like to find some way augment the Foobar's get_something method so that we get the following output:
>>> something()
'orange'
>>>
There's a mock module within the unittests library, however, it's not clear to be how I could leverage that for my use case. I'm fairly married to the idea of not passing an argument into the decorator or an extra argument into the something function as many of the examples of the mock library show.
I also notice that the moto library is accomplishing something similar to what I'm trying to do. I tried digging into the source code, but it seems fairly complex for what I'm trying to do.
How about updating the global variables dict of the function?
from functools import update_wrapper
class Foobar:
def get_something(self):
return "apple"
class FakeFoobar:
def get_something(self):
return "orange"
class my_decorator:
def __init__(self, original_function):
self._original_function = original_function
update_wrapper(self, original_function)
def __call__(self, *args, **kwargs):
f = self._original_function
restore_val = f.func_globals['Foobar']
f.func_globals['Foobar'] = f.func_globals['FakeFoobar']
# ^^^^^ This is your magic-line.
try:
return f(*args, **kwargs)
except:
raise
finally:
f.func_globals['Foobar'] = restore_val
#my_decorator
def something():
f = Foobar()
return f.get_something()
if __name__ == '__main__':
print(something()) #Prints orange
print(Foobar().get_something()) #Prints apple
Suppose I have this decorator:
def decorator(f):
def f_wrap(*args):
for item in args:
print(args)
return f(*args)
return f_wrap
When used as "permanent" decorators with the # syntax, args retrieves the arguments of the wrapped function. For example, when used with the class below, I receive the instance of MyObject.
Class MyObject(object):
def __init__(self):
pass
#decorator
def function(self):
return
How can I achieve the same result using a "fluid" decorator. Or a decorator that is not permanently bound to the function it is decorating? For example:
def decorator(f):
def f_wrap(*args):
if (not args):
print("Nothing in args")
return f(*args)
return f_wrap
class MyClass(object):
def __init__(self):
pass
def function(self):
return
if __name__ == "__main__":
myobj = MyClass()
myobj.function = decorator(myobj.function)
myobj.function()
In this case, the args tuple always returns empty (I always get "Nothing in args"), even though I anticipated that it would return the instance variable myobj.
EDIT:
In case it was not clear from #AChampion's post the solution is to simply call the fluid-decoratored method as an "unbound" method. E.g.,
from types import MethodType
def decorator(f):
def f_wrap(*args):
# I replaced this with an iteration through
# args. It's a bit more demonstrative.
for item in args:
print(item)
return f(*args)
return f_wrap
class MyClass(object):
def __init__(self):
pass
def function(self):
return
if __name__ == "__main__":
myobj = MyClass()
myobj.function = MethodType(decorator(MyClass.function), myobj)
myobj.function()
The reason for the difference is that you are wrapping different things, a unbound method vs a bound method:
class MyObject(object):
#decorator
def function(self):
pass
Is equivalent to:
import types
class MyClass(object):
def function(self):
pass
m = MyClass(object)
m.function = types.MethodType(decorator(MyClass.function), m)
Not:
m.function = decorator(m.function)
The first being an unbound method, the second being a bound method.
You aren't using all properly. all returns a bool on whether all conditions are met inside what you are checking for in all. In your case, you aren't really doing anything. You will always evaluate to True with how you are using all.
I believe what you are looking for is simply this:
if not args:
Now, ultimately what this checks is if the method you are executing has *args. For the case of the function you have, you aren't passing any arguments, therefore, with the if not args check, you will actually get:
"Nothing in args"
However, if you add an argument to your method as such:
def function(self, x):
return
Then call: myobj.function(1)
You will not get "Nothing in args".
To answer your last question about not getting your instance. If you print out f using this method of calling your decorator:
myobj.function = decorator(myobj.function)
myobj.function()
You will get a bound method:
<bound method MyClass.function of <__main__.MyClass object at 0x102002390>>
Now, set up your decorator as such:
#decorator
def function(self):
return
You will see you get a function attached to your class object:
<function MyClass.function at 0x102001620>
Hence showing that they aren't doing the exact same thing you would expect. Hope this helps clarify a bit.
I have a class which maintains a list of functions. These functions are just objects sitting in a queue and every so often the class pops one off and executes it. However, there are times when I would like to print out this list, and I'm imagining code as follows:
for function in self.control_queue:
print function.summarize()
if function.ready():
function()
In other words, I would like to call methods called summarize() and ready(), that I want to define somewhere, on these function objects. Also, I would like to be able to toss anonymous functions on this queue - i.e., generate everything dynamically.
you can make it a class and define __call__
class MyClass():
def summarize(self):
#summarize stuff
pass
def ready(self):
#ready stuff
pass
def _call__(self):
#put the code here, for when you call myClass()
pass
How you run it:
function = MyClass()
print function.summarize()
if function.ready():
function()
You have a couple possible approaches.
You could add the definitions to functions.
def foo():
pass
# later..
foo.summarize = lambda: "To pair with bar"
foo.ready = lambda: True
You could create class objects to wrap the function operation.
class Func():
def summarize(self):
return "Function!"
def ready(self):
return self.ready
def __call__(self):
# Act as a function
Or you can have a function which checks the function label for these capabilities.
def summarize_func(func):
return func.__name__ # Or branch here on specific names/attributes
def ready_func(func):
return True # Or branch on names/attributes
Finally to accommodate anonymous functions you can check for prescience of these attributes and return optimistically if the attributes are absent. Then you can combine above approaches with something that will work on any function.
def summarize_func(func):
if hasattr(func, summarize):
return func.summarize()
else:
# Note this will just be '<lambda>' for anonymous funcs
return func.__name__
def ready_func(func):
if hasattr(func, ready):
return func.ready()
else:
return True
One option is to implement function as a class instance:
class Function(object):
def summarize(self): pass # some relevant code here
def __call__(self): pass # and there
and use it later with
function = Function()
With __call__ magic method implemented, this function becomes a callable object.
For sure, you can assign attributes to functions, but it is rather obscure and conterintuitive:
>>> def summ(a): return sum(a)
...
>>> def function(a): return a
...
>>> function.sum=summ
>>> function.sum([1,2,3])
6
I have been testing out this caching method/code:
http://code.activestate.com/recipes/498245-lru-and-lfu-cache-decorators/?c=15348
and in some cases, I get this (or similar) error:
"AttributeError: 'str' object has no attribute 'module'"
and here are code examples, these work fine:
if __name__ == '__main__':
#lru_cacheItem(maxsize=20)
def f(x, y):
return 3*x+y
domain = range(5)
from random import choice
for i in range(1000):
r = f(choice(domain), choice(domain))
print('Hits:{0}'.format(f.hits), 'Misses:{0}'.format(f.misses))
#lfu_cacheItem(maxsize=20)
def f(x, y):
return 3*x+y
domain = range(5)
from random import choice
for i in range(1000):
r = f(choice(domain), choice(domain))
print('Hits:{0}'.format(f.hits), 'Misses:{0}'.format(f.misses))
#lru_cacheItem(maxsize=20)
def myString(a, b):
return '{0} and {1}'.format(a, b)
a = 'crap'
b = 'shit'
for i in range(1000):
r = myString(a, b)
print('Hits:{0}'.format(myString.hits), 'Misses:{0}'.format(myString.misses))
and this does not:
if __name__ == '__main__':
class P4client(object):
def __init__(self):
pass
def checkFileStats(self, filePath):
results = 'The filepath: {0}'.format(filePath)
print results
return results
p4client = P4client()
filePath = (r"C:\depot\tester.tga")
#lfu_cacheItem
def p4checkFileStats(filePath):
'''Will cache the fstats return'''
p4checkResults = p4client.checkFileStats(filePath)
return p4checkResults
p4checkFileStats(filePath)
I am not sure how to fix this ... it appears to be an issue in functools, I assume somehow do to that fact I am calling a class/method within the function I am wrapping?
#lfu_cacheItem
def p4checkFileStats(filePath):
You are missing parenthesis here:
#lfu_cacheItem()
def p4checkFileStats(filePath):
All decorators which expect "options", i.e. that you can use as:
#decorator(a=Something, b=Other, ...)
def the_function(...):
Must always be called when decorating, even if you do not provide arguments:
#decorator()
def the_function(...):
Why you wonder? Well, first of all remember that decorators are normal functions that accept a function as argument:
In [1]: def hooray(func):
...: print("I'm decorating function: {.__name__}".format(func))
...: return func
In [2]: #hooray
...: def my_function(): pass
I'm decorating function: my_function
As you can see hooray was called. In fact this is what really happens when using a decorator:
In [3]: def my_function(): pass
...: my_function = hooray(my_function)
...:
I'm decorating function: my_function
Now, if you want to pass options to the decorator you can create a function that returns a decorator. This is exactly what happens with lfu_cache from the recipe you link:
def lfu_cache(maxsize=100):
# ...
def decorating_function(user_function):
# ...
return decorating_function
Now here you can see that lfu_cache is really a function. this function creates a decorator, called decorating_function and returns it. This means that when calling:
#lfu_cache(maxsize=20)
def my_function(): pass
This is what happens:
def my_function(): pass
decorator = lfu_cache(maxsize=20)
my_function = decorator(my_function)
As you can see first lfu_cache is called, and returns a decorator. Afterwards the decorator is called to decorate the function.
What happens if you forget the parenthesis? What does this:
#lfu_cache
def my_function(): pass
do?
Pretty simple, it uses lfu_cache as a simple decorator:
def my_function(): pass
my_function = lfu_cache(my_function)
But this is bad! You passed a function as maxsize parameter and the value returned by lfu_cache is the decorating_function of before!
to learn more about decorators read this So answer.
Is it possible to decorate a function based on a condition?
a'la:
if she.weight() == duck.weight():
#burn
def witch():
pass
I'm just wondering if logic could be used (when witch is called?) to figure out whether or not to decorate witch with #burn?
If not, is it possible to create a condition within the decorator to the same effect? (witch being called undecorated.)
You can create a 'conditionally' decorator:
>>> def conditionally(dec, cond):
def resdec(f):
if not cond:
return f
return dec(f)
return resdec
Usage example follows:
>>> def burn(f):
def blah(*args, **kwargs):
print 'hah'
return f(*args, **kwargs)
return blah
>>> #conditionally(burn, True)
def witch(): pass
>>> witch()
hah
>>> #conditionally(burn, False)
def witch(): pass
>>> witch()
It is possible to enable/disable decorators by reassignment.
def unchanged(func):
"This decorator doesn't add any behavior"
return func
def disabled(func):
"This decorator disables the provided function, and does nothing"
def empty_func(*args,**kargs):
pass
return empty_func
# define this as equivalent to unchanged, for nice symmetry with disabled
enabled = unchanged
#
# Sample use
#
GLOBAL_ENABLE_FLAG = True
state = enabled if GLOBAL_ENABLE_FLAG else disabled
#state
def special_function_foo():
print "function was enabled"
Decorators are just syntactical sugar for re-defining the function, ex:
def wrapper(f):
def inner(f, *args):
return f(*args)
return lambda *args: inner(f, *args)
def foo():
return 4
foo = wrapper(foo)
Which means that you could do it the old way, before the syntactical sugar existed:
def foo():
return 4
if [some_condition]:
foo = wrapper(foo)