1238 lines
29 KiB
Plaintext
1238 lines
29 KiB
Plaintext
|
# Test cases for functions and calls (compile and run)
|
||
|
|
||
|
[case testCallTrivialFunction]
|
||
|
def f(x: int) -> int:
|
||
|
return x
|
||
|
[file driver.py]
|
||
|
from native import f
|
||
|
print(f(3))
|
||
|
print(f(-157))
|
||
|
print(f(10**20))
|
||
|
print(f(-10**20))
|
||
|
[out]
|
||
|
3
|
||
|
-157
|
||
|
100000000000000000000
|
||
|
-100000000000000000000
|
||
|
|
||
|
[case testRecursiveFibonacci]
|
||
|
def fib(n: int) -> int:
|
||
|
if n <= 1:
|
||
|
return 1
|
||
|
else:
|
||
|
return fib(n - 1) + fib(n - 2)
|
||
|
[file driver.py]
|
||
|
from native import fib
|
||
|
print(fib(0))
|
||
|
print(fib(1))
|
||
|
print(fib(2))
|
||
|
print(fib(6))
|
||
|
[out]
|
||
|
1
|
||
|
1
|
||
|
2
|
||
|
13
|
||
|
|
||
|
[case testNestedFunctions]
|
||
|
from typing import Callable, List
|
||
|
|
||
|
def a() -> Callable[[], object]:
|
||
|
def inner() -> object:
|
||
|
return None
|
||
|
return inner
|
||
|
|
||
|
def b() -> Callable[[], Callable[[], str]]:
|
||
|
def first() -> Callable[[], str]:
|
||
|
def second() -> str:
|
||
|
return 'b.first.second: nested function'
|
||
|
return second
|
||
|
return first
|
||
|
|
||
|
def c(num: float) -> Callable[[str], str]:
|
||
|
def inner(s: str) -> str:
|
||
|
return s + '!'
|
||
|
return inner
|
||
|
|
||
|
def d(num: float) -> str:
|
||
|
def inner(s: str) -> str:
|
||
|
return s + '?'
|
||
|
a = inner('one')
|
||
|
b = inner('two')
|
||
|
return a
|
||
|
|
||
|
def e() -> int:
|
||
|
return 0
|
||
|
|
||
|
def f() -> int:
|
||
|
def inner() -> int:
|
||
|
return e()
|
||
|
return inner()
|
||
|
|
||
|
def g() -> Callable[[], Callable[[], int]]:
|
||
|
def inner() -> Callable[[], int]:
|
||
|
return e
|
||
|
return inner
|
||
|
|
||
|
def h(num: int) -> int:
|
||
|
def inner() -> int:
|
||
|
return num
|
||
|
return inner()
|
||
|
|
||
|
def i() -> int:
|
||
|
num = 3
|
||
|
def inner() -> int:
|
||
|
return num
|
||
|
return inner()
|
||
|
|
||
|
def j(num: int) -> int:
|
||
|
x = 1
|
||
|
y = 2
|
||
|
def inner() -> int:
|
||
|
nonlocal x
|
||
|
x = 3
|
||
|
return num + x + y
|
||
|
return inner()
|
||
|
|
||
|
def k() -> int:
|
||
|
num = 3
|
||
|
def inner() -> int:
|
||
|
nonlocal num
|
||
|
num = 5
|
||
|
return num
|
||
|
return inner() + num
|
||
|
|
||
|
def l() -> int:
|
||
|
num = 3
|
||
|
def inner() -> int:
|
||
|
num = 5
|
||
|
return num
|
||
|
return inner() + num
|
||
|
|
||
|
def m() -> Callable[[], int]:
|
||
|
num = 1
|
||
|
def inner() -> int:
|
||
|
num += 1
|
||
|
return num
|
||
|
num += 1
|
||
|
return inner
|
||
|
|
||
|
def n() -> int:
|
||
|
x = 1
|
||
|
def add_one() -> None:
|
||
|
x += 1
|
||
|
def add_two() -> None:
|
||
|
x += 2
|
||
|
add_one()
|
||
|
add_two()
|
||
|
return x
|
||
|
|
||
|
def triple(a: int) -> Callable[[], Callable[[int], int]]:
|
||
|
x = 1
|
||
|
def outer() -> Callable[[int], int]:
|
||
|
nonlocal x
|
||
|
x += 1
|
||
|
x += a
|
||
|
a += 1
|
||
|
def inner(b: int) -> int:
|
||
|
x += b
|
||
|
return x
|
||
|
return inner
|
||
|
return outer
|
||
|
|
||
|
def if_else(flag: int) -> str:
|
||
|
def dummy_funtion() -> str:
|
||
|
return 'if_else.dummy_function'
|
||
|
|
||
|
if flag < 0:
|
||
|
def inner() -> str:
|
||
|
return 'if_else.inner: first definition'
|
||
|
elif flag > 0:
|
||
|
def inner() -> str:
|
||
|
return 'if_else.inner: second definition'
|
||
|
else:
|
||
|
def inner() -> str:
|
||
|
return 'if_else.inner: third definition'
|
||
|
return inner()
|
||
|
|
||
|
def for_loop() -> int:
|
||
|
def dummy_funtion() -> str:
|
||
|
return 'for_loop.dummy_function'
|
||
|
|
||
|
for i in range(5):
|
||
|
def inner(i: int) -> int:
|
||
|
return i
|
||
|
if i == 3:
|
||
|
return inner(i)
|
||
|
return 0
|
||
|
|
||
|
def while_loop() -> int:
|
||
|
def dummy_funtion() -> str:
|
||
|
return 'while_loop.dummy_function'
|
||
|
|
||
|
i = 0
|
||
|
while i < 5:
|
||
|
def inner(i: int) -> int:
|
||
|
return i
|
||
|
if i == 3:
|
||
|
return inner(i)
|
||
|
i += 1
|
||
|
return 0
|
||
|
|
||
|
def free_vars(foo: int, bar: int) -> int:
|
||
|
x = 1
|
||
|
y = 2
|
||
|
def g(): # type: ignore # missing type annotation for testing
|
||
|
nonlocal y
|
||
|
y = 3
|
||
|
nonlocal bar
|
||
|
bar += y
|
||
|
z = 3
|
||
|
g()
|
||
|
return bar
|
||
|
|
||
|
def lambdas(x: int, y: int) -> int:
|
||
|
s = lambda a, b: a + b + x + y
|
||
|
return s(1, 2)
|
||
|
|
||
|
def outer() -> str:
|
||
|
return 'outer: normal function'
|
||
|
|
||
|
def inner() -> str:
|
||
|
return 'inner: normal function'
|
||
|
|
||
|
class A:
|
||
|
def __init__(self, x: int) -> None:
|
||
|
self.x = x
|
||
|
|
||
|
def outer(self, num: int) -> int:
|
||
|
y = 5
|
||
|
def inner() -> int:
|
||
|
return self.x + y + num
|
||
|
return inner()
|
||
|
|
||
|
def o() -> int:
|
||
|
a = [0, 0]
|
||
|
b = 0
|
||
|
def b_incr() -> List[int]:
|
||
|
b += 10
|
||
|
return a
|
||
|
c = 0
|
||
|
def c_incr() -> int:
|
||
|
c += 1
|
||
|
return c
|
||
|
|
||
|
# x = 1, y = 1
|
||
|
x = y = c_incr()
|
||
|
|
||
|
# a = [2, 2], b = 20
|
||
|
b_incr()[0] = b_incr()[1] = c_incr()
|
||
|
# Should return 26.
|
||
|
return x + y + a[0] + a[1] + b
|
||
|
|
||
|
global_upvar = 20
|
||
|
|
||
|
toplevel_lambda = lambda x: 10 + global_upvar + x
|
||
|
|
||
|
[file driver.py]
|
||
|
from native import (
|
||
|
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, triple, if_else, for_loop, while_loop,
|
||
|
free_vars, lambdas, outer, inner, A, toplevel_lambda
|
||
|
)
|
||
|
|
||
|
assert a()() == None
|
||
|
assert b()()() == 'b.first.second: nested function'
|
||
|
assert c(5.0)('c') == 'c!'
|
||
|
assert d(4.0) == 'one?'
|
||
|
assert e() == 0
|
||
|
assert f() == 0
|
||
|
assert g()()() == 0
|
||
|
assert h(3) == 3
|
||
|
assert i() == 3
|
||
|
assert j(3) == 8
|
||
|
assert k() == 10
|
||
|
assert l() == 8
|
||
|
assert m()() == 3
|
||
|
assert n() == 4
|
||
|
assert o() == 26
|
||
|
|
||
|
triple_outer = triple(2)
|
||
|
triple_inner = triple_outer()
|
||
|
|
||
|
assert triple_inner(4) == 8
|
||
|
assert triple_inner(4) == 12
|
||
|
assert triple_outer()(4) == 20
|
||
|
|
||
|
assert if_else(-1) == 'if_else.inner: first definition'
|
||
|
assert if_else(1) == 'if_else.inner: second definition'
|
||
|
assert if_else(0) == 'if_else.inner: third definition'
|
||
|
|
||
|
assert for_loop() == 3
|
||
|
assert while_loop() == 3
|
||
|
|
||
|
assert free_vars(1, 2) == 5
|
||
|
assert lambdas(3, 4) == 10
|
||
|
|
||
|
assert outer() == 'outer: normal function'
|
||
|
assert inner() == 'inner: normal function'
|
||
|
|
||
|
assert A(3).outer(4) == 12
|
||
|
|
||
|
assert toplevel_lambda(5) == 35
|
||
|
|
||
|
[case testNestedFunctions2]
|
||
|
from typing import Callable
|
||
|
|
||
|
def outer() -> Callable[[], object]:
|
||
|
def inner() -> object:
|
||
|
return None
|
||
|
return inner
|
||
|
|
||
|
def first() -> Callable[[], Callable[[], str]]:
|
||
|
def second() -> Callable[[], str]:
|
||
|
def third() -> str:
|
||
|
return 'third: nested function'
|
||
|
return third
|
||
|
return second
|
||
|
|
||
|
def f1() -> int:
|
||
|
x = 1
|
||
|
def f2() -> int:
|
||
|
y = 2
|
||
|
def f3() -> int:
|
||
|
z = 3
|
||
|
return y
|
||
|
return f3()
|
||
|
return f2()
|
||
|
|
||
|
def outer_func() -> int:
|
||
|
def inner_func() -> int:
|
||
|
return x
|
||
|
x = 1
|
||
|
return inner_func()
|
||
|
|
||
|
def mutual_recursion(start : int) -> int:
|
||
|
def f1(k : int) -> int:
|
||
|
if k <= 0:
|
||
|
return 0
|
||
|
k -= 1
|
||
|
return f2(k)
|
||
|
|
||
|
def f2(k : int) -> int:
|
||
|
if k <= 0:
|
||
|
return 0
|
||
|
k -= 1
|
||
|
return f1(k)
|
||
|
return f1(start)
|
||
|
|
||
|
def topLayer() -> int:
|
||
|
def middleLayer() -> int:
|
||
|
def bottomLayer() -> int:
|
||
|
return x
|
||
|
|
||
|
return bottomLayer()
|
||
|
|
||
|
x = 1
|
||
|
return middleLayer()
|
||
|
|
||
|
def nest1() -> str:
|
||
|
def nest2() -> str:
|
||
|
def nest3() -> str:
|
||
|
def mut1(val: int) -> str:
|
||
|
if val <= 0:
|
||
|
return "bottomed"
|
||
|
val -= 1
|
||
|
return mut2(val)
|
||
|
def mut2(val: int) -> str:
|
||
|
if val <= 0:
|
||
|
return "bottomed"
|
||
|
val -= 1
|
||
|
return mut1(val)
|
||
|
return mut1(start)
|
||
|
return nest3()
|
||
|
start = 3
|
||
|
return nest2()
|
||
|
|
||
|
def uno(num: float) -> Callable[[str], str]:
|
||
|
def dos(s: str) -> str:
|
||
|
return s + '!'
|
||
|
return dos
|
||
|
|
||
|
def eins(num: float) -> str:
|
||
|
def zwei(s: str) -> str:
|
||
|
return s + '?'
|
||
|
a = zwei('eins')
|
||
|
b = zwei('zwei')
|
||
|
return a
|
||
|
|
||
|
def call_other_inner_func(a: int) -> int:
|
||
|
def foo() -> int:
|
||
|
return a + 1
|
||
|
|
||
|
def bar() -> int:
|
||
|
return foo()
|
||
|
|
||
|
def baz(n: int) -> int:
|
||
|
if n == 0:
|
||
|
return 0
|
||
|
return n + baz(n - 1)
|
||
|
|
||
|
return bar() + baz(a)
|
||
|
|
||
|
def inner() -> str:
|
||
|
return 'inner: normal function'
|
||
|
|
||
|
def second() -> str:
|
||
|
return 'second: normal function'
|
||
|
|
||
|
def third() -> str:
|
||
|
return 'third: normal function'
|
||
|
|
||
|
[file driver.py]
|
||
|
from native import (outer, inner, first, uno, eins, call_other_inner_func,
|
||
|
second, third, f1, outer_func, mutual_recursion, topLayer, nest1)
|
||
|
|
||
|
assert outer()() == None
|
||
|
assert inner() == 'inner: normal function'
|
||
|
assert first()()() == 'third: nested function'
|
||
|
assert uno(5.0)('uno') == 'uno!'
|
||
|
assert eins(4.0) == 'eins?'
|
||
|
assert call_other_inner_func(5) == 21
|
||
|
assert second() == 'second: normal function'
|
||
|
assert third() == 'third: normal function'
|
||
|
assert f1() == 2
|
||
|
assert outer_func() == 1
|
||
|
assert mutual_recursion(5) == 0
|
||
|
assert topLayer() == 1
|
||
|
assert nest1() == "bottomed"
|
||
|
|
||
|
[case testFunctionCallWithDefaultArgs]
|
||
|
from typing import Tuple, List, Optional, Callable, Any
|
||
|
def f(x: int, y: int = 3, s: str = "test", z: object = 5) -> Tuple[int, str]:
|
||
|
def inner() -> int:
|
||
|
return x + y
|
||
|
return inner(), s
|
||
|
def g() -> None:
|
||
|
assert f(2) == (5, "test")
|
||
|
assert f(s = "123", x = -2) == (1, "123")
|
||
|
def h(a: Optional[object] = None, b: Optional[str] = None) -> Tuple[object, Optional[str]]:
|
||
|
return (a, b)
|
||
|
|
||
|
def same(x: object = object()) -> object:
|
||
|
return x
|
||
|
|
||
|
a_lambda: Callable[..., Any] = lambda n=20: n
|
||
|
|
||
|
def nested_funcs(n: int) -> List[Callable[..., Any]]:
|
||
|
ls: List[Callable[..., Any]] = []
|
||
|
for i in range(n):
|
||
|
def f(i: int = i) -> int:
|
||
|
return i
|
||
|
ls.append(f)
|
||
|
return ls
|
||
|
|
||
|
|
||
|
[file driver.py]
|
||
|
from native import f, g, h, same, nested_funcs, a_lambda
|
||
|
g()
|
||
|
assert f(2) == (5, "test")
|
||
|
assert f(s = "123", x = -2) == (1, "123")
|
||
|
assert h() == (None, None)
|
||
|
assert h(10) == (10, None)
|
||
|
assert h(b='a') == (None, 'a')
|
||
|
assert h(10, 'a') == (10, 'a')
|
||
|
assert same() == same()
|
||
|
|
||
|
assert [f() for f in nested_funcs(10)] == list(range(10))
|
||
|
|
||
|
assert a_lambda(10) == 10
|
||
|
assert a_lambda() == 20
|
||
|
|
||
|
[case testMethodCallWithDefaultArgs]
|
||
|
from typing import Tuple, List
|
||
|
class A:
|
||
|
def f(self, x: int, y: int = 3, s: str = "test") -> Tuple[int, str]:
|
||
|
def inner() -> int:
|
||
|
return x + y
|
||
|
return inner(), s
|
||
|
def g() -> None:
|
||
|
a = A()
|
||
|
assert a.f(2) == (5, "test")
|
||
|
assert a.f(s = "123", x = -2) == (1, "123")
|
||
|
[file driver.py]
|
||
|
from native import A, g
|
||
|
g()
|
||
|
a = A()
|
||
|
assert a.f(2) == (5, "test")
|
||
|
assert a.f(s = "123", x = -2) == (1, "123")
|
||
|
|
||
|
[case testMethodCallOrdering]
|
||
|
class A:
|
||
|
def __init__(self, s: str) -> None:
|
||
|
print(s)
|
||
|
def f(self, x: 'A', y: 'A') -> None:
|
||
|
pass
|
||
|
|
||
|
def g() -> None:
|
||
|
A('A!').f(A('hello'), A('world'))
|
||
|
[file driver.py]
|
||
|
from native import g
|
||
|
g()
|
||
|
[out]
|
||
|
A!
|
||
|
hello
|
||
|
world
|
||
|
|
||
|
[case testPyMethodCall]
|
||
|
from typing import List
|
||
|
def f(x: List[int]) -> int:
|
||
|
return x.pop()
|
||
|
def g(x: List[int], y: List[int]) -> None:
|
||
|
x.extend(y)
|
||
|
[file driver.py]
|
||
|
from native import f, g
|
||
|
l = [1, 2]
|
||
|
assert f(l) == 2
|
||
|
g(l, [10])
|
||
|
assert l == [1, 10]
|
||
|
assert f(l) == 10
|
||
|
assert f(l) == 1
|
||
|
g(l, [11, 12])
|
||
|
assert l == [11, 12]
|
||
|
|
||
|
[case testMethodCallWithKeywordArgs]
|
||
|
from typing import Tuple
|
||
|
import testmodule
|
||
|
class A:
|
||
|
def echo(self, a: int, b: int, c: int) -> Tuple[int, int, int]:
|
||
|
return a, b, c
|
||
|
def test_native_method_call_with_kwargs() -> None:
|
||
|
a = A()
|
||
|
assert a.echo(1, c=3, b=2) == (1, 2, 3)
|
||
|
assert a.echo(c = 3, a = 1, b = 2) == (1, 2, 3)
|
||
|
def test_module_method_call_with_kwargs() -> None:
|
||
|
a = testmodule.A()
|
||
|
assert a.echo(1, c=3, b=2) == (1, 2, 3)
|
||
|
assert a.echo(c = 3, a = 1, b = 2) == (1, 2, 3)
|
||
|
[file testmodule.py]
|
||
|
from typing import Tuple
|
||
|
class A:
|
||
|
def echo(self, a: int, b: int, c: int) -> Tuple[int, int, int]:
|
||
|
return a, b, c
|
||
|
[file driver.py]
|
||
|
import native
|
||
|
native.test_native_method_call_with_kwargs()
|
||
|
native.test_module_method_call_with_kwargs()
|
||
|
|
||
|
[case testAnyCall]
|
||
|
from typing import Any
|
||
|
def call(f: Any) -> Any:
|
||
|
return f(1, 'x')
|
||
|
[file driver.py]
|
||
|
from native import call
|
||
|
def f(x, y):
|
||
|
return (x, y)
|
||
|
def g(x): pass
|
||
|
|
||
|
assert call(f) == (1, 'x')
|
||
|
for bad in g, 1:
|
||
|
try:
|
||
|
call(bad)
|
||
|
except TypeError:
|
||
|
pass
|
||
|
else:
|
||
|
assert False, bad
|
||
|
|
||
|
[case testCallableTypes]
|
||
|
from typing import Callable
|
||
|
def absolute_value(x: int) -> int:
|
||
|
return x if x > 0 else -x
|
||
|
|
||
|
def call_native_function(x: int) -> int:
|
||
|
return absolute_value(x)
|
||
|
|
||
|
def call_python_function(x: int) -> int:
|
||
|
return int(x)
|
||
|
|
||
|
def return_float() -> float:
|
||
|
return 5.0
|
||
|
|
||
|
def return_callable_type() -> Callable[[], float]:
|
||
|
return return_float
|
||
|
|
||
|
def call_callable_type() -> float:
|
||
|
f = return_callable_type()
|
||
|
return f()
|
||
|
|
||
|
def return_passed_in_callable_type(f: Callable[[], float]) -> Callable[[], float]:
|
||
|
return f
|
||
|
|
||
|
def call_passed_in_callable_type(f: Callable[[], float]) -> float:
|
||
|
return f()
|
||
|
|
||
|
[file driver.py]
|
||
|
from native import call_native_function, call_python_function, return_float, return_callable_type, call_callable_type, return_passed_in_callable_type, call_passed_in_callable_type
|
||
|
a = call_native_function(1)
|
||
|
b = call_python_function(1)
|
||
|
c = return_callable_type()
|
||
|
d = call_callable_type()
|
||
|
e = return_passed_in_callable_type(return_float)
|
||
|
f = call_passed_in_callable_type(return_float)
|
||
|
assert a == 1
|
||
|
assert b == 1
|
||
|
assert c() == 5.0
|
||
|
assert d == 5.0
|
||
|
assert e() == 5.0
|
||
|
assert f == 5.0
|
||
|
|
||
|
[case testKeywordArgs]
|
||
|
from typing import Tuple
|
||
|
import testmodule
|
||
|
|
||
|
def g(a: int, b: int, c: int) -> Tuple[int, int, int]:
|
||
|
return a, b, c
|
||
|
|
||
|
def test_call_native_function_with_keyword_args() -> None:
|
||
|
assert g(1, c = 3, b = 2) == (1, 2, 3)
|
||
|
assert g(c = 3, a = 1, b = 2) == (1, 2, 3)
|
||
|
|
||
|
def test_call_module_function_with_keyword_args() -> None:
|
||
|
assert testmodule.g(1, c = 3, b = 2) == (1, 2, 3)
|
||
|
assert testmodule.g(c = 3, a = 1, b = 2) == (1, 2, 3)
|
||
|
|
||
|
def test_call_python_function_with_keyword_args() -> None:
|
||
|
assert int("11", base=2) == 3
|
||
|
|
||
|
def test_call_lambda_function_with_keyword_args() -> None:
|
||
|
g = testmodule.get_lambda_function()
|
||
|
assert g(1, c = 3, b = 2) == (1, 2, 3)
|
||
|
assert g(c = 3, a = 1, b = 2) == (1, 2, 3)
|
||
|
|
||
|
[file testmodule.py]
|
||
|
from typing import Tuple
|
||
|
|
||
|
def g(a: int, b: int, c: int) -> Tuple[int, int, int]:
|
||
|
return a, b, c
|
||
|
|
||
|
def get_lambda_function():
|
||
|
return (lambda a, b, c: (a, b, c))
|
||
|
|
||
|
[file driver.py]
|
||
|
import native
|
||
|
native.test_call_native_function_with_keyword_args()
|
||
|
native.test_call_module_function_with_keyword_args()
|
||
|
native.test_call_python_function_with_keyword_args()
|
||
|
native.test_call_lambda_function_with_keyword_args()
|
||
|
|
||
|
[case testStarArgs]
|
||
|
from typing import Tuple
|
||
|
|
||
|
def g(a: int, b: int, c: int) -> Tuple[int, int, int]:
|
||
|
return a, b, c
|
||
|
|
||
|
def test_star_args() -> None:
|
||
|
assert g(*[1, 2, 3]) == (1, 2, 3)
|
||
|
assert g(*(1, 2, 3)) == (1, 2, 3)
|
||
|
assert g(*(1,), *[2, 3]) == (1, 2, 3)
|
||
|
assert g(*(), *(1,), *(), *(2,), *(3,), *()) == (1, 2, 3)
|
||
|
assert g(*range(3)) == (0, 1, 2)
|
||
|
|
||
|
[file driver.py]
|
||
|
import native
|
||
|
native.test_star_args()
|
||
|
|
||
|
[case testStar2Args]
|
||
|
from typing import Tuple
|
||
|
|
||
|
def g(a: int, b: int, c: int) -> Tuple[int, int, int]:
|
||
|
return a, b, c
|
||
|
|
||
|
def test_star2_args() -> None:
|
||
|
assert g(**{'a': 1, 'b': 2, 'c': 3}) == (1, 2, 3)
|
||
|
assert g(**{'c': 3, 'a': 1, 'b': 2}) == (1, 2, 3)
|
||
|
assert g(b=2, **{'a': 1, 'c': 3}) == (1, 2, 3)
|
||
|
|
||
|
def test_star2_args_bad(v: dict) -> bool:
|
||
|
return g(a=1, b=2, **v) == (1, 2, 3)
|
||
|
[file driver.py]
|
||
|
import native
|
||
|
native.test_star2_args()
|
||
|
|
||
|
# this should raise TypeError due to duplicate kwarg, but currently it doesn't
|
||
|
assert native.test_star2_args_bad({'b': 2, 'c': 3})
|
||
|
|
||
|
[case testStarAndStar2Args]
|
||
|
from typing import Tuple
|
||
|
def g(a: int, b: int, c: int) -> Tuple[int, int, int]:
|
||
|
return a, b, c
|
||
|
|
||
|
class C:
|
||
|
def g(self, a: int, b: int, c: int) -> Tuple[int, int, int]:
|
||
|
return a, b, c
|
||
|
|
||
|
def test_star_and_star2_args() -> None:
|
||
|
assert g(1, *(2,), **{'c': 3}) == (1, 2, 3)
|
||
|
assert g(*[1], **{'b': 2, 'c': 3}) == (1, 2, 3)
|
||
|
c = C()
|
||
|
assert c.g(1, *(2,), **{'c': 3}) == (1, 2, 3)
|
||
|
assert c.g(*[1], **{'b': 2, 'c': 3}) == (1, 2, 3)
|
||
|
|
||
|
[file driver.py]
|
||
|
import native
|
||
|
native.test_star_and_star2_args()
|
||
|
|
||
|
[case testAllTheArgCombinations]
|
||
|
from typing import Tuple
|
||
|
def g(a: int, b: int, c: int, d: int = -1) -> Tuple[int, int, int, int]:
|
||
|
return a, b, c, d
|
||
|
|
||
|
class C:
|
||
|
def g(self, a: int, b: int, c: int, d: int = -1) -> Tuple[int, int, int, int]:
|
||
|
return a, b, c, d
|
||
|
|
||
|
def test_all_the_arg_combinations() -> None:
|
||
|
assert g(1, *(2,), **{'c': 3}) == (1, 2, 3, -1)
|
||
|
assert g(*[1], **{'b': 2, 'c': 3, 'd': 4}) == (1, 2, 3, 4)
|
||
|
c = C()
|
||
|
assert c.g(1, *(2,), **{'c': 3}) == (1, 2, 3, -1)
|
||
|
assert c.g(*[1], **{'b': 2, 'c': 3, 'd': 4}) == (1, 2, 3, 4)
|
||
|
|
||
|
[file driver.py]
|
||
|
import native
|
||
|
native.test_all_the_arg_combinations()
|
||
|
|
||
|
[case testOverloads]
|
||
|
from typing import overload, Union, Tuple
|
||
|
|
||
|
@overload
|
||
|
def foo(x: int) -> int: ...
|
||
|
|
||
|
@overload
|
||
|
def foo(x: str) -> str: ...
|
||
|
|
||
|
def foo(x: Union[int, str]) -> Union[int, str]:
|
||
|
return x
|
||
|
|
||
|
class A:
|
||
|
@overload
|
||
|
def foo(self, x: int) -> int: ...
|
||
|
|
||
|
@overload
|
||
|
def foo(self, x: str) -> str: ...
|
||
|
|
||
|
def foo(self, x: Union[int, str]) -> Union[int, str]:
|
||
|
return x
|
||
|
|
||
|
def call1() -> Tuple[int, str]:
|
||
|
return (foo(10), foo('10'))
|
||
|
def call2() -> Tuple[int, str]:
|
||
|
x = A()
|
||
|
return (x.foo(10), x.foo('10'))
|
||
|
|
||
|
[file driver.py]
|
||
|
from native import *
|
||
|
assert call1() == (10, '10')
|
||
|
assert call2() == (10, '10')
|
||
|
|
||
|
[case testDecorators1]
|
||
|
from typing import Generator, Callable, Iterator
|
||
|
from contextlib import contextmanager
|
||
|
|
||
|
def a(f: Callable[[], None]) -> Callable[[], None]:
|
||
|
def g() -> None:
|
||
|
print('Entering')
|
||
|
f()
|
||
|
print('Exited')
|
||
|
return g
|
||
|
|
||
|
def b(f: Callable[[], None]) -> Callable[[], None]:
|
||
|
def g() -> None:
|
||
|
print('***')
|
||
|
f()
|
||
|
print('***')
|
||
|
return g
|
||
|
|
||
|
@contextmanager
|
||
|
def foo() -> Iterator[int]:
|
||
|
try:
|
||
|
print('started')
|
||
|
yield 0
|
||
|
finally:
|
||
|
print('finished')
|
||
|
|
||
|
@contextmanager
|
||
|
def catch() -> Iterator[None]:
|
||
|
try:
|
||
|
print('started')
|
||
|
yield
|
||
|
except IndexError:
|
||
|
print('index')
|
||
|
raise
|
||
|
except Exception:
|
||
|
print('lol')
|
||
|
|
||
|
def thing() -> None:
|
||
|
c()
|
||
|
|
||
|
@a
|
||
|
@b
|
||
|
def c() -> None:
|
||
|
@a
|
||
|
@b
|
||
|
def d() -> None:
|
||
|
print('d')
|
||
|
print('c')
|
||
|
d()
|
||
|
|
||
|
def hm() -> None:
|
||
|
x = [1]
|
||
|
with catch():
|
||
|
x[2]
|
||
|
|
||
|
[file driver.py]
|
||
|
from native import foo, c, thing, hm
|
||
|
|
||
|
with foo() as f:
|
||
|
print('hello')
|
||
|
|
||
|
c()
|
||
|
thing()
|
||
|
print('==')
|
||
|
try:
|
||
|
hm()
|
||
|
except IndexError:
|
||
|
pass
|
||
|
else:
|
||
|
assert False
|
||
|
|
||
|
[out]
|
||
|
started
|
||
|
hello
|
||
|
finished
|
||
|
Entering
|
||
|
***
|
||
|
c
|
||
|
Entering
|
||
|
***
|
||
|
d
|
||
|
***
|
||
|
Exited
|
||
|
***
|
||
|
Exited
|
||
|
Entering
|
||
|
***
|
||
|
c
|
||
|
Entering
|
||
|
***
|
||
|
d
|
||
|
***
|
||
|
Exited
|
||
|
***
|
||
|
Exited
|
||
|
==
|
||
|
started
|
||
|
index
|
||
|
|
||
|
[case testDecoratorsMethods]
|
||
|
from typing import Any, Callable, Iterator, TypeVar
|
||
|
from contextlib import contextmanager
|
||
|
|
||
|
T = TypeVar('T')
|
||
|
def dec(f: T) -> T:
|
||
|
return f
|
||
|
|
||
|
def a(f: Callable[[Any], None]) -> Callable[[Any], None]:
|
||
|
def g(a: Any) -> None:
|
||
|
print('Entering')
|
||
|
f(a)
|
||
|
print('Exited')
|
||
|
return g
|
||
|
|
||
|
class A:
|
||
|
@a
|
||
|
def foo(self) -> None:
|
||
|
print('foo')
|
||
|
|
||
|
@contextmanager
|
||
|
def generator(self) -> Iterator[int]:
|
||
|
try:
|
||
|
print('contextmanager: entering')
|
||
|
yield 0
|
||
|
finally:
|
||
|
print('contextmanager: exited')
|
||
|
|
||
|
class Lol:
|
||
|
@staticmethod
|
||
|
def foo() -> None:
|
||
|
Lol.bar()
|
||
|
Lol.baz()
|
||
|
|
||
|
@staticmethod
|
||
|
@dec
|
||
|
def bar() -> None:
|
||
|
pass
|
||
|
|
||
|
@classmethod
|
||
|
@dec
|
||
|
def baz(cls) -> None:
|
||
|
pass
|
||
|
|
||
|
def inside() -> None:
|
||
|
with A().generator() as g:
|
||
|
print('hello!')
|
||
|
|
||
|
with A().generator() as g:
|
||
|
print('hello!')
|
||
|
|
||
|
def lol() -> None:
|
||
|
with A().generator() as g:
|
||
|
raise Exception
|
||
|
|
||
|
[file driver.py]
|
||
|
from native import A, lol
|
||
|
|
||
|
A.foo(A())
|
||
|
A().foo()
|
||
|
with A().generator() as g:
|
||
|
print('hello!')
|
||
|
try:
|
||
|
lol()
|
||
|
except:
|
||
|
pass
|
||
|
else:
|
||
|
assert False
|
||
|
|
||
|
[out]
|
||
|
contextmanager: entering
|
||
|
hello!
|
||
|
contextmanager: exited
|
||
|
Entering
|
||
|
foo
|
||
|
Exited
|
||
|
Entering
|
||
|
foo
|
||
|
Exited
|
||
|
contextmanager: entering
|
||
|
hello!
|
||
|
contextmanager: exited
|
||
|
contextmanager: entering
|
||
|
contextmanager: exited
|
||
|
|
||
|
[case testUnannotatedFunction]
|
||
|
def g(x: int) -> int:
|
||
|
return x * 2
|
||
|
|
||
|
def f(x):
|
||
|
return g(x)
|
||
|
[file driver.py]
|
||
|
from native import f
|
||
|
assert f(3) == 6
|
||
|
|
||
|
[case testUnannotatedModuleLevelInitFunction]
|
||
|
# Ensure that adding an implicit `-> None` annotation only applies to `__init__`
|
||
|
# _methods_ specifically (not module-level `__init__` functions).
|
||
|
def __init__():
|
||
|
return 42
|
||
|
[file driver.py]
|
||
|
from native import __init__
|
||
|
assert __init__() == 42
|
||
|
|
||
|
[case testDifferentArgCountsFromInterpreted]
|
||
|
# Test various signatures from interpreted code.
|
||
|
def noargs() -> int:
|
||
|
return 5
|
||
|
|
||
|
def onearg(x: int) -> int:
|
||
|
return x + 1
|
||
|
|
||
|
def twoargs(x: int, y: str) -> int:
|
||
|
return x + len(y)
|
||
|
|
||
|
def one_or_two(x: int, y: str = 'a') -> int:
|
||
|
return x + len(y)
|
||
|
|
||
|
[file driver.py]
|
||
|
from native import noargs, onearg, twoargs, one_or_two
|
||
|
from testutil import assertRaises
|
||
|
|
||
|
assert noargs() == 5
|
||
|
t = ()
|
||
|
assert noargs(*t) == 5
|
||
|
d = {}
|
||
|
assert noargs(**d) == 5
|
||
|
assert noargs(*t, **d) == 5
|
||
|
|
||
|
assert onearg(12) == 13
|
||
|
assert onearg(x=8) == 9
|
||
|
t = (1,)
|
||
|
assert onearg(*t) == 2
|
||
|
d = {'x': 5}
|
||
|
assert onearg(**d) == 6
|
||
|
|
||
|
# Test a bogus call to twoargs before any correct calls are made
|
||
|
with assertRaises(TypeError, "twoargs() missing required argument 'x' (pos 1)"):
|
||
|
twoargs()
|
||
|
|
||
|
assert twoargs(5, 'foo') == 8
|
||
|
assert twoargs(4, y='foo') == 7
|
||
|
assert twoargs(y='foo', x=7) == 10
|
||
|
t = (1, 'xy')
|
||
|
assert twoargs(*t) == 3
|
||
|
d = {'y': 'xy'}
|
||
|
assert twoargs(2, **d) == 4
|
||
|
|
||
|
assert one_or_two(5) == 6
|
||
|
assert one_or_two(x=3) == 4
|
||
|
assert one_or_two(6, 'xy') == 8
|
||
|
assert one_or_two(7, y='xy') == 9
|
||
|
assert one_or_two(y='xy', x=2) == 4
|
||
|
assert one_or_two(*t) == 3
|
||
|
d = {'x': 5}
|
||
|
assert one_or_two(**d) == 6
|
||
|
assert one_or_two(y='xx', **d) == 7
|
||
|
d = {'y': 'abc'}
|
||
|
assert one_or_two(1, **d) == 4
|
||
|
|
||
|
with assertRaises(TypeError, 'noargs() takes at most 0 arguments (1 given)'):
|
||
|
noargs(1)
|
||
|
with assertRaises(TypeError, 'noargs() takes at most 0 keyword arguments (1 given)'):
|
||
|
noargs(x=1)
|
||
|
|
||
|
with assertRaises(TypeError, "onearg() missing required argument 'x' (pos 1)"):
|
||
|
onearg()
|
||
|
with assertRaises(TypeError, 'onearg() takes at most 1 argument (2 given)'):
|
||
|
onearg(1, 2)
|
||
|
with assertRaises(TypeError, "onearg() missing required argument 'x' (pos 1)"):
|
||
|
onearg(y=1)
|
||
|
with assertRaises(TypeError, "onearg() takes at most 1 argument (2 given)"):
|
||
|
onearg(1, y=1)
|
||
|
|
||
|
with assertRaises(TypeError, "twoargs() missing required argument 'x' (pos 1)"):
|
||
|
twoargs()
|
||
|
with assertRaises(TypeError, "twoargs() missing required argument 'y' (pos 2)"):
|
||
|
twoargs(1)
|
||
|
with assertRaises(TypeError, 'twoargs() takes at most 2 arguments (3 given)'):
|
||
|
twoargs(1, 'x', 2)
|
||
|
with assertRaises(TypeError, 'twoargs() takes at most 2 arguments (3 given)'):
|
||
|
twoargs(1, 'x', y=2)
|
||
|
|
||
|
with assertRaises(TypeError, "one_or_two() missing required argument 'x' (pos 1)"):
|
||
|
one_or_two()
|
||
|
with assertRaises(TypeError, 'one_or_two() takes at most 2 arguments (3 given)'):
|
||
|
one_or_two(1, 'x', 2)
|
||
|
with assertRaises(TypeError, 'one_or_two() takes at most 2 arguments (3 given)'):
|
||
|
one_or_two(1, 'x', y=2)
|
||
|
|
||
|
[case testComplicatedArgs]
|
||
|
from typing import Tuple, Dict
|
||
|
|
||
|
def kwonly1(x: int = 0, *, y: int) -> Tuple[int, int]:
|
||
|
return x, y
|
||
|
|
||
|
def kwonly2(*, x: int = 0, y: int) -> Tuple[int, int]:
|
||
|
return x, y
|
||
|
|
||
|
def kwonly3(a: int, b: int = 0, *, y: int, x: int = 1) -> Tuple[int, int, int, int]:
|
||
|
return a, b, x, y
|
||
|
|
||
|
def kwonly4(*, x: int, y: int) -> Tuple[int, int]:
|
||
|
return x, y
|
||
|
|
||
|
def varargs1(*args: int) -> Tuple[int, ...]:
|
||
|
return args
|
||
|
|
||
|
def varargs2(*args: int, **kwargs: int) -> Tuple[Tuple[int, ...], Dict[str, int]]:
|
||
|
return args, kwargs
|
||
|
|
||
|
def varargs3(**kwargs: int) -> Dict[str, int]:
|
||
|
return kwargs
|
||
|
|
||
|
def varargs4(a: int, b: int = 0,
|
||
|
*args: int, y: int, x: int = 1,
|
||
|
**kwargs: int) -> Tuple[Tuple[int, ...], Dict[str, int]]:
|
||
|
return (a, b, *args), {'x': x, 'y': y, **kwargs}
|
||
|
|
||
|
class A:
|
||
|
def f(self, x: int) -> Tuple[int, ...]:
|
||
|
return (x,)
|
||
|
def g(self, x: int) -> Tuple[Tuple[int, ...], Dict[str, int]]:
|
||
|
return (x,), {}
|
||
|
|
||
|
class B(A):
|
||
|
def f(self, *args: int) -> Tuple[int, ...]:
|
||
|
return args
|
||
|
def g(self, *args: int, **kwargs: int) -> Tuple[Tuple[int, ...], Dict[str, int]]:
|
||
|
return args, kwargs
|
||
|
|
||
|
[file other.py]
|
||
|
# This file is imported in both compiled and interpreted mode in order to
|
||
|
# test both native calls and calls via the C API.
|
||
|
|
||
|
from native import (
|
||
|
kwonly1, kwonly2, kwonly3, kwonly4,
|
||
|
varargs1, varargs2, varargs3, varargs4,
|
||
|
A, B
|
||
|
)
|
||
|
|
||
|
# kwonly arg tests
|
||
|
assert kwonly1(10, y=20) == (10, 20)
|
||
|
assert kwonly1(y=20) == (0, 20)
|
||
|
|
||
|
assert kwonly2(x=10, y=20) == (10, 20)
|
||
|
assert kwonly2(y=20) == (0, 20)
|
||
|
|
||
|
assert kwonly3(10, y=20) == (10, 0, 1, 20)
|
||
|
assert kwonly3(a=10, y=20) == (10, 0, 1, 20)
|
||
|
assert kwonly3(10, 30, y=20) == (10, 30, 1, 20)
|
||
|
assert kwonly3(10, b=30, y=20) == (10, 30, 1, 20)
|
||
|
assert kwonly3(a=10, b=30, y=20) == (10, 30, 1, 20)
|
||
|
|
||
|
assert kwonly3(10, x=40, y=20) == (10, 0, 40, 20)
|
||
|
assert kwonly3(a=10, x=40, y=20) == (10, 0, 40, 20)
|
||
|
assert kwonly3(10, 30, x=40, y=20) == (10, 30, 40, 20)
|
||
|
assert kwonly3(10, b=30, x=40, y=20) == (10, 30, 40, 20)
|
||
|
assert kwonly3(a=10, b=30, x=40, y=20) == (10, 30, 40, 20)
|
||
|
|
||
|
assert kwonly4(x=1, y=2) == (1, 2)
|
||
|
assert kwonly4(y=2, x=1) == (1, 2)
|
||
|
|
||
|
# varargs tests
|
||
|
assert varargs1() == ()
|
||
|
assert varargs1(1, 2, 3) == (1, 2, 3)
|
||
|
assert varargs1(1, *[2, 3, 4], 5, *[6, 7, 8], 9) == (1, 2, 3, 4, 5, 6, 7, 8, 9)
|
||
|
assert varargs2(1, 2, 3) == ((1, 2, 3), {})
|
||
|
assert varargs2(1, 2, 3, x=4) == ((1, 2, 3), {'x': 4})
|
||
|
assert varargs2(x=4) == ((), {'x': 4})
|
||
|
assert varargs3() == {}
|
||
|
assert varargs3(x=4) == {'x': 4}
|
||
|
assert varargs3(x=4, y=5) == {'x': 4, 'y': 5}
|
||
|
|
||
|
assert varargs4(-1, y=2) == ((-1, 0), {'x': 1, 'y': 2})
|
||
|
assert varargs4(-1, 2, y=2) == ((-1, 2), {'x': 1, 'y': 2})
|
||
|
assert varargs4(-1, 2, 3, y=2) == ((-1, 2, 3), {'x': 1, 'y': 2})
|
||
|
assert varargs4(-1, 2, 3, x=10, y=2) == ((-1, 2, 3), {'x': 10, 'y': 2})
|
||
|
assert varargs4(-1, x=10, y=2) == ((-1, 0), {'x': 10, 'y': 2})
|
||
|
assert varargs4(-1, y=2, z=20) == ((-1, 0), {'x': 1, 'y': 2, 'z': 20})
|
||
|
assert varargs4(-1, 2, y=2, z=20) == ((-1, 2), {'x': 1, 'y': 2, 'z': 20})
|
||
|
assert varargs4(-1, 2, 3, y=2, z=20) == ((-1, 2, 3), {'x': 1, 'y': 2, 'z': 20})
|
||
|
assert varargs4(-1, 2, 3, x=10, y=2, z=20) == ((-1, 2, 3), {'x': 10, 'y': 2, 'z': 20})
|
||
|
assert varargs4(-1, x=10, y=2, z=20) == ((-1, 0), {'x': 10, 'y': 2, 'z': 20})
|
||
|
|
||
|
x = B() # type: A
|
||
|
assert x.f(1) == (1,)
|
||
|
assert x.g(1) == ((1,), {})
|
||
|
# This one is really funny! When we make native calls we lose
|
||
|
# track of which arguments are positional or keyword, so the glue
|
||
|
# calls them all positional unless they are keyword only...
|
||
|
# It would be possible to fix this by dynamically tracking which
|
||
|
# arguments were passed by keyword (for example, by passing a bitmask
|
||
|
# to functions indicating this), but paying a speed, size, and complexity
|
||
|
# cost for something so deeply marginal seems like a bad choice.
|
||
|
# assert x.g(x=1) == ((), {'x': 1})
|
||
|
|
||
|
[file driver.py]
|
||
|
from testutil import assertRaises
|
||
|
from native import (
|
||
|
kwonly1, kwonly2, kwonly3, kwonly4,
|
||
|
varargs1, varargs2, varargs3, varargs4,
|
||
|
)
|
||
|
|
||
|
# Run the non-exceptional tests in both interpreted and compiled mode
|
||
|
import other
|
||
|
import other_interpreted
|
||
|
|
||
|
|
||
|
# And the tests for errors at the interfaces in interpreted only
|
||
|
with assertRaises(TypeError, "missing required keyword-only argument 'y'"):
|
||
|
kwonly1()
|
||
|
with assertRaises(TypeError, "takes at most 1 positional argument (2 given)"):
|
||
|
kwonly1(10, 20)
|
||
|
|
||
|
with assertRaises(TypeError, "missing required keyword-only argument 'y'"):
|
||
|
kwonly2()
|
||
|
with assertRaises(TypeError, "takes no positional arguments"):
|
||
|
kwonly2(10, 20)
|
||
|
|
||
|
with assertRaises(TypeError, "missing required argument 'a'"):
|
||
|
kwonly3(b=30, x=40, y=20)
|
||
|
with assertRaises(TypeError, "missing required keyword-only argument 'y'"):
|
||
|
kwonly3(10)
|
||
|
|
||
|
with assertRaises(TypeError, "missing required keyword-only argument 'y'"):
|
||
|
kwonly4(x=1)
|
||
|
with assertRaises(TypeError, "missing required keyword-only argument 'x'"):
|
||
|
kwonly4(y=1)
|
||
|
with assertRaises(TypeError, "missing required keyword-only argument 'x'"):
|
||
|
kwonly4()
|
||
|
|
||
|
with assertRaises(TypeError, "'x' is an invalid keyword argument for varargs1()"):
|
||
|
varargs1(x=10)
|
||
|
with assertRaises(TypeError, "'x' is an invalid keyword argument for varargs1()"):
|
||
|
varargs1(1, x=10)
|
||
|
with assertRaises(TypeError, "varargs3() takes no positional arguments"):
|
||
|
varargs3(10)
|
||
|
with assertRaises(TypeError, "varargs3() takes no positional arguments"):
|
||
|
varargs3(10, x=10)
|
||
|
|
||
|
with assertRaises(TypeError, "varargs4() missing required argument 'a' (pos 1)"):
|
||
|
varargs4()
|
||
|
with assertRaises(TypeError, "varargs4() missing required keyword-only argument 'y'"):
|
||
|
varargs4(1, 2)
|
||
|
with assertRaises(TypeError, "varargs4() missing required keyword-only argument 'y'"):
|
||
|
varargs4(1, 2, x=1)
|
||
|
with assertRaises(TypeError, "varargs4() missing required keyword-only argument 'y'"):
|
||
|
varargs4(1, 2, 3)
|
||
|
with assertRaises(TypeError, "varargs4() missing required argument 'a' (pos 1)"):
|
||
|
varargs4(y=20)
|
||
|
|
||
|
[case testDecoratorName]
|
||
|
def dec(f): return f
|
||
|
|
||
|
@dec
|
||
|
def foo(): pass
|
||
|
|
||
|
def test_decorator_name():
|
||
|
assert foo.__name__ == "foo"
|
||
|
|
||
|
[case testLambdaArgToOverloaded]
|
||
|
from lib import sub
|
||
|
|
||
|
def test_str_overload() -> None:
|
||
|
assert sub('x', lambda m: m) == 'x'
|
||
|
|
||
|
def test_bytes_overload() -> None:
|
||
|
assert sub(b'x', lambda m: m) == b'x'
|
||
|
|
||
|
[file lib.py]
|
||
|
from typing import overload, Callable, TypeVar, Generic
|
||
|
|
||
|
T = TypeVar("T")
|
||
|
|
||
|
class Match(Generic[T]):
|
||
|
def __init__(self, x: T) -> None:
|
||
|
self.x = x
|
||
|
|
||
|
def group(self, n: int) -> T:
|
||
|
return self.x
|
||
|
|
||
|
@overload
|
||
|
def sub(s: str, f: Callable[[str], str]) -> str: ...
|
||
|
@overload
|
||
|
def sub(s: bytes, f: Callable[[bytes], bytes]) -> bytes: ...
|
||
|
def sub(s, f):
|
||
|
return f(s)
|
||
|
|
||
|
[case testContextManagerSpecialCase]
|
||
|
from typing import Generator, Callable, Iterator
|
||
|
from contextlib import contextmanager
|
||
|
|
||
|
@contextmanager
|
||
|
def f() -> Iterator[None]:
|
||
|
yield
|
||
|
|
||
|
def g() -> None:
|
||
|
a = ['']
|
||
|
with f():
|
||
|
a.pop()
|
||
|
|
||
|
g()
|