Doctest and third party decorator - python

I need to doc-test a method which has to be wrapped with a decorator that does not apply #functools.wraps or functools.update_wrapper to the method being wrapped. In this case, the doctest does not see the docstring of the method to be tested:
#third_party_decorator
def method_to_be_tested():
"""
>>> method_to_be_tested()
"foo"
"""
return "foo"
This question is similar, however, I cannot change the code of the decorator.
What is the best thing I can do?

You may not be able to change the code of third_party_decorator, but you can wrap it once again to address the problem, and even re-use the same name if necessary:
def third_party_decorator(f):
# badly behaved decorator, this removed f's docstring
def no_docstring():
return f()
return no_docstring
old_third_party_decorator = third_party_decorator
def third_party_decorator(f):
# replace third_party_decorator AND preserve docstring
new_f = old_third_party_decorator(f)
new_f.__doc__ = f.__doc__
return new_f
#third_party_decorator
def method_to_be_tested():
"""
>>> method_to_be_tested()
'foo'
"""
return "foo"
import doctest
print(doctest.testmod())

A small meta-decorator to fix this:
def w(decorator):
def wrapper(func):
return wraps(func)(decorator(func))
return wrapper
Use:
#w(third_party_decorator)
def method_to_be_tested():
"""
>>> method_to_be_tested()
"foo"
"""
return "foo"
Or, monkey-patch it (do it only once):
third_party_decorator = w(third_party_decorator)

Related

Check whether method is called directly or by another method

I'd like to know whether my method is called by the user directly or by another method. To make it less abstract:
class myclass():
def __init__(self, ...):
....
def method1(self, ...):
...
--- some if statement --
print "Hello"
return something
def callmethod(self, ...):
x = self.method1(...)
return x*2
myinstance = myclass(...)
myinstance.method1(...)
--> 'Hello'
myinstance.callmethod(...)
--> -
Hopefully my class makes clear what I'd like to do: When the user calls 'method1' the print statement shall be executed but if 'method1' is called by another method like 'callmethod' the print statement shall not be executed. Therefore I need 'some if statement' which checks whether 'method1' is called by the user directly or by another method. Thanks for you help!
No, and you don't want to do this.
If you want to change behaviour depending on the way a method is called, then you need to use a parameter. You can use a default value to make this simpler, for example:
def method1(self, do_print=True):
...
if do_print:
print "Hello"
return something
def callmethod(self, ...):
x = self.method1(do_print=False)
return x*2
Now, calling myinstance.method1() will print, whereas myinstance.callmethod() will not.
It's actually achievable using the python inspector, like e.g.:
import inspect
class myclass():
def __init__(self):
pass
def method1(self):
(frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1]
if function_name == '<module>':
print "Hello"
return 2
def callmethod(self):
x = self.method1()
return x*2
myinstance = myclass()
myinstance.method1()
myinstance.callmethod()
but I agree with Daniel it's not an elegant way to achieve the result as it hides some behaviour.
For further details also see: this post

How can I call a function inside this function with parameters, if I don't have both name and args/kwargs? [duplicate]

I can access a python function's attribute inside of function itself by below code:
def aa():
print aa.__name__
print aa.__hash__
# other simliar
However, if above aa() function is a template for write other code, say bb(), I have to write:
def bb():
print bb.__name__
print bb.__hash__
# other simliar
Is there a "pointer" similar to the self argument in a class method so I could write code like this?
def whatever():
print self.__name__
print self.__hash__
# other simliar
I searched and found someone said to use the class to solve this problem, but that may be a trouble to redefine all the existing functions. Any suggestions?
There is no generic way for a function to refer to itself. Consider using a decorator instead. If all you want as you indicated was to print information about the function that can be done easily with a decorator:
from functools import wraps
def showinfo(f):
#wraps(f)
def wrapper(*args, **kwds):
print(f.__name__, f.__hash__)
return f(*args, **kwds)
return wrapper
#showinfo
def aa():
pass
If you really do need to reference the function, then just add it to the function arguments:
def withself(f):
#wraps(f)
def wrapper(*args, **kwds):
return f(f, *args, **kwds)
return wrapper
#withself
def aa(self):
print(self.__name__)
# etc.
Edit to add alternate decorator:
You can also write a simpler (and probably faster) decorator that will make the wrapped function work correctly with Python's introspection:
def bind(f):
"""Decorate function `f` to pass a reference to the function
as the first argument"""
return f.__get__(f, type(f))
#bind
def foo(self, x):
"This is a bound function!"
print(self, x)
>>> foo(42)
<function foo at 0x02A46030> 42
>>> help(foo)
Help on method foo in module __main__:
foo(self, x) method of builtins.function instance
This is a bound function!
This leverages Python's descriptor protocol: functions have a __get__ method that is used to create bound methods. The decorator simply uses the existing method to make the function a bound method of itself. It will only work for standalone functions, if you wanted a method to be able to reference itself you would have to do something more like the original solution.
http://docs.python.org/library/inspect.html looks promising:
import inspect
def foo():
felf = globals()[inspect.getframeinfo(inspect.currentframe()).function]
print felf.__name__, felf.__doc__
you can also use the sys module to get the name of the current function:
import sys
def bar():
felf = globals()[sys._getframe().f_code.co_name]
print felf.__name__, felf.__doc__
You can at least say self = bb in the first line, and then you only need to change that line when you change the function name, instead of every other reference.
My code editor highlights the variable self the same way it does for classes, too.
How about a quick hack to make your own "self" name, like this:
>>> def f():
... self = f
... print "My name is ", self.__name__, "and I am", self.__hash__
...
>>> f()
My name is f and I am <method-wrapper '__hash__' of function object at 0x00B50F30>
>>> x = f
>>> x()
My name is f and I am <method-wrapper '__hash__' of function object at 0x00B50F30>
>>>

