def test_wrap_function(): '''Tests function wrapper utility''' FooIn = NamedTuple('FooIn', [('x', int), ('y', int)]) FooOut = NamedTuple('FooOut', [('value', int)]) # ============================================================================= # both args and return need to be wrapped # ============================================================================= def foo(x: int, y: int) -> int: return x + y f, in_, out = _wrap_function(foo) assert _types_equal(in_, FooIn) assert _types_equal(out, FooOut) assert f(FooIn(1, 2)) == FooOut(3) # ============================================================================= # function is already considered wrapped # ============================================================================= def bar(msg: FooIn) -> FooOut: return FooOut(msg.x + msg.y) f, in_, out = _wrap_function(bar) assert f is bar assert _types_equal(in_, FooIn) assert _types_equal(out, FooOut) assert f(FooIn(1, 2)) == FooOut(3) # ============================================================================= # function args need to be wrapped but return is fine # ============================================================================= BazIn = NamedTuple('BazIn', [('x', int), ('y', int)]) def baz(x: int, y: int) -> FooOut: return FooOut(x + y) f, in_, out = _wrap_function(baz) assert _types_equal(in_, BazIn) assert _types_equal(out, FooOut) assert f(BazIn(1, 2)) == FooOut(3) # ============================================================================= # function return needs to be wrapped but args are fine # ============================================================================= QuxOut = NamedTuple('QuxOut', [('value', int)]) def qux(msg: FooIn) -> int: return msg.x + msg.y f, in_, out = _wrap_function(qux) assert _types_equal(in_, FooIn) assert _types_equal(out, QuxOut) assert f(BazIn(1, 2)) == QuxOut(3)
def test_reserved_name(): '''Tests that a reserved NamedTuple name cannot be used''' Empty = NamedTuple('Empty', []) def foo(x: Empty) -> Empty: return Empty() with pytest.raises(AcumosError): _wrap_function(foo)
def test_nested_defs(): '''Tests that nested types raise exceptions''' def f1(x: List[List[int]]) -> float: pass def f2(x: List[Dict[str, int]]) -> float: pass def f3(x: Dict[str, List[int]]) -> float: pass def f4(x: Dict[str, Dict[str, int]]) -> float: pass for f in (f1, f2, f3, f4): with pytest.raises(AcumosError): _wrap_function(f)
def test_wrap_function_structured_to_structured(FooIn, FooOut, Image): '''Tests function wrapper utility both args and return need to be wrapped''' def foo(x: int, y: int) -> int: return x + y f, in_, out = _wrap_function(foo) assert _types_equal(in_, FooIn) assert _types_equal(out, FooOut) assert f(FooIn(1, 2)) == FooOut(3)
def test_wrap_function_structured_to_raw(FooIn, FooOut, Image): '''Tests function wrapper utility check for structured to user-defined data''' def test_create_image_func(x: int, y: int) -> Image: return Image("b\00" * x * y) f, raw_in, raw_out = _wrap_function(test_create_image_func) assert _types_equal(raw_in, FooIn, ignore_type_name=True) assert is_raw_type(raw_out) assert f(raw_in(2, 2)) == Image("b\00" * 4)
def test_wrap_function_raw_to_structured(FooIn, FooOut, Image): '''Tests function wrapper utility check for user-defined to structured data''' def test_get_image_size_func(image: Image) -> int: return len(image) f, raw_in, raw_out = _wrap_function(test_get_image_size_func) assert is_raw_type(raw_in) assert _types_equal(raw_out, FooOut, ignore_type_name=True) assert f(Image(Image(b"1234"))) == raw_out(4)
def test_wrap_function_raw_to_raw(FooIn, FooOut, Image): '''Tests function wrapper utility check for both user defined raw data type''' def test_image_func(image: Image) -> Image: return Image(image) f, raw_in, raw_out = _wrap_function(test_image_func) assert is_raw_type(raw_in) assert is_raw_type(raw_out) assert f(Image(b"1234")) == Image(b"1234")
def test_wrap_function_structured_to_structured_already_wrapped(FooIn, FooOut, Image): '''Tests function wrapper utility both args and return are already wrapped''' def bar(msg: FooIn) -> FooOut: return FooOut(msg.x + msg.y) f, in_, out = _wrap_function(bar) assert f is bar assert _types_equal(in_, FooIn) assert _types_equal(out, FooOut) assert f(FooIn(1, 2)) == FooOut(3)
def test_wrap_function_structured_to_structured_return_already_wrapped(FooIn, FooOut, Image): '''Tests function wrapper utility return is already wrapped''' QuxOut = NamedTuple('QuxOut', [('value', int)]) def qux(msg: FooIn) -> int: return msg.x + msg.y f, in_, out = _wrap_function(qux) assert _types_equal(in_, FooIn) assert _types_equal(out, QuxOut) assert f(FooIn(1, 2)) == QuxOut(3)
def test_wrap_function_structured_to_structured_args_already_wrapped(FooIn, FooOut, Image): '''Tests function wrapper utility args are already wrapped''' BazIn = NamedTuple('BazIn', [('x', int), ('y', int)]) def baz(x: int, y: int) -> FooOut: return FooOut(x + y) f, in_, out = _wrap_function(baz) assert _types_equal(in_, BazIn) assert _types_equal(out, FooOut) assert f(BazIn(1, 2)) == FooOut(3)
def test_bad_annotations(): '''Tests bad annotation scenarios''' def f1(x: float): pass def f2(x): pass def f3(x) -> float: pass def f4(x: float, y) -> float: pass def f5(x: float) -> float: pass for f in (f1, f2, f3, f4): with pytest.raises(AcumosError): _wrap_function(f) _wrap_function(f5)
def test_null_functions(): '''Tests the wrapping of a function with no arguments and no returns''' def f1() -> None: pass def f2() -> NoReturn: pass def f3() -> Empty: pass for f in (f1, f2, f3): _, in_, out = _wrap_function(f) assert in_ is Empty assert out is Empty