def test_call_kwargs(self): builtins = {"func": lambda a, x=1, y="foo": (a, x, y)} func = Function[Int, {"x": Int, "y": Str}, Tuple[Int, Int, Str]]("func") res1 = func(1) assert interpreter.interpret(res1.graft, builtins)() == (1, 1, "foo") res2 = func(1, x=-1) assert interpreter.interpret(res2.graft, builtins)() == (1, -1, "foo") res2 = func(1, y="bar") assert interpreter.interpret(res2.graft, builtins)() == (1, 1, "bar") res2 = func(1, x=-1, y="bar") assert interpreter.interpret(res2.graft, builtins)() == (1, -1, "bar")
def test_shared_outer_scope(): shared = Function[{}, Int]("func")() result = ifelse(shared > 0, shared + 1, shared - 1) assert isinstance(result, Int) func_result = 10 calls = 0 def func(): nonlocal calls calls += 1 return func_result interpreted = interpret( result.graft, builtins={ "func": func, "wf.ifelse": lambda cond, t, f: t() if cond else f(), "wf.numpy.add": operator.add, "wf.numpy.subtract": operator.sub, "wf.numpy.greater": operator.gt, }, )() assert interpreted == func_result + 1 assert calls == 1
def test_returns_closure(self): def outer(a): b = a + parameter("global", Int) # 1; use to track closure correctness def inner(x, y): return (x + y) / b return inner func = Function[Int, {}, Function[Int, Int, {}, Float]](outer) global_value = 1 first_call_arg = 4 proxy_inner = func(4) assert isinstance(proxy_inner, Function[Int, Int, {}, Float]) result_2 = proxy_inner(6, 4) result_3 = proxy_inner(10, 5) result = result_2 + result_3 m = mock.MagicMock() m.__radd__.side_effect = lambda other: other + global_value interpreted = interpreter.interpret( result.graft, builtins={ "numpy.add": operator.add, "numpy.true_divide": operator.truediv, "global": m, }, )() assert interpreted == 5 m.__radd__.assert_called_once_with(first_call_arg)
def test_init(): lst = List[Int]([1, 2, 3]) assert client.is_delayed(lst) assert lst.params == () assert interpreter.interpret( lst.graft, builtins={"wf.list": lambda *args: list(args)})() == [1, 2, 3]
def test_init_sequence(): b = parameter("b", Bool) tup = Tuple[Int, Str, Int, Bool]([1, "foo", 3, b]) assert client.is_delayed(tup) assert tup.params == (b,) assert interpreter.interpret( tup.graft, builtins={"wf.tuple": lambda *tuple: tuple, b._name: True} )() == (1, "foo", 3, True)
def test_init_copy(): lst1 = List[Int]([1, 2, 3]) lst2 = List[Int](lst1) assert lst2.graft != lst1.graft assert interpreter.interpret( lst2.graft, builtins={"list": lambda *args: list(args), "list.copy": list} )() == [1, 2, 3]
def test_very_higher_order(self): ext1_value = -1 ext2_value = -10 def make_function(proxy=True): ext1 = parameter("ext1", Int) if proxy else ext1_value def func_a(a_1): x = a_1 + ext1 def func_b(b_1, b_2): y = b_1 - b_2 + (parameter("ext2", Int) if proxy else ext2_value) def func_c(c_1): return x + y + c_1 + ext1 return func_c return func_b return func_a func = Function[Int, {}, Function[Int, Int, {}, Function[Int, {}, Int]]](make_function()) assert tuple(p._name for p in func.params) == ("ext1", "ext2") def do_operation(f): b = f(2) c1 = b(1, 3) c2 = b(2, 4) result = c1(0) - c1(5) + c2(10) + c2(3) return result proxy_result = do_operation(func) real_result = do_operation(make_function(proxy=False)) ext1 = mock.MagicMock() ext1.__radd__.side_effect = lambda other: ext1_value + other ext2 = mock.MagicMock() ext2.__radd__.side_effect = lambda other: ext2_value + other interpreted = interpreter.interpret( proxy_result.graft, builtins={ "wf.numpy.add": operator.add, "wf.numpy.subtract": operator.sub, "ext1": ext1, "ext2": ext2, }, )() assert interpreted == real_result assert len( ext1.__radd__.mock_calls) == 5 # 4 `c` calls + 1 to construct `x` assert len(ext2.__radd__.mock_calls) == 2 # 2 `b` calls
def test_init_kwargs(self): with pytest.raises(TypeError, match="Parameter foo=1 has a default value."): Function[{"foo": Int}, Int](lambda foo=1: foo) func = Function[{"foo": Int}, Int](lambda foo: foo) assert client.is_delayed(func) interpreted_func = interpreter.interpret(func.graft) assert interpreted_func(1) == 1 assert interpreted_func(foo=1) == 1
def test_call(self): def delayable(a, b): assert isinstance(a, Int) assert isinstance(b, Str) return a func = Function[Int, Str, {}, Int](delayable) result = func(1, "foo") assert isinstance(result, Int) assert interpreter.interpret(result.graft)() == 1
def test_getitem_roundtrip(): src = [1, 2, 3] tup = List[Int](src) for i, truth in enumerate(src): value = interpreter.interpret( tup[i].graft, builtins={"list": lambda *args: list(args), "getitem": operator.getitem}, )() assert value == truth
def test_getitem_roundtrip(): src = [1, "foo", 3] tup = Tuple[Int, Str, Int](src) for i, truth in enumerate(src): value = interpreter.interpret( tup[i].graft, builtins={"wf.tuple": lambda *tuple: tuple, "wf.get": operator.getitem}, )() assert value == truth
def test_call_proper_binding(self, call_args, call_kwargs): func = Function[Int, dict(a=Int, b=Str), Int]("foo") builtins = {"foo": lambda *args, **kwargs: (args, kwargs)} res = func(*call_args, **call_kwargs) args, kwargs = interpreter.interpret(res.graft, builtins)() # positional args should always be given positionally in the graft assert args == (1, ) # named args should always be given by name in the graft, and in the right order, # even if given positionally or in a different order in py assert list(kwargs.items()) == [("a", 2), ("b", "x")]
def test_from_callable(self): def py_func(a, b, c): return (a + b) / c func = Function.from_callable(py_func) assert isinstance(func, Function[Any, Any, Any, {}, Any]) result = func(7, 1, 4) interpreted = interpreter.interpret( result.graft, builtins={"wf.add": operator.add, "wf.div": operator.truediv} )() assert interpreted == 2
def test_getitem_roundtrip(): src = {"a": 1, "b": 2} dct = Dict[Str, Int](src) for key, truth in six.iteritems(src): value = interpreter.interpret( dct[key].graft, builtins={ "getitem": operator.getitem, "dict.create": dict_builtin }, )() assert value == truth
def test_takes_function(self): def main(a, b, helper): return helper(a) / helper(b) func = Function[Int, Int, Function[Int, {}, Int], {}, Float](main) result = func(3, 1, lambda x: x + 1) interpreted = interpreter.interpret(result.graft, builtins={ "add": operator.add, "div": operator.truediv })() assert interpreted == 2
def test_init_fromkwargs(mock_apply): dct = Dict[Str, Int](a=1, b=2, c=3) apply_args, apply_kwargs = mock_apply.call_args assert apply_args == ("dict.create", ) assert six.viewkeys(apply_kwargs) == {"a", "b", "c"} for value in six.itervalues(apply_kwargs): assert isinstance(value, Int) assert client.is_delayed(dct) assert interpreter.interpret(dct.graft, builtins={"dict.create": dict_builtin})() == dict(a=1, b=2, c=3)
def test_init_fromdict(mock_apply): dct = Dict[Int, Float]({1: 1.1, 2: 2.2}) apply_args, apply_kwargs = mock_apply.call_args assert apply_args[0] == "dict.create" assert len(apply_kwargs) == 0 for (key_item, value_item) in iter_argpairs(apply_args[1:]): assert isinstance(key_item, Int) assert isinstance(value_item, Float) assert client.is_delayed(dct) assert interpreter.interpret(dct.graft, builtins={"dict.create": dict_builtin})() == { 1: 1.1, 2: 2.2 }
def test_from_callable(self): def py_func(a: Int, b: Float, c: Int) -> Float: "my func" return (a + b) / c func = Function.from_callable(py_func) assert isinstance(func, Function[dict(a=Int, b=Float, c=Int), Float]) assert func.__doc__ == "my func" result = func(7, 1.0, 4) interpreted = interpreter.interpret( result.graft, builtins={ "wf.numpy.add": operator.add, "wf.numpy.true_divide": operator.truediv, }, )() assert interpreted == 2
def test_init_fromdict_andkwargs(mock_apply): dct = Dict[Str, Int]({"a": 0, "z": 100}, a=1, b=2, c=3) apply_args, apply_kwargs = mock_apply.call_args assert apply_args == ("wf.dict.create", ) assert six.viewkeys(apply_kwargs) == {"a", "z", "b", "c"} for value in six.itervalues(apply_kwargs): assert isinstance(value, Int) assert client.is_delayed(dct) assert dct.params == () assert interpreter.interpret(dct.graft, builtins={"wf.dict.create": dict_builtin})() == { "a": 1, "z": 100, "b": 2, "c": 3 }
def test_short_circuit(): func1 = Function[{}, Int]("func1") func2 = Function[{}, Int]("func2") result = ifelse(True, func1(), func2()) assert isinstance(result, Int) func1_mock = mock.Mock(return_value=1) func2_mock = mock.Mock(return_value=2) interpreted = interpret( result.graft, builtins={ "func1": func1_mock, "func2": func2_mock, "wf.ifelse": lambda cond, t, f: t() if cond else f(), }, )() assert interpreted == 1 func1_mock.assert_called_once() func2_mock.assert_not_called()
def test_init_sequence(): tup = Tuple[Int, Str, Int]([1, "foo", 3]) assert client.is_delayed(tup) assert interpreter.interpret(tup.graft, builtins={"wf.tuple": lambda *tuple: tuple })() == (1, "foo", 3)
def test_init_callable(self): func = Function[{}, Int](lambda: 1) assert isinstance(func.function, Int) # ^ this is weird and should change eventually interpreted_func = interpreter.interpret(func.graft) assert interpreted_func() == 1
def test_init_callable(self): func = Function[{}, Int](lambda: 1) assert client.is_delayed(func) interpreted_func = interpreter.interpret(func.graft) assert interpreted_func() == 1