passing variables between two python decorators

Is there are a way to pass a variable between two python decorators applied to the same function? The goal is for one of the decorators to know that the other was also applied. I need something like decobar_present() from the example below:
def decobar(f):
def wrap():
return f() + "bar"
return wrap
def decofu(f):
def wrap():
print decobar_present() # Tells me whether decobar was also applied
return f() + "fu"
return wrap
#decofu
#decobar
def important_task():
return "abc"
More generally I would like to be able to modify the behavior of decofu depending on whether decobar was also applied.
You can add the function to a "registry" when decobar is applied to it, then later check the registry to determine whether decobar was applied to the function or not. This approach requires preserving original function's __module__ and __name__ properties intact (use functools.wraps over the wrapper function for that).
import functools
class decobar(object):
registry = set()
#classmethod
def _func_key(cls, f):
return '.'.join((f.__module__, f.func_name))
#classmethod
def present(cls, f):
return cls._func_key(f) in cls.registry
def __call__(self, f):
self.registry.add(self._func_key(f))
#functools.wraps(f)
def wrap():
return f() + "bar"
return wrap
# Make the decorator singleton
decobar = decobar()
def decofu(f):
#functools.wraps(f)
def wrap():
print decobar.present(f) # Tells me whether decobar was also applied
return f() + "fu"
return wrap
#decofu
#decobar
def important_task():
return "abc"
Used a class to implement decobar, as it keeps registry and present() in a single namespace (which feels slighly cleaner, IMO)
To pass a variable between two python decorators you can use the decorated function's keyword arguments dictionary. Only don't forget to pop the added argument from there before calling the function from within the second decorator.
def decorator1(func):
def wrap(*args, **kwargs):
kwargs['cat_says'] = 'meow'
return func(*args, **kwargs)
return wrap
def decorator2(func):
def wrap(*args, **kwargs):
print(kwargs.pop('cat_says'))
return func(*args, **kwargs)
return wrap
class C:
#decorator1
#decorator2
def spam(self, a, b, c, d=0):
print("Hello, cat! What's your favourite number?")
return a + b + c + d
x=C()
print(x.spam(1, 2, 3, d=7))
While it is possible to do things like manipulate the stack trace, you're better off, I think, simply creating a function decofubar and incorporate as much of both "fu" and "bar" as possible. At a minimum, it will make your code cleaner and more obvious.
Each decorator gets to wrap another function. The function passed to decofu() is the result of the decobar() decorator.
Just test for specific traits of the decobar wrapper, provided you make the wrapper recognisable:
def decobar(f):
def wrap():
return f() + "bar"
wrap.decobar = True
return wrap
def decofu(f):
def wrap():
print 'decobar!' if getattr(f, 'decobar') else 'not decobar'
return f() + "fu"
return wrap
I used an arbitrary attribute on the wrapper function, but you could try to test for a name (not so unambiguous), for the signature (using inspect.getargspec() perhaps), etc.
This is limited to direct wrapping only.
Generally speaking, you don't want to couple decorators as tightly as all this. Work out a different solution and only depend on function signature or return values.
You can assign flag to f (or rather wrap) in decobar just like this
def decobar(f):
def wrap():
return f() + "bar"
wrap.decobar_applied = True
return wrap
def decofu(f):
def wrap():
if hasattr(f, 'decobar_applied') and f.decobar_applied:
print decobar_present() # Tells me whether decobar was also applied
return f() + "fu"
return wrap
#decofu
#decobar
def important_task():
return "abc"

Find Out If a Function has been Called

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.

Python3 decorating conditionally?

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)

Categories