1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
import sys
import pytest
from funcy.decorators import *
def test_decorator_no_args():
@decorator
def inc(call):
return call() + 1
@inc
def ten():
return 10
assert ten() == 11
def test_decorator_with_args():
@decorator
def add(call, n):
return call() + n
@add(2)
def ten():
return 10
assert ten() == 12
def test_decorator_kw_only_args():
@decorator
def add(call, *, n=1):
return call() + n
def ten(a, b):
return 10
# Should work with or without parentheses
assert add(n=2)(ten)(1, 2) == 12
assert add()(ten)(1, 2) == 11
assert add(ten)(1, 2) == 11
# TODO: replace this with a full version once we drop Python 3.7
def test_decorator_access_args():
@decorator
def return_x(call):
return call.x
# no arg
with pytest.raises(AttributeError): return_x(lambda y: None)(10)
# pos arg
assert return_x(lambda x: None)(10) == 10
with pytest.raises(AttributeError): return_x(lambda x: None)()
assert return_x(lambda x=11: None)(10) == 10
assert return_x(lambda x=11: None)() == 11
# varargs
assert return_x(lambda *x: None)(1, 2) == (1, 2)
assert return_x(lambda _, *x: None)(1, 2) == (2,)
# varkeywords
assert return_x(lambda **x: None)(a=1, b=2) == {'a': 1, 'b': 2}
assert return_x(lambda **x: None)(a=1, x=3) == {'a': 1, 'x': 3} # Not just 3
assert return_x(lambda a, **x: None)(a=1, b=2) == {'b': 2}
if sys.version_info >= (3, 8):
pytest.register_assert_rewrite("tests.py38_decorators")
from .py38_decorators import test_decorator_access_args # noqa
def test_double_decorator_defaults():
@decorator
def deco(call):
return call.y
@decorator
def noop(call):
return call()
@deco
@noop
def f(x, y=1):
pass
assert f(42) == 1
def test_decorator_with_method():
@decorator
def inc(call):
return call() + 1
class A(object):
def ten(self):
return 10
@classmethod
def ten_cls(cls):
return 10
@staticmethod
def ten_static():
return 10
assert inc(A().ten)() == 11
assert inc(A.ten_cls)() == 11
assert inc(A.ten_static)() == 11
def test_decorator_with_method_descriptor():
@decorator
def exclaim(call):
return call() + '!'
assert exclaim(str.upper)('hi') == 'HI!'
def test_chain_arg_access():
@decorator
def decor(call):
return call.x + call()
@decor
@decor
def func(x):
return x
assert func(2) == 6
def test_meta_attribtes():
@decorator
def decor(call):
return call()
def func(x):
"Some doc"
return x
decorated = decor(func)
double_decorated = decor(decorated)
assert decorated.__name__ == 'func'
assert decorated.__module__ == __name__
assert decorated.__doc__ == "Some doc"
assert decorated.__wrapped__ is func
assert decorated.__original__ is func
assert double_decorated.__wrapped__ is decorated
assert double_decorated.__original__ is func
def test_decorator_introspection():
@decorator
def decor(call, x):
return call()
assert decor.__name__ == 'decor'
decor_x = decor(42)
assert decor_x.__name__ == 'decor'
assert decor_x._func is decor.__wrapped__
assert decor_x._args == (42,)
assert decor_x._kwargs == {}
|