def test_curry_kwargs(): def f(a, b, c=10): return (a + b) * c f = curry(f) assert f(1, 2, 3) == 9 assert f(1)(2, 3) == 9 assert f(1, 2) == 30 assert f(1, c=3)(2) == 9 assert f(c=3)(1, 2) == 9 def g(a=1, b=10, c=0): return a + b + c cg = curry(g, b=2) assert cg() == 3 assert cg(b=3) == 4 assert cg(a=0) == 2 assert cg(a=0, b=1) == 1 assert cg(0) == 2 # pass "a" as arg, not kwarg assert raises(TypeError, lambda: cg(1, 2)) # pass "b" as arg AND kwarg def h(x, func=int): return func(x) if platform.python_implementation() != 'PyPy'\ or platform.python_version_tuple()[0] != '3': # Bug on PyPy3<2.5 # __init__ must not pick func as positional arg assert curry(h)(0.0) == 0 assert curry(h)(func=str)(0.0) == '0.0' assert curry(h, func=str)(0.0) == '0.0'
def test_curry_simple(): cmul = curry(mul) double = cmul(2) assert callable(double) assert double(10) == 20 assert repr(cmul) == repr(mul) cmap = curry(map) assert list(cmap(inc)([1, 2, 3])) == [2, 3, 4] assert raises(TypeError, lambda: curry()) assert raises(TypeError, lambda: curry({1: 2}))
def test_curry_is_idempotent(): def foo(a, b, c=1): return a + b + c f = curry(foo, 1, c=2) g = curry(f) assert isinstance(f, curry) assert isinstance(g, curry) assert not isinstance(g.func, curry) assert not hasattr(g.func, 'func') assert f.func == g.func assert f.args == g.args assert f.keywords == g.keywords
def test_curry_comparable(): def foo(a, b, c=1): return a + b + c f1 = curry(foo, 1, c=2) f2 = curry(foo, 1, c=2) g1 = curry(foo, 1, c=3) h1 = curry(foo, c=2) h2 = h1(c=2) h3 = h1() assert f1 == f2 assert not (f1 != f2) assert f1 != g1 assert not (f1 == g1) assert f1 != h1 assert h1 == h2 assert h1 == h3 # test function comparison works def bar(a, b, c=1): return a + b + c b1 = curry(bar, 1, c=2) assert b1 != f1 assert {f1, f2, g1, h1, h2, h3, b1, b1()} == {f1, g1, h1, b1} # test unhashable input unhash1 = curry(foo, []) assert raises(TypeError, lambda: hash(unhash1)) unhash2 = curry(foo, c=[]) assert raises(TypeError, lambda: hash(unhash2))
def test_curry_doesnot_transmogrify(): # Early versions of `curry` transmogrified to `partial` objects if # only one positional argument remained even if keyword arguments # were present. Now, `curry` should always remain `curry`. def f(x, y=0): return x + y cf = curry(f) assert cf(y=1)(y=2)(y=3)(1) == f(1, 3)
def test_curry_docstring(): def f(x, y): """ A docstring """ return x g = curry(f) assert g.__doc__ == f.__doc__ assert str(g) == str(f) assert f(1, 2) == g(1, 2)
def test_curry_is_like_partial(): def foo(a, b, c=1): return a + b + c p, c = partial(foo, 1, c=2), curry(foo)(1, c=2) assert p.keywords == c.keywords assert p.args == c.args assert p(3) == c(3) p, c = partial(foo, 1), curry(foo)(1) assert p.keywords == c.keywords assert p.args == c.args assert p(3) == c(3) assert p(3, c=2) == c(3, c=2) p, c = partial(foo, c=1), curry(foo)(c=1) assert p.keywords == c.keywords assert p.args == c.args assert p(1, 2) == c(1, 2)
def check_curry(func, args, kwargs, incomplete=True): try: curry(func)(*args, **kwargs) curry(func, *args)(**kwargs) curry(func, **kwargs)(*args) curry(func, *args, **kwargs)() if not isinstance(func, type(lambda: None)): return None return incomplete except ValueError: return True except TypeError: return False
def test_curry_attributes_readonly(): def foo(a, b, c=1): return a + b + c f = curry(foo, 1, c=2) assert raises(AttributeError, lambda: setattr(f, 'args', (2, ))) assert raises(AttributeError, lambda: setattr(f, 'keywords', {'c': 3})) assert raises(AttributeError, lambda: setattr(f, 'func', f)) assert raises(AttributeError, lambda: delattr(f, 'args')) assert raises(AttributeError, lambda: delattr(f, 'keywords')) assert raises(AttributeError, lambda: delattr(f, 'func'))
def test_curry_attributes_writable(): def foo(a, b, c=1): return a + b + c foo.__qualname__ = 'this.is.foo' f = curry(foo, 1, c=2) assert f.__qualname__ == 'this.is.foo' f.__name__ = 'newname' f.__doc__ = 'newdoc' f.__module__ = 'newmodule' f.__qualname__ = 'newqualname' assert f.__name__ == 'newname' assert f.__doc__ == 'newdoc' assert f.__module__ == 'newmodule' assert f.__qualname__ == 'newqualname' if hasattr(f, 'func_name'): assert f.__name__ == f.func_name
from __future__ import absolute_import import operator from aiotoolz.functoolz import curry, num_required_args, has_keywords def should_curry(f): num = num_required_args(f) return num is None or num > 1 or num == 1 and has_keywords(f) is not False locals().update( { name: curry(f) if should_curry(f) else f for name, f in vars(operator).items() if callable(f) }, ) # Clean up the namespace. del curry del num_required_args del has_keywords del operator del should_curry
def test_curry_bad_types(): assert raises(TypeError, lambda: curry(1))