| # 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_function() -> 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_function() -> 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_function() -> 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 |
| |
| def bool_default(x: bool = False, y: bool = True) -> str: |
| return str(x) + '-' + str(y) |
| |
| [file driver.py] |
| from native import f, g, h, same, nested_funcs, a_lambda, bool_default |
| 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 |
| |
| assert bool_default() == 'False-True' |
| assert bool_default(True) == 'True-True' |
| assert bool_default(True, False) == 'True-False' |
| |
| [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() |
| |
| [case testUnpackKwargsCompiled] |
| from typing import TypedDict |
| from typing_extensions import Unpack |
| |
| class Person(TypedDict): |
| name: str |
| age: int |
| |
| def foo(**kwargs: Unpack[Person]) -> None: |
| print(kwargs["name"]) |
| |
| # This is not really supported yet, just test that we behave reasonably. |
| foo(name='Jennifer', age=38) |
| [typing fixtures/typing-full.pyi] |
| [out] |
| Jennifer |
| |
| [case testNestedFunctionDunderDict312] |
| import sys |
| |
| def foo() -> None: |
| def inner() -> str: return "bar" |
| print(inner.__dict__) # type: ignore[attr-defined] |
| inner.__dict__.update({"x": 1}) # type: ignore[attr-defined] |
| print(inner.__dict__) # type: ignore[attr-defined] |
| print(inner.x) # type: ignore[attr-defined] |
| |
| if sys.version_info >= (3, 12): # type: ignore |
| foo() |
| [out] |
| [out version>=3.12] |
| {} |
| {'x': 1} |
| 1 |
| |
| [case testFunctoolsUpdateWrapper] |
| import functools |
| |
| def bar() -> None: |
| def inner() -> str: return "bar" |
| functools.update_wrapper(inner, bar) # type: ignore |
| print(inner.__dict__) # type: ignore |
| |
| bar() |
| [out] |
| {'__module__': 'native', '__name__': 'bar', '__qualname__': 'bar', '__doc__': None, '__wrapped__': <built-in function bar>} |
| |
| [case testCallNestedFunctionWithNamed] |
| def f() -> None: |
| def a() -> None: |
| pass |
| def b() -> None: |
| a() |
| b() |
| [file driver.py] |
| from native import f |
| f() |
| |
| [case testCallNestedFunctionWithLambda] |
| def f(x: int) -> int: |
| def inc(x: int) -> int: |
| return x + 1 |
| return (lambda x: inc(x))(1) |
| [file driver.py] |
| from native import f |
| print(f(1)) |
| [out] |
| 2 |