def test_simple_default_checked_args5(): @tc.typecheck def axc_b2c(a: int, b: int = 2): return a + b assert axc_b2c(10, 20) == 30 with expected( InputParameterError( "axc_b2c() has got an incompatible value for b: 20.0")): axc_b2c(10, 20.0) with expected( InputParameterError( "axc_b2c() has got an incompatible value for a: 10.0")): axc_b2c(10.0, 20) with expected( InputParameterError( "axc_b2c() has got an incompatible value for a: 10.0")): axc_b2c(10.0, 20.0) assert axc_b2c(10) == 12 with expected( InputParameterError( "axc_b2c() has got an incompatible value for a: 10.0")): axc_b2c(10.0) with expected(TypeError, "axc_b2c"): axc_b2c()
def test_default_vs_checked_kwargs10(): @tc.typecheck def pxc_q2c(*, p: int, q: int = 2): return p + q assert pxc_q2c(p=1, q=2) == 3 with expected( InputParameterError( "pxc_q2c() has got an incompatible value for q: 2.0")): pxc_q2c(p=1, q=2.0) with expected( InputParameterError( "pxc_q2c() has got an incompatible value for p: 1.0")): pxc_q2c(p=1.0, q=2) with expected( InputParameterError, "pxc_q2c\(\) has got an incompatible value for (p: 1.0|q: 2.0)"): pxc_q2c(p=1.0, q=2.0) #TODO: should tc.optional() be required when a default is given? No! (also elsewhere) with expected( InputParameterError( "pxc_q2c() has got an incompatible value for q: <no value>")): pxc_q2c(p=1) with expected( InputParameterError( "pxc_q2c() has got an incompatible value for p: <no value>")): pxc_q2c(q=2)
def test_default_vs_checked_kwargs7(): @tc.typecheck def pxn_q2c(*, p, q: int = 2): return p + q assert pxn_q2c(p=1, q=2) == 3 with expected( InputParameterError( "pxn_q2c() has got an incompatible value for q: 2.0")): pxn_q2c(p=1, q=2.0) assert pxn_q2c(p=1.0, q=2) == 3.0 with expected( InputParameterError( "pxn_q2c() has got an incompatible value for q: 2.0")): pxn_q2c(p=1.0, q=2.0) with expected( InputParameterError( "pxn_q2c() has got an incompatible value for q: <no value>")): pxn_q2c(p=1) with expected(TypeError, "pxn_q2c"): pxn_q2c(q=2) with expected( InputParameterError( "pxn_q2c() has got an incompatible value for q: <no value>")): pxn_q2c()
def test_any1(): @tc.typecheck def foo(x: tc.any()): pass with expected( InputParameterError( "foo() has got an incompatible value for x: 1")): foo(1) @tc.typecheck def bar(x: tc.any((int, float), tc.re("^foo$"), tc.enum(b"X", b"Y"))): pass bar((1, 1.0)) bar("foo") bar(b"X") bar(b"Y") with expected( InputParameterError( "bar() has got an incompatible value for x: (1.0, 1)")): bar((1.0, 1)) with expected( InputParameterError( "bar() has got an incompatible value for x: b'foo'")): bar(b"foo") with expected( InputParameterError( "bar() has got an incompatible value for x: X")): bar("X") with expected( InputParameterError( "bar() has got an incompatible value for x: Y")): bar("Y")
def test_default_vs_checked_kwargs11(): @tc.typecheck def p1c_q2c(*, p: int = 1, q: int = 2): return p + q assert p1c_q2c(p=1, q=2) == 3 with expected( InputParameterError( "p1c_q2c() has got an incompatible value for q: 2.0")): p1c_q2c(p=1, q=2.0) with expected( InputParameterError( "p1c_q2c() has got an incompatible value for p: 1.0")): p1c_q2c(p=1.0, q=2) with expected( InputParameterError, "p1c_q2c\(\) has got an incompatible value for (p: 1.0|q: 2.0)"): p1c_q2c(p=1.0, q=2.0) with expected( InputParameterError( "p1c_q2c() has got an incompatible value for q: <no value>")): p1c_q2c(p=1) with expected( InputParameterError( "p1c_q2c() has got an incompatible value for p: <no value>")): p1c_q2c(q=2)
def test_map_of_complex(): @tc.typecheck def foo(*, k: tc.map_of( (int, int), [tc.re("^[0-9]+$"), tc.re("^[0-9]+$")])): return functools.reduce( lambda r, t: r and str(t[0][0]) == t[1][0] and str(t[0][1]) == t[1] [1], k.items(), True) assert foo(k={(1, 2): ["1", "2"], (3, 4): ["3", "4"]}) assert not foo(k={(1, 3): ["1", "2"], (3, 4): ["3", "4"]}) assert not foo(k={(1, 2): ["1", "2"], (3, 4): ["3", "5"]}) with expected( InputParameterError( "foo() has got an incompatible value for k: {(1, 2): ['1', '2'], (3, 4): ['3', 'x']}" )): foo(k={(1, 2): ["1", "2"], (3, 4): ["3", "x"]}) with expected( InputParameterError( "foo() has got an incompatible value for k: {(1, 2): ['1', '2'], (3,): ['3', '4']}" )): foo(k={(1, 2): ["1", "2"], (3, ): ["3", "4"]}) with expected( InputParameterError( "foo() has got an incompatible value for k: {(1, 2): ['1', '2'], (3, 4.0): ['3', '4']}" )): foo(k={(1, 2): ["1", "2"], (3, 4.0): ["3", "4"]})
def test_empty_string_in_incompatible_values(): @tc.typecheck def foo(s: lambda s: s != "" = None): return s assert foo() is None assert foo(None) is None assert foo(0) == 0 with expected( InputParameterError( "foo() has got an incompatible value for s: ''")): foo("") @tc.typecheck def foo(*, k: tc.optional(lambda s: s != "") = None): return k assert foo() is None assert foo(k=None) is None assert foo(k=0) == 0 with expected( InputParameterError( "foo() has got an incompatible value for k: ''")): foo(k="") @tc.typecheck def foo(s=None) -> lambda s: s != "": return s assert foo() is None assert foo(None) is None assert foo(0) == 0 with expected( ReturnValueError("foo() has returned an incompatible value: ''")): foo("")
def test_FixedSequenceChecker2(): @tc.typecheck def foo(a: [] = [], *, k: tc.optional([]) = None) -> ([], tc.optional([])): return a, k assert foo() == ([], None) assert foo([]) == ([], None) assert foo(k=[]) == ([], []) assert foo([], k=[]) == ([], []) with expected( InputParameterError( "foo() has got an incompatible value for a: ()")): foo(()) with expected( InputParameterError( "foo() has got an incompatible value for a: (1,)")): foo((1, )) with expected( InputParameterError( "foo() has got an incompatible value for k: ()")): foo(k=()) with expected( InputParameterError( "foo() has got an incompatible value for k: (1,)")): foo(k=(1, ))
def test_none2(): class TestCase: pass class MyCheckers(TestCase): pass class AddressTest: pass def classname_contains_Test(arg): return type(arg).__name__.find("Test") >= 0 @tc.typecheck def no_tests_please(arg: tc.none(TestCase, classname_contains_Test)): pass no_tests_please("stuff") # OK with expected( InputParameterError( "no_tests_please() has got an incompatible value for arg: <")): no_tests_please(TestCase()) # Wrong: not wanted here with expected( InputParameterError( "no_tests_please() has got an incompatible value for arg: <")): no_tests_please(MyCheckers()) # Wrong: superclass not wanted here with expected( InputParameterError( "no_tests_please() has got an incompatible value for arg: <")): no_tests_please(AddressTest()) # Wrong: suspicious class name
def test_event(): with expected(InputParameterError("event() has got an incompatible value for key: 123")): pmnc.performance.event(123) with expected(InputParameterError("event() has got an incompatible value for key: $$$")): pmnc.performance.event("$$$") with expected(InputParameterError("event() has got an incompatible value for key: foo")): pmnc.performance.event("foo") pmnc.performance.event("interface.foo.request_rate")
def test_sample(): with expected(InputParameterError("sample() has got an incompatible value for key: 123")): pmnc.performance.sample(123, 1000) with expected(InputParameterError("sample() has got an incompatible value for key: $$$")): pmnc.performance.sample("$$$", 1000) with expected(InputParameterError("sample() has got an incompatible value for key: bar")): pmnc.performance.sample("bar", 1000) with expected(InputParameterError("sample() has got an incompatible value for value: value")): pmnc.performance.sample("resource.bar.processing_time", "value") pmnc.performance.sample("resource.bar.processing_time", 1000)
def test_seq_of_simple(): @tc.typecheck def foo_s(x: tc.seq_of(int)) -> tc.seq_of(float): return list(map(float, x)) assert foo_s([]) == [] assert foo_s(()) == [] assert foo_s([1, 2, 3]) == [1.0, 2.0, 3.0] with expected( InputParameterError( "foo_s() has got an incompatible value for x: ['1.0']")): foo_s(["1.0"]) with expected( InputParameterError( "foo_s() has got an incompatible value for x: 1")): foo_s(1)
def test_has2(): @tc.typecheck def foo(*, k: tc.re("^[0-9A-F]+$")) -> tc.re("^[0-9]+$"): return "".join(reversed(k)) assert foo(k="1234") == "4321" with expected( InputParameterError( "foo() has got an incompatible value for k: ''")): foo(k="") with expected( InputParameterError( "foo() has got an incompatible value for k: 1")): foo(k=1) with expected( ReturnValueError("foo() has returned an incompatible value: DAB")): foo(k="BAD")
def test_all2(): def complete_blocks(arg): return len(arg) % 512 == 0 @tc.typecheck def foo_all(arg: tc.all(tc.any(bytes, bytearray), complete_blocks)): pass foo_all(b"x" * 512) # OK foo_all(bytearray(b"x" * 1024)) # OK with expected( InputParameterError( "foo_all() has got an incompatible value for arg: xxx")): foo_all("x" * 512) # Wrong: not a bytearray or bytes with expected( InputParameterError( "foo_all() has got an incompatible value for arg: b'xxx")): foo_all(b"x" * 1012) # Wrong: no complete blocks
def test_simple_default_checked_args2(): @tc.typecheck def a1n_b2c(a=1, b: int = 2): return a + b assert a1n_b2c(10, 20) == 30 with expected( InputParameterError( "a1n_b2c() has got an incompatible value for b: 20.0")): a1n_b2c(10, 20.0) assert a1n_b2c(10.0, 20) == 30.0 with expected( InputParameterError( "a1n_b2c() has got an incompatible value for b: 20.0")): a1n_b2c(10.0, 20.0) assert a1n_b2c(10) == 12 assert a1n_b2c(10.0) == 12.0 assert a1n_b2c() == 3
def test_simple_checked_args1(): @tc.typecheck def axc_bxn(a: int, b): return a + b assert axc_bxn(10, 20) == 30 assert axc_bxn(10, 20.0) == 30.0 with expected( InputParameterError( "axc_bxn() has got an incompatible value for a: 10.0")): axc_bxn(10.0, 20) with expected( InputParameterError( "axc_bxn() has got an incompatible value for a: 10.0")): axc_bxn(10.0, 20.0) with expected(TypeError, "axc_bxn"): axc_bxn(10) with expected(TypeError, "axc_bxn"): axc_bxn()
def test_map_of_simple(): @tc.typecheck def foo(x: tc.map_of(int, str)) -> tc.map_of(str, int): return {v: k for k, v in x.items()} assert foo({}) == {} assert foo({1: "1", 2: "2"}) == {"1": 1, "2": 2} with expected( InputParameterError( "foo() has got an incompatible value for x: []")): foo([]) with expected( InputParameterError( "foo() has got an incompatible value for x: {'1': '2'}")): foo({"1": "2"}) with expected( InputParameterError( "foo() has got an incompatible value for x: {1: 2}")): foo({1: 2})
def test_simple_checked_args2(): @tc.typecheck def axn_bxc(a, b: int): return a + b assert axn_bxc(10, 20) == 30 with expected( InputParameterError( "axn_bxc() has got an incompatible value for b: 20.0")): axn_bxc(10, 20.0) assert axn_bxc(10.0, 20) == 30.0 with expected( InputParameterError( "axn_bxc() has got an incompatible value for b: 20.0")): axn_bxc(10.0, 20.0) with expected(TypeError, "axn_bxc"): axn_bxc(10) with expected(TypeError, "axn_bxc"): axn_bxc()
def test_FixedSequenceChecker1(): @tc.typecheck def foo(a: (int, str) = (1, "!"), *, k: tc.optional(()) = ()) -> (str, ()): return a[1], k assert foo() == ("!", ()) assert foo((2, "x")) == ("x", ()) assert foo(k=()) == ("!", ()) assert foo((33, "44"), k=()) == ("44", ()) assert foo([3, "4"]) == ("4", ()) assert foo(k=[]) == ("!", []) with expected( InputParameterError( "foo() has got an incompatible value for a: (1,)")): foo((1, )) with expected( InputParameterError( "foo() has got an incompatible value for k: (1, 2)")): foo(k=(1, 2))
def test_default_vs_checked_kwargs1(): @tc.typecheck def foo(*, a: str): return a with expected( InputParameterError( "foo() has got an incompatible value for a: <no value>")): foo() assert foo(a="b") == "b"
def test_all1(): @tc.typecheck def foo(x: tc.all()): pass foo(foo) # an empty all() accepts anything @tc.typecheck def bar(x: tc.all(tc.re("abcdef"), tc.re("defghi"), tc.re("^abc"))): pass bar("abcdefghijklm") with expected( InputParameterError( "bar() has got an incompatible value for x: abcdefghi")): bar(" abcdefghi") with expected( InputParameterError( "bar() has got an incompatible value for x: abc defghi")): bar("abc defghi")
def test_has5(): @tc.typecheck def numbers_only_please(s: tc.re("^[0-9]+$")): pass numbers_only_please("123") with expected( InputParameterError( "numbers_only_please() has got an incompatible value for s: 123" )): numbers_only_please("123\x00HUH?")
def test_FixedSequenceChecker5(): @tc.typecheck def foo(a: collections.UserList([str, collections.UserList])): return a[1][1] assert foo(collections.UserList(["aha!", collections.UserList([3, 4, 5])])) == 4 with expected( InputParameterError( "foo() has got an incompatible value for a: ")): assert foo(["aha!", collections.UserList([3, 4, 5])]) == 4
def test_FixedSequenceChecker4(): @tc.typecheck def foo(*, k: tc.optional([[[[lambda x: x % 3 == 1]]]]) = [[[[4]]]]): return k[0][0][0][0] assert foo() % 3 == 1 assert foo(k=[[[[1]]]]) % 3 == 1 with expected( InputParameterError( "foo() has got an incompatible value for k: [[[[5]]]]")): foo(k=[[[[5]]]])
def test_enum1(): @tc.typecheck def foo(x: tc.enum(int, 1)) -> tc.enum(1, int): return x assert foo(1) == 1 assert foo(int) is int with expected( InputParameterError( "foo() has got an incompatible value for x: 2")): foo(2)
def test_default_vs_checked_kwargs2(): @tc.typecheck def foo(*, a: tc.optional(str) = "a"): return a assert foo() == "a" assert foo(a="b") == "b" with expected( InputParameterError( "foo() has got an incompatible value for a: 10")): foo(a=10)
def test_none1(): @tc.typecheck def foo(x: tc.none()): pass foo(foo) # an empty none() accepts anything @tc.typecheck def taboo(x: tc.none(tc.re("foo"), tc.re("bar"))): pass taboo("boofar") with expected( InputParameterError( "taboo() has got an incompatible value for x: foofar")): taboo("foofar") with expected( InputParameterError( "taboo() has got an incompatible value for x: boobar-ism")): taboo("boobar-ism")
def test_any3(): @tc.typecheck def accept_number(x: tc.any(int, tc.re("^[0-9]+$"))): return int(x) + 1 assert accept_number(1) == 2 assert accept_number("1") == 2 assert accept_number(-1) == 0 with expected( InputParameterError( "accept_number() has got an incompatible value for x: -1")): accept_number("-1")
def test_has3(): @tc.typecheck def foo(*, k: (tc.re("^1$"), [tc.re("^x$"), tc.re("^y$")])): return k[0] + k[1][0] + k[1][1] assert foo(k=("1", ["x", "y"])) == "1xy" with expected( InputParameterError( "foo() has got an incompatible value for k: ('2', ['x', 'y'])") ): foo(k=("2", ["x", "y"])) with expected( InputParameterError( "foo() has got an incompatible value for k: ('1', ['X', 'y'])") ): foo(k=("1", ["X", "y"])) with expected( InputParameterError( "foo() has got an incompatible value for k: ('1', ['x', 'Y'])") ): foo(k=("1", ["x", "Y"]))
def test_simple_default_checked_args4(): @tc.typecheck def a1c_b2n(a: int = 1, b=2): return a + b assert a1c_b2n(10, 20) == 30 assert a1c_b2n(10, 20.0) == 30.0 with expected( InputParameterError( "a1c_b2n() has got an incompatible value for a: 10.0")): a1c_b2n(10.0, 20) with expected( InputParameterError( "a1c_b2n() has got an incompatible value for a: 10.0")): a1c_b2n(10.0, 20.0) assert a1c_b2n(10) == 12 with expected( InputParameterError( "a1c_b2n() has got an incompatible value for a: 10.0")): a1c_b2n(10.0) assert a1c_b2n() == 3