From b17f82753ecd22932f740880a038ad50786a8286 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 20:00:51 +0100 Subject: [PATCH 01/14] Move some lists tests to a separate test file --- mypyc/test-data/run-classes.test | 23 ------ mypyc/test-data/run-lists.test | 128 +++++++++++++++++++++++++++++++ mypyc/test-data/run.test | 105 ------------------------- mypyc/test/test_run.py | 1 + 4 files changed, 129 insertions(+), 128 deletions(-) create mode 100644 mypyc/test-data/run-lists.test diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index db910bacf055..42b41e219b7c 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -390,29 +390,6 @@ assert c.a == 13 assert type(c) == C assert not hasattr(c, 'b') -[case testListOfUserDefinedClass] -class C: - x: int - -def f() -> int: - c = C() - c.x = 5 - a = [c] - d = a[0] - return d.x + 1 - -def g() -> int: - a = [C()] - a[0].x = 3 - return a[0].x + 4 -[file driver.py] -from native import f, g -print(f()) -print(g()) -[out] -6 -7 - [case testCastUserClass] from typing import List diff --git a/mypyc/test-data/run-lists.test b/mypyc/test-data/run-lists.test new file mode 100644 index 000000000000..ac1f9b392007 --- /dev/null +++ b/mypyc/test-data/run-lists.test @@ -0,0 +1,128 @@ +# Test cases for strings (compile and run) + +[case testListPlusEquals] +from typing import Any +def append(x: Any) -> None: + x += [1] + +[file driver.py] +from native import append +x = [] +append(x) +assert x == [1] + +[case testListSum] +from typing import List +def sum(a: List[int], l: int) -> int: + sum = 0 + i = 0 + while i < l: + sum = sum + a[i] + i = i + 1 + return sum +[file driver.py] +from native import sum +print(sum([], 0)) +print(sum([3], 1)) +print(sum([5, 6, -4], 3)) +print(sum([2**128 + 5, -2**127 - 8], 2)) +[out] +0 +3 +7 +170141183460469231731687303715884105725 + +[case testListSet] +from typing import List +def copy(a: List[int], b: List[int], l: int) -> int: + i = 0 + while i < l: + a[i] = b[i] + i = i + 1 + return 0 +[file driver.py] +from native import copy +a = [0, ''] +copy(a, [-1, 5], 2) +print(1, a) +copy(a, [2**128 + 5, -2**127 - 8], 2) +print(2, a) +[out] +1 [-1, 5] +2 [340282366920938463463374607431768211461, -170141183460469231731687303715884105736] + +[case testSieve] +from typing import List + +def primes(n: int) -> List[int]: + a = [1] * (n + 1) + a[0] = 0 + a[1] = 0 + i = 0 + while i < n: + if a[i] == 1: + j = i * i + while j < n: + a[j] = 0 + j = j + i + i = i + 1 + return a +[file driver.py] +from native import primes +print(primes(3)) +print(primes(13)) +[out] +\[0, 0, 1, 1] +\[0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1] + +[case testListPrims] +from typing import List +def append(x: List[int], n: int) -> None: + x.append(n) +def pop_last(x: List[int]) -> int: + return x.pop() +def pop(x: List[int], i: int) -> int: + return x.pop(i) +def count(x: List[int], i: int) -> int: + return x.count(i) +[file driver.py] +from native import append, pop_last, pop, count +l = [1, 2] +append(l, 10) +assert l == [1, 2, 10] +append(l, 3) +append(l, 4) +append(l, 5) +assert l == [1, 2, 10, 3, 4, 5] +pop_last(l) +pop_last(l) +assert l == [1, 2, 10, 3] +pop(l, 2) +assert l == [1, 2, 3] +pop(l, -2) +assert l == [1, 3] +assert count(l, 1) == 1 +assert count(l, 2) == 0 + +[case testListOfUserDefinedClass] +class C: + x: int + +def f() -> int: + c = C() + c.x = 5 + a = [c] + d = a[0] + return d.x + 1 + +def g() -> int: + a = [C()] + a[0].x = 3 + return a[0].x + 4 +[file driver.py] +from native import f, g +print(f()) +print(g()) +[out] +6 +7 diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index 8db18e19ef7d..af05e904f532 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -364,111 +364,6 @@ print(fib(6)) 2 13 -[case testListPlusEquals] -from typing import Any -def append(x: Any) -> None: - x += [1] - -[file driver.py] -from native import append -x = [] -append(x) -assert x == [1] - -[case testListSum] -from typing import List -def sum(a: List[int], l: int) -> int: - sum = 0 - i = 0 - while i < l: - sum = sum + a[i] - i = i + 1 - return sum -[file driver.py] -from native import sum -print(sum([], 0)) -print(sum([3], 1)) -print(sum([5, 6, -4], 3)) -print(sum([2**128 + 5, -2**127 - 8], 2)) -[out] -0 -3 -7 -170141183460469231731687303715884105725 - -[case testListSet] -from typing import List -def copy(a: List[int], b: List[int], l: int) -> int: - i = 0 - while i < l: - a[i] = b[i] - i = i + 1 - return 0 -[file driver.py] -from native import copy -a = [0, ''] -copy(a, [-1, 5], 2) -print(1, a) -copy(a, [2**128 + 5, -2**127 - 8], 2) -print(2, a) -[out] -1 [-1, 5] -2 [340282366920938463463374607431768211461, -170141183460469231731687303715884105736] - -[case testSieve] -from typing import List - -def primes(n: int) -> List[int]: - a = [1] * (n + 1) - a[0] = 0 - a[1] = 0 - i = 0 - while i < n: - if a[i] == 1: - j = i * i - while j < n: - a[j] = 0 - j = j + i - i = i + 1 - return a -[file driver.py] -from native import primes -print(primes(3)) -print(primes(13)) -[out] -\[0, 0, 1, 1] -\[0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1] - - -[case testListPrims] -from typing import List -def append(x: List[int], n: int) -> None: - x.append(n) -def pop_last(x: List[int]) -> int: - return x.pop() -def pop(x: List[int], i: int) -> int: - return x.pop(i) -def count(x: List[int], i: int) -> int: - return x.count(i) -[file driver.py] -from native import append, pop_last, pop, count -l = [1, 2] -append(l, 10) -assert l == [1, 2, 10] -append(l, 3) -append(l, 4) -append(l, 5) -assert l == [1, 2, 10, 3, 4, 5] -pop_last(l) -pop_last(l) -assert l == [1, 2, 10, 3] -pop(l, 2) -assert l == [1, 2, 3] -pop(l, -2) -assert l == [1, 3] -assert count(l, 1) == 1 -assert count(l, 2) == 0 - [case testTrue] def f() -> bool: return True diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index bbe4d31a8dbc..f1b9f0624b47 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -34,6 +34,7 @@ 'run.test', 'run-strings.test', 'run-tuples.test', + 'run-lists.test', 'run-classes.test', 'run-traits.test', 'run-multimodule.test', From 2c54f480da5c9bc41cbc5b9b1b89a2bd44fe6861 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 20:03:06 +0100 Subject: [PATCH 02/14] Move some dict run tests to a separate file --- mypyc/test-data/run-dicts.test | 194 +++++++++++++++++++++++++++++++++ mypyc/test-data/run.test | 193 -------------------------------- mypyc/test/test_run.py | 1 + 3 files changed, 195 insertions(+), 193 deletions(-) create mode 100644 mypyc/test-data/run-dicts.test diff --git a/mypyc/test-data/run-dicts.test b/mypyc/test-data/run-dicts.test new file mode 100644 index 000000000000..cac68b9af060 --- /dev/null +++ b/mypyc/test-data/run-dicts.test @@ -0,0 +1,194 @@ +# Dict test cases (compile and run) + +[case testDictStuff] +from typing import Dict, Any, List, Set, Tuple +from defaultdictwrap import make_dict + +def f(x: int) -> int: + dict1 = {} # type: Dict[int, int] + dict1[1] = 1 + dict2 = {} # type: Dict[int, int] + dict2[x] = 2 + dict1.update(dict2) + + l = [(5, 2)] # type: Any + dict1.update(l) + d2 = {6: 4} # type: Any + dict1.update(d2) + + return dict1[1] + +def g() -> int: + d = make_dict() + d['a'] = 10 + d['a'] += 10 + d['b'] += 10 + l = [('c', 2)] # type: Any + d.update(l) + d2 = {'d': 4} # type: Any + d.update(d2) + return d['a'] + d['b'] + +def h() -> None: + d = {} # type: Dict[Any, Any] + d[{}] + +def update_dict(x: Dict[Any, Any], y: Any): + x.update(y) + +def make_dict1(x: Any) -> Dict[Any, Any]: + return dict(x) + +def make_dict2(x: Dict[Any, Any]) -> Dict[Any, Any]: + return dict(x) + +def u(x: int) -> int: + d = {} # type: Dict[str, int] + d.update(x=x) + return d['x'] + +def get_content(d: Dict[int, int]) -> Tuple[List[int], List[int], List[Tuple[int, int]]]: + return list(d.keys()), list(d.values()), list(d.items()) + +def get_content_set(d: Dict[int, int]) -> Tuple[Set[int], Set[int], Set[Tuple[int, int]]]: + return set(d.keys()), set(d.values()), set(d.items()) +[file defaultdictwrap.py] +from typing import Dict +from collections import defaultdict # type: ignore +def make_dict() -> Dict[str, int]: + return defaultdict(int) + +[file driver.py] +from collections import OrderedDict +from native import ( + f, g, h, u, make_dict1, make_dict2, update_dict, get_content, get_content_set +) +assert f(1) == 2 +assert f(2) == 1 +assert g() == 30 +# Make sure we get a TypeError from indexing with unhashable and not KeyError +try: + h() +except TypeError: + pass +else: + assert False +d = {'a': 1, 'b': 2} +assert make_dict1(d) == d +assert make_dict1(d.items()) == d +assert make_dict2(d) == d +# object.__dict__ is a "mappingproxy" and not a dict +assert make_dict1(object.__dict__) == dict(object.__dict__) +d = {} +update_dict(d, object.__dict__) +assert d == dict(object.__dict__) + +assert u(10) == 10 +assert get_content({1: 2}) == ([1], [2], [(1, 2)]) +od = OrderedDict([(1, 2), (3, 4)]) +assert get_content(od) == ([1, 3], [2, 4], [(1, 2), (3, 4)]) +od.move_to_end(1) +assert get_content(od) == ([3, 1], [4, 2], [(3, 4), (1, 2)]) +assert get_content_set({1: 2}) == ({1}, {2}, {(1, 2)}) +assert get_content_set(od) == ({1, 3}, {2, 4}, {(1, 2), (3, 4)}) +[typing fixtures/typing-full.pyi] + +[case testDictIterationMethodsRun] +from typing import Dict +def print_dict_methods(d1: Dict[int, int], + d2: Dict[int, int], + d3: Dict[int, int]) -> None: + for k in d1.keys(): + print(k) + for k, v in d2.items(): + print(k) + print(v) + for v in d3.values(): + print(v) + +def clear_during_iter(d: Dict[int, int]) -> None: + for k in d: + d.clear() + +class Custom(Dict[int, int]): pass +[file driver.py] +from native import print_dict_methods, Custom, clear_during_iter +from collections import OrderedDict +print_dict_methods({}, {}, {}) +print_dict_methods({1: 2}, {3: 4, 5: 6}, {7: 8}) +print('==') +c = Custom({0: 1}) +print_dict_methods(c, c, c) +print('==') +d = OrderedDict([(1, 2), (3, 4)]) +print_dict_methods(d, d, d) +print('==') +d.move_to_end(1) +print_dict_methods(d, d, d) +clear_during_iter({}) # OK +try: + clear_during_iter({1: 2, 3: 4}) +except RuntimeError as e: + assert str(e) == "dictionary changed size during iteration" +else: + assert False +try: + clear_during_iter(d) +except RuntimeError as e: + assert str(e) == "OrderedDict changed size during iteration" +else: + assert False + +class CustomMad(dict): + def __iter__(self): + return self + def __next__(self): + raise ValueError +m = CustomMad() +try: + clear_during_iter(m) +except ValueError: + pass +else: + assert False + +class CustomBad(dict): + def items(self): + return [(1, 2, 3)] # Oops +b = CustomBad() +try: + print_dict_methods(b, b, b) +except TypeError as e: + assert str(e) == "a tuple of length 2 expected" +else: + assert False +[out] +1 +3 +4 +5 +6 +8 +== +0 +0 +1 +1 +== +1 +3 +1 +2 +3 +4 +2 +4 +== +3 +1 +3 +4 +1 +2 +4 +2 diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index af05e904f532..0d1899ae61a5 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -707,199 +707,6 @@ s = {1, 2, 3} update(s, [5, 4, 3]) assert s == {1, 2, 3, 4, 5} -[case testDictStuff] -from typing import Dict, Any, List, Set, Tuple -from defaultdictwrap import make_dict - -def f(x: int) -> int: - dict1 = {} # type: Dict[int, int] - dict1[1] = 1 - dict2 = {} # type: Dict[int, int] - dict2[x] = 2 - dict1.update(dict2) - - l = [(5, 2)] # type: Any - dict1.update(l) - d2 = {6: 4} # type: Any - dict1.update(d2) - - return dict1[1] - -def g() -> int: - d = make_dict() - d['a'] = 10 - d['a'] += 10 - d['b'] += 10 - l = [('c', 2)] # type: Any - d.update(l) - d2 = {'d': 4} # type: Any - d.update(d2) - return d['a'] + d['b'] - -def h() -> None: - d = {} # type: Dict[Any, Any] - d[{}] - -def update_dict(x: Dict[Any, Any], y: Any): - x.update(y) - -def make_dict1(x: Any) -> Dict[Any, Any]: - return dict(x) - -def make_dict2(x: Dict[Any, Any]) -> Dict[Any, Any]: - return dict(x) - -def u(x: int) -> int: - d = {} # type: Dict[str, int] - d.update(x=x) - return d['x'] - -def get_content(d: Dict[int, int]) -> Tuple[List[int], List[int], List[Tuple[int, int]]]: - return list(d.keys()), list(d.values()), list(d.items()) - -def get_content_set(d: Dict[int, int]) -> Tuple[Set[int], Set[int], Set[Tuple[int, int]]]: - return set(d.keys()), set(d.values()), set(d.items()) -[file defaultdictwrap.py] -from typing import Dict -from collections import defaultdict # type: ignore -def make_dict() -> Dict[str, int]: - return defaultdict(int) - -[file driver.py] -from collections import OrderedDict -from native import ( - f, g, h, u, make_dict1, make_dict2, update_dict, get_content, get_content_set -) -assert f(1) == 2 -assert f(2) == 1 -assert g() == 30 -# Make sure we get a TypeError from indexing with unhashable and not KeyError -try: - h() -except TypeError: - pass -else: - assert False -d = {'a': 1, 'b': 2} -assert make_dict1(d) == d -assert make_dict1(d.items()) == d -assert make_dict2(d) == d -# object.__dict__ is a "mappingproxy" and not a dict -assert make_dict1(object.__dict__) == dict(object.__dict__) -d = {} -update_dict(d, object.__dict__) -assert d == dict(object.__dict__) - -assert u(10) == 10 -assert get_content({1: 2}) == ([1], [2], [(1, 2)]) -od = OrderedDict([(1, 2), (3, 4)]) -assert get_content(od) == ([1, 3], [2, 4], [(1, 2), (3, 4)]) -od.move_to_end(1) -assert get_content(od) == ([3, 1], [4, 2], [(3, 4), (1, 2)]) -assert get_content_set({1: 2}) == ({1}, {2}, {(1, 2)}) -assert get_content_set(od) == ({1, 3}, {2, 4}, {(1, 2), (3, 4)}) -[typing fixtures/typing-full.pyi] - -[case testDictIterationMethodsRun] -from typing import Dict -def print_dict_methods(d1: Dict[int, int], - d2: Dict[int, int], - d3: Dict[int, int]) -> None: - for k in d1.keys(): - print(k) - for k, v in d2.items(): - print(k) - print(v) - for v in d3.values(): - print(v) - -def clear_during_iter(d: Dict[int, int]) -> None: - for k in d: - d.clear() - -class Custom(Dict[int, int]): pass -[file driver.py] -from native import print_dict_methods, Custom, clear_during_iter -from collections import OrderedDict -print_dict_methods({}, {}, {}) -print_dict_methods({1: 2}, {3: 4, 5: 6}, {7: 8}) -print('==') -c = Custom({0: 1}) -print_dict_methods(c, c, c) -print('==') -d = OrderedDict([(1, 2), (3, 4)]) -print_dict_methods(d, d, d) -print('==') -d.move_to_end(1) -print_dict_methods(d, d, d) -clear_during_iter({}) # OK -try: - clear_during_iter({1: 2, 3: 4}) -except RuntimeError as e: - assert str(e) == "dictionary changed size during iteration" -else: - assert False -try: - clear_during_iter(d) -except RuntimeError as e: - assert str(e) == "OrderedDict changed size during iteration" -else: - assert False - -class CustomMad(dict): - def __iter__(self): - return self - def __next__(self): - raise ValueError -m = CustomMad() -try: - clear_during_iter(m) -except ValueError: - pass -else: - assert False - -class CustomBad(dict): - def items(self): - return [(1, 2, 3)] # Oops -b = CustomBad() -try: - print_dict_methods(b, b, b) -except TypeError as e: - assert str(e) == "a tuple of length 2 expected" -else: - assert False -[out] -1 -3 -4 -5 -6 -8 -== -0 -0 -1 -1 -== -1 -3 -1 -2 -3 -4 -2 -4 -== -3 -1 -3 -4 -1 -2 -4 -2 - [case testPyMethodCall] from typing import List def f(x: List[int]) -> int: diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index f1b9f0624b47..03f6b471d408 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -35,6 +35,7 @@ 'run-strings.test', 'run-tuples.test', 'run-lists.test', + 'run-dicts.test', 'run-classes.test', 'run-traits.test', 'run-multimodule.test', From aa1678de4581078e5af83e65505c5a90640fce05 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 20:07:41 +0100 Subject: [PATCH 03/14] Move integer run tests to a separate file --- mypyc/test-data/run-integers.test | 132 ++++++++++++++++++++++++++++++ mypyc/test-data/run.test | 131 ----------------------------- mypyc/test/test_run.py | 1 + 3 files changed, 133 insertions(+), 131 deletions(-) create mode 100644 mypyc/test-data/run-integers.test diff --git a/mypyc/test-data/run-integers.test b/mypyc/test-data/run-integers.test new file mode 100644 index 000000000000..a24a36470207 --- /dev/null +++ b/mypyc/test-data/run-integers.test @@ -0,0 +1,132 @@ +# Test cases for integers (compile and run) + +[case testInc] +def inc(x: int) -> int: + return x + 1 +[file driver.py] +from native import inc +print(inc(3)) +print(inc(-5)) +print(inc(10**20)) +[out] +4 +-4 +100000000000000000001 + +[case testCount] +def count(n: int) -> int: + i = 1 + while i <= n: + i = i + 1 + return i +[file driver.py] +from native import count +print(count(0)) +print(count(1)) +print(count(5)) +[out] +1 +2 +6 + +[case testIntMathOps] +# This tests integer math things that are either easier to test in Python than +# in our C tests or are tested here because (for annoying reasons) we don't run +# the C unit tests in our 32-bit CI. +def multiply(x: int, y: int) -> int: + return x * y + +# these stringify their outputs because that will catch if exceptions are mishandled +def floor_div(x: int, y: int) -> str: + return str(x // y) +def remainder(x: int, y: int) -> str: + return str(x % y) + +[file driver.py] +from native import multiply, floor_div, remainder + +def test_multiply(x, y): + assert multiply(x, y) == x * y +def test_floor_div(x, y): + assert floor_div(x, y) == str(x // y) +def test_remainder(x, y): + assert remainder(x, y) == str(x % y) + +test_multiply(10**6, 10**6) +test_multiply(2**15, 2**15-1) +test_multiply(2**14, 2**14) + +test_multiply(10**12, 10**12) +test_multiply(2**30, 2**30-1) +test_multiply(2**29, 2**29) + +test_floor_div(-2**62, -1) +test_floor_div(-2**30, -1) +try: + floor_div(10, 0) +except ZeroDivisionError: + pass +else: + assert False, "Expected ZeroDivisionError" + +test_remainder(-2**62, -1) +test_remainder(-2**30, -1) +try: + remainder(10, 0) +except ZeroDivisionError: + pass +else: + assert False, "Expected ZeroDivisionError" + +[case testBigIntLiteral] +def big_int() -> None: + a_62_bit = 4611686018427387902 + max_62_bit = 4611686018427387903 + b_63_bit = 4611686018427387904 + c_63_bit = 9223372036854775806 + max_63_bit = 9223372036854775807 + d_64_bit = 9223372036854775808 + max_32_bit = 2147483647 + max_31_bit = 1073741823 + print(a_62_bit) + print(max_62_bit) + print(b_63_bit) + print(c_63_bit) + print(max_63_bit) + print(d_64_bit) + print(max_32_bit) + print(max_31_bit) +[file driver.py] +from native import big_int +big_int() +[out] +4611686018427387902 +4611686018427387903 +4611686018427387904 +9223372036854775806 +9223372036854775807 +9223372036854775808 +2147483647 +1073741823 + +[case testNeg] +def neg(x: int) -> int: + return -x +[file driver.py] +from native import neg +assert neg(5) == -5 +assert neg(-5) == 5 +assert neg(1073741823) == -1073741823 +assert neg(-1073741823) == 1073741823 +assert neg(1073741824) == -1073741824 +assert neg(-1073741824) == 1073741824 +assert neg(2147483647) == -2147483647 +assert neg(-2147483647) == 2147483647 +assert neg(2147483648) == -2147483648 +assert neg(-2147483648) == 2147483648 +assert neg(4611686018427387904) == -4611686018427387904 +assert neg(-4611686018427387904) == 4611686018427387904 +assert neg(9223372036854775807) == -9223372036854775807 +assert neg(-9223372036854775807) == 9223372036854775807 +assert neg(9223372036854775808) == -9223372036854775808 +assert neg(-9223372036854775808) == 9223372036854775808 diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index 0d1899ae61a5..9a3f0bdd4e49 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -15,35 +15,6 @@ print(f(-10**20)) 100000000000000000000 -100000000000000000000 -[case testInc] -def inc(x: int) -> int: - return x + 1 -[file driver.py] -from native import inc -print(inc(3)) -print(inc(-5)) -print(inc(10**20)) -[out] -4 --4 -100000000000000000001 - -[case testCount] -def count(n: int) -> int: - i = 1 - while i <= n: - i = i + 1 - return i -[file driver.py] -from native import count -print(count(0)) -print(count(1)) -print(count(5)) -[out] -1 -2 -6 - [case testFor] from typing import List, Tuple def count(n: int) -> None: @@ -1418,55 +1389,6 @@ assert get_item(d, 'x') == 5 set_item(d, 'y', 6) assert d['y'] == 6 -[case testIntMathOps] -# This tests integer math things that are either easier to test in Python than -# in our C tests or are tested here because (for annoying reasons) we don't run -# the C unit tests in our 32-bit CI. -def multiply(x: int, y: int) -> int: - return x * y - -# these stringify their outputs because that will catch if exceptions are mishandled -def floor_div(x: int, y: int) -> str: - return str(x // y) -def remainder(x: int, y: int) -> str: - return str(x % y) - -[file driver.py] -from native import multiply, floor_div, remainder - -def test_multiply(x, y): - assert multiply(x, y) == x * y -def test_floor_div(x, y): - assert floor_div(x, y) == str(x // y) -def test_remainder(x, y): - assert remainder(x, y) == str(x % y) - -test_multiply(10**6, 10**6) -test_multiply(2**15, 2**15-1) -test_multiply(2**14, 2**14) - -test_multiply(10**12, 10**12) -test_multiply(2**30, 2**30-1) -test_multiply(2**29, 2**29) - -test_floor_div(-2**62, -1) -test_floor_div(-2**30, -1) -try: - floor_div(10, 0) -except ZeroDivisionError: - pass -else: - assert False, "Expected ZeroDivisionError" - -test_remainder(-2**62, -1) -test_remainder(-2**30, -1) -try: - remainder(10, 0) -except ZeroDivisionError: - pass -else: - assert False, "Expected ZeroDivisionError" - [case testSubclassAttributeAccess] from mypy_extensions import trait @@ -1608,37 +1530,6 @@ assert not eq(b'123', b'1234') assert neq(b'123', b'1234') assert join() == b'1\x07"\x07\xf0' -[case testBigIntLiteral] -def big_int() -> None: - a_62_bit = 4611686018427387902 - max_62_bit = 4611686018427387903 - b_63_bit = 4611686018427387904 - c_63_bit = 9223372036854775806 - max_63_bit = 9223372036854775807 - d_64_bit = 9223372036854775808 - max_32_bit = 2147483647 - max_31_bit = 1073741823 - print(a_62_bit) - print(max_62_bit) - print(b_63_bit) - print(c_63_bit) - print(max_63_bit) - print(d_64_bit) - print(max_32_bit) - print(max_31_bit) -[file driver.py] -from native import big_int -big_int() -[out] -4611686018427387902 -4611686018427387903 -4611686018427387904 -9223372036854775806 -9223372036854775807 -9223372036854775808 -2147483647 -1073741823 - [case testForIterable] from typing import Iterable, Dict, Any, Tuple def iterate_over_any(a: Any) -> None: @@ -1743,28 +1634,6 @@ RuntimeError: dictionary changed size during iteration 2 3 -[case testNeg] -def neg(x: int) -> int: - return -x -[file driver.py] -from native import neg -assert neg(5) == -5 -assert neg(-5) == 5 -assert neg(1073741823) == -1073741823 -assert neg(-1073741823) == 1073741823 -assert neg(1073741824) == -1073741824 -assert neg(-1073741824) == 1073741824 -assert neg(2147483647) == -2147483647 -assert neg(-2147483647) == 2147483647 -assert neg(2147483648) == -2147483648 -assert neg(-2147483648) == 2147483648 -assert neg(4611686018427387904) == -4611686018427387904 -assert neg(-4611686018427387904) == 4611686018427387904 -assert neg(9223372036854775807) == -9223372036854775807 -assert neg(-9223372036854775807) == 9223372036854775807 -assert neg(9223372036854775808) == -9223372036854775808 -assert neg(-9223372036854775808) == 9223372036854775808 - [case testContinueFor] def f() -> None: for n in range(5): diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index 03f6b471d408..86ac379984e1 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -32,6 +32,7 @@ files = [ 'run-functions.test', 'run.test', + 'run-integers.test', 'run-strings.test', 'run-tuples.test', 'run-lists.test', From 4197ec838afa5875ac980d49cb37be2fce783452 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 20:12:35 +0100 Subject: [PATCH 04/14] Move generators and yield run tests to a new file --- mypyc/test-data/run-generators.test | 518 ++++++++++++++++++++++++++++ mypyc/test-data/run.test | 517 --------------------------- mypyc/test/test_run.py | 3 +- 3 files changed, 520 insertions(+), 518 deletions(-) create mode 100644 mypyc/test-data/run-generators.test diff --git a/mypyc/test-data/run-generators.test b/mypyc/test-data/run-generators.test new file mode 100644 index 000000000000..3f34c732b522 --- /dev/null +++ b/mypyc/test-data/run-generators.test @@ -0,0 +1,518 @@ +# Test cases for generators and yield (compile and run) + +[case testYield] +from typing import Generator, Iterable, Union, Tuple, Dict + +def yield_three_times() -> Iterable[int]: + yield 1 + yield 2 + yield 3 + +def yield_twice_and_return() -> Generator[int, None, int]: + yield 1 + yield 2 + return 4 + +def yield_while_loop() -> Generator[int, None, int]: + i = 0 + while i < 5: + if i == 3: + return i + yield i + i += 1 + return -1 + +def yield_for_loop() -> Iterable[int]: + l = [i for i in range(3)] + for i in l: + yield i + + d = {k: None for k in range(3)} + for k in d: + yield k + + for i in range(3): + yield i + + for i in range(three()): + yield i + +def yield_with_except() -> Generator[int, None, None]: + yield 10 + try: + return + except: + print('Caught exception inside generator function') + +def complex_yield(a: int, b: str, c: float) -> Generator[Union[str, int], None, float]: + x = 2 + while x < a: + if x % 2 == 0: + dummy_var = 1 + yield str(x) + ' ' + b + dummy_var = 1 + else: + dummy_var = 1 + yield x + dummy_var = 1 + x += 1 + return c + +def yield_with_default(x: bool = False) -> Iterable[int]: + if x: + yield 0 + +def yield_dict_methods(d1: Dict[int, int], + d2: Dict[int, int], + d3: Dict[int, int]) -> Iterable[int]: + for k in d1.keys(): + yield k + for k, v in d2.items(): + yield k + yield v + for v in d3.values(): + yield v + +def three() -> int: + return 3 + +class A(object): + def __init__(self, x: int) -> None: + self.x = x + + def generator(self) -> Iterable[int]: + yield self.x + +def return_tuple() -> Generator[int, None, Tuple[int, int]]: + yield 0 + return 1, 2 + +[file driver.py] +from native import ( + yield_three_times, + yield_twice_and_return, + yield_while_loop, + yield_for_loop, + yield_with_except, + complex_yield, + yield_with_default, + A, + return_tuple, + yield_dict_methods, +) +from testutil import run_generator +from collections import defaultdict + +assert run_generator(yield_three_times()) == ((1, 2, 3), None) +assert run_generator(yield_twice_and_return()) == ((1, 2), 4) +assert run_generator(yield_while_loop()) == ((0, 1, 2), 3) +assert run_generator(yield_for_loop()) == (tuple(4 * [i for i in range(3)]), None) +assert run_generator(yield_with_except()) == ((10,), None) +assert run_generator(complex_yield(5, 'foo', 1.0)) == (('2 foo', 3, '4 foo'), 1.0) +assert run_generator(yield_with_default()) == ((), None) +assert run_generator(A(0).generator()) == ((0,), None) +assert run_generator(return_tuple()) == ((0,), (1, 2)) +assert run_generator(yield_dict_methods({}, {}, {})) == ((), None) +assert run_generator(yield_dict_methods({1: 2}, {3: 4}, {5: 6})) == ((1, 3, 4, 6), None) +dd = defaultdict(int, {0: 1}) +assert run_generator(yield_dict_methods(dd, dd, dd)) == ((0, 0, 1, 1), None) + +for i in yield_twice_and_return(): + print(i) + +for i in yield_while_loop(): + print(i) + +[out] +1 +2 +0 +1 +2 + +[case testYieldTryFinallyWith] +from typing import Generator, Any + +class Thing: + def __init__(self, x: str) -> None: + self.x = x + def __enter__(self) -> str: + print('enter!', self.x) + if self.x == 'crash': + raise Exception('ohno') + return self.x + def __exit__(self, x: Any, y: Any, z: Any) -> None: + print('exit!', self.x, y) + +def yield_try_finally() -> Generator[int, None, str]: + try: + yield 1 + yield 2 + return 'lol' + except Exception: + raise + finally: + print('goodbye!') + +def yield_with(i: int) -> Generator[int, None, int]: + with Thing('a') as x: + yield 1 + print("yooo?", x) + if i == 0: + yield 2 + return 10 + elif i == 1: + raise Exception('exception!') + return -1 + +[file driver.py] +from native import yield_try_finally, yield_with +from testutil import run_generator + +print(run_generator(yield_try_finally(), p=True)) +print(run_generator(yield_with(0), p=True)) +print(run_generator(yield_with(1), p=True)) +[out] +1 +2 +goodbye! +((1, 2), 'lol') +enter! a +1 +yooo? a +2 +exit! a None +((1, 2), 10) +enter! a +1 +yooo? a +exit! a exception! +((1,), 'exception!') + +[case testYieldNested] +from typing import Callable, Generator + +def normal(a: int, b: float) -> Callable: + def generator(x: int, y: str) -> Generator: + yield a + yield b + yield x + yield y + return generator + +def generator(a: int) -> Generator: + def normal(x: int) -> int: + return a + x + for i in range(3): + yield normal(i) + +def triple() -> Callable: + def generator() -> Generator: + x = 0 + def inner() -> int: + x += 1 + return x + while x < 3: + yield inner() + return generator + +def another_triple() -> Callable: + def generator() -> Generator: + x = 0 + def inner_generator() -> Generator: + x += 1 + yield x + yield next(inner_generator()) + return generator + +def outer() -> Generator: + def recursive(n: int) -> Generator: + if n < 10: + for i in range(n): + yield i + return + for i in recursive(5): + yield i + return recursive(10) + +[file driver.py] +from native import normal, generator, triple, another_triple, outer +from testutil import run_generator + +assert run_generator(normal(1, 2.0)(3, '4.00')) == ((1, 2.0, 3, '4.00'), None) +assert run_generator(generator(1)) == ((1, 2, 3), None) +assert run_generator(triple()()) == ((1, 2, 3), None) +assert run_generator(another_triple()()) == ((1,), None) +assert run_generator(outer()) == ((0, 1, 2, 3, 4), None) + +[case testYieldThrow] +from typing import Generator, Iterable, Any +from traceback import print_tb +from contextlib import contextmanager +import wrapsys + +def generator() -> Iterable[int]: + try: + yield 1 + yield 2 + yield 3 + except Exception as e: + print_tb(wrapsys.exc_info()[2]) + s = str(e) + if s: + print('caught exception with value ' + s) + else: + print('caught exception without value') + return 0 + +def no_except() -> Iterable[int]: + yield 1 + yield 2 + +def raise_something() -> Iterable[int]: + yield 1 + yield 2 + raise Exception('failure') + +def wrapper(x: Any) -> Any: + return (yield from x) + +def foo() -> Generator[int, None, None]: + try: + yield 1 + except Exception as e: + print(str(e)) + finally: + print('goodbye') + +ctx_manager = contextmanager(foo) + +[file wrapsys.py] +# This is a gross hack around some limitations of the test system/mypyc. +from typing import Any +import sys +def exc_info() -> Any: + return sys.exc_info() # type: ignore + +[file driver.py] +import sys +from typing import Generator, Tuple, TypeVar, Sequence +from native import generator, ctx_manager, wrapper, no_except, raise_something + +T = TypeVar('T') +U = TypeVar('U') + +def run_generator_and_throw(gen: Generator[T, None, U], + num_times: int, + value: object = None, + traceback: object = None) -> Tuple[Sequence[T], U]: + res = [] + try: + for i in range(num_times): + res.append(next(gen)) + if value is not None and traceback is not None: + gen.throw(Exception, value, traceback) + elif value is not None: + gen.throw(Exception, value) + else: + gen.throw(Exception) + except StopIteration as e: + return (tuple(res), e.value) + except Exception as e: + return (tuple(res), str(e)) + +assert run_generator_and_throw(generator(), 0, 'hello') == ((), 'hello') +assert run_generator_and_throw(generator(), 3) == ((1, 2, 3), 0) +assert run_generator_and_throw(generator(), 2, 'some string') == ((1, 2), 0) +try: + raise Exception +except Exception as e: + tb = sys.exc_info()[2] + assert run_generator_and_throw(generator(), 1, 'some other string', tb) == ((1,), 0) + +assert run_generator_and_throw(wrapper(generator()), 0, 'hello') == ((), 'hello') +assert run_generator_and_throw(wrapper(generator()), 3) == ((1, 2, 3), 0) +assert run_generator_and_throw(wrapper(generator()), 2, 'some string') == ((1, 2), 0) +# Make sure we aren't leaking exc_info +assert sys.exc_info()[0] is None + +assert run_generator_and_throw(wrapper([1, 2, 3]), 3, 'lol') == ((1, 2, 3), 'lol') +assert run_generator_and_throw(wrapper(no_except()), 2, 'lol') == ((1, 2), 'lol') + +assert run_generator_and_throw(wrapper(raise_something()), 3) == ((1, 2), 'failure') + +with ctx_manager() as c: + raise Exception('exception') + +[out] + File "native.py", line 10, in generator + yield 3 + File "native.py", line 9, in generator + yield 2 + File "native.py", line 8, in generator + yield 1 + File "driver.py", line 31, in + raise Exception + File "native.py", line 10, in generator + yield 3 + File "native.py", line 30, in wrapper + return (yield from x) + File "native.py", line 9, in generator + yield 2 + File "native.py", line 30, in wrapper + return (yield from x) +caught exception without value +caught exception with value some string +caught exception with value some other string +caught exception without value +caught exception with value some string +exception +goodbye + +[case testYieldSend] +from typing import Generator + +def basic() -> Generator[int, int, int]: + x = yield 1 + y = yield (x + 1) + return y + +def use_from() -> Generator[int, int, int]: + return (yield from basic()) + +[file driver.py] +from native import basic, use_from +from testutil import run_generator + +assert run_generator(basic(), [5, 50]) == ((1, 6), 50) +assert run_generator(use_from(), [5, 50]) == ((1, 6), 50) + +[case testYieldFrom] +from typing import Generator, Iterator, List + +def basic() -> Iterator[int]: + yield from [1, 2, 3] + +def call_next() -> int: + x = [] # type: List[int] + return next(iter(x)) + +def inner(b: bool) -> Generator[int, None, int]: + if b: + yield from [1, 2, 3] + return 10 + +def with_return(b: bool) -> Generator[int, None, int]: + x = yield from inner(b) + for a in [1, 2]: + pass + return x + +[file driver.py] +from native import basic, call_next, with_return +from testutil import run_generator, assertRaises + +assert run_generator(basic()) == ((1, 2, 3), None) + +with assertRaises(StopIteration): + call_next() + +assert run_generator(with_return(True)) == ((1, 2, 3), 10) +assert run_generator(with_return(False)) == ((), 10) + +[case testNextGenerator] +from typing import Iterable + +def f(x: int) -> int: + print(x) + return x + +def call_next_loud(l: Iterable[int], val: int) -> int: + return next(i for i in l if f(i) == val) + +def call_next_default(l: Iterable[int], val: int) -> int: + return next((i*2 for i in l if i == val), -1) + +def call_next_default_list(l: Iterable[int], val: int) -> int: + return next((i*2 for i in l if i == val), -1) +[file driver.py] +from native import call_next_loud, call_next_default, call_next_default_list +from testutil import assertRaises + +assert call_next_default([0, 1, 2], 0) == 0 +assert call_next_default([0, 1, 2], 1) == 2 +assert call_next_default([0, 1, 2], 2) == 4 +assert call_next_default([0, 1, 2], 3) == -1 +assert call_next_default([], 0) == -1 +assert call_next_default_list([0, 1, 2], 0) == 0 +assert call_next_default_list([0, 1, 2], 1) == 2 +assert call_next_default_list([0, 1, 2], 2) == 4 +assert call_next_default_list([0, 1, 2], 3) == -1 +assert call_next_default_list([], 0) == -1 + +assert call_next_loud([0, 1, 2], 0) == 0 +assert call_next_loud([0, 1, 2], 1) == 1 +assert call_next_loud([0, 1, 2], 2) == 2 +with assertRaises(StopIteration): + call_next_loud([42], 3) +with assertRaises(StopIteration): + call_next_loud([], 3) + +[out] +0 +0 +1 +0 +1 +2 +42 + +[case testGeneratorSuper] +from typing import Iterator, Callable, Any + +class A(): + def testA(self) -> int: + return 2 + +class B(A): + def testB(self) -> Iterator[int]: + x = super().testA() + while True: + yield x + +def testAsserts(): + b = B() + b_gen = b.testB() + assert next(b_gen) == 2 + +[file driver.py] +from native import testAsserts + +testAsserts() + +[case testNameClashIssues] +class A: + def foo(self) -> object: + yield +class B: + def foo(self) -> object: + yield + +class C: + def foo(self) -> None: + def bar(self) -> None: + pass + +def C___foo() -> None: pass + +class D: + def foo(self) -> None: + def bar(self) -> None: + pass + +class E: + default: int + switch: int + +[file driver.py] +# really I only care it builds diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index 9a3f0bdd4e49..8b1ad0d92246 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -2990,426 +2990,6 @@ except TypeError: else: assert False -[case testYield] -from typing import Generator, Iterable, Union, Tuple, Dict - -def yield_three_times() -> Iterable[int]: - yield 1 - yield 2 - yield 3 - -def yield_twice_and_return() -> Generator[int, None, int]: - yield 1 - yield 2 - return 4 - -def yield_while_loop() -> Generator[int, None, int]: - i = 0 - while i < 5: - if i == 3: - return i - yield i - i += 1 - return -1 - -def yield_for_loop() -> Iterable[int]: - l = [i for i in range(3)] - for i in l: - yield i - - d = {k: None for k in range(3)} - for k in d: - yield k - - for i in range(3): - yield i - - for i in range(three()): - yield i - -def yield_with_except() -> Generator[int, None, None]: - yield 10 - try: - return - except: - print('Caught exception inside generator function') - -def complex_yield(a: int, b: str, c: float) -> Generator[Union[str, int], None, float]: - x = 2 - while x < a: - if x % 2 == 0: - dummy_var = 1 - yield str(x) + ' ' + b - dummy_var = 1 - else: - dummy_var = 1 - yield x - dummy_var = 1 - x += 1 - return c - -def yield_with_default(x: bool = False) -> Iterable[int]: - if x: - yield 0 - -def yield_dict_methods(d1: Dict[int, int], - d2: Dict[int, int], - d3: Dict[int, int]) -> Iterable[int]: - for k in d1.keys(): - yield k - for k, v in d2.items(): - yield k - yield v - for v in d3.values(): - yield v - -def three() -> int: - return 3 - -class A(object): - def __init__(self, x: int) -> None: - self.x = x - - def generator(self) -> Iterable[int]: - yield self.x - -def return_tuple() -> Generator[int, None, Tuple[int, int]]: - yield 0 - return 1, 2 - -[file driver.py] -from native import ( - yield_three_times, - yield_twice_and_return, - yield_while_loop, - yield_for_loop, - yield_with_except, - complex_yield, - yield_with_default, - A, - return_tuple, - yield_dict_methods, -) -from testutil import run_generator -from collections import defaultdict - -assert run_generator(yield_three_times()) == ((1, 2, 3), None) -assert run_generator(yield_twice_and_return()) == ((1, 2), 4) -assert run_generator(yield_while_loop()) == ((0, 1, 2), 3) -assert run_generator(yield_for_loop()) == (tuple(4 * [i for i in range(3)]), None) -assert run_generator(yield_with_except()) == ((10,), None) -assert run_generator(complex_yield(5, 'foo', 1.0)) == (('2 foo', 3, '4 foo'), 1.0) -assert run_generator(yield_with_default()) == ((), None) -assert run_generator(A(0).generator()) == ((0,), None) -assert run_generator(return_tuple()) == ((0,), (1, 2)) -assert run_generator(yield_dict_methods({}, {}, {})) == ((), None) -assert run_generator(yield_dict_methods({1: 2}, {3: 4}, {5: 6})) == ((1, 3, 4, 6), None) -dd = defaultdict(int, {0: 1}) -assert run_generator(yield_dict_methods(dd, dd, dd)) == ((0, 0, 1, 1), None) - -for i in yield_twice_and_return(): - print(i) - -for i in yield_while_loop(): - print(i) - -[out] -1 -2 -0 -1 -2 - -[case testYieldTryFinallyWith] -from typing import Generator, Any - -class Thing: - def __init__(self, x: str) -> None: - self.x = x - def __enter__(self) -> str: - print('enter!', self.x) - if self.x == 'crash': - raise Exception('ohno') - return self.x - def __exit__(self, x: Any, y: Any, z: Any) -> None: - print('exit!', self.x, y) - -def yield_try_finally() -> Generator[int, None, str]: - try: - yield 1 - yield 2 - return 'lol' - except Exception: - raise - finally: - print('goodbye!') - -def yield_with(i: int) -> Generator[int, None, int]: - with Thing('a') as x: - yield 1 - print("yooo?", x) - if i == 0: - yield 2 - return 10 - elif i == 1: - raise Exception('exception!') - return -1 - -[file driver.py] -from native import yield_try_finally, yield_with -from testutil import run_generator - -print(run_generator(yield_try_finally(), p=True)) -print(run_generator(yield_with(0), p=True)) -print(run_generator(yield_with(1), p=True)) -[out] -1 -2 -goodbye! -((1, 2), 'lol') -enter! a -1 -yooo? a -2 -exit! a None -((1, 2), 10) -enter! a -1 -yooo? a -exit! a exception! -((1,), 'exception!') - -[case testYieldNested] -from typing import Callable, Generator - -def normal(a: int, b: float) -> Callable: - def generator(x: int, y: str) -> Generator: - yield a - yield b - yield x - yield y - return generator - -def generator(a: int) -> Generator: - def normal(x: int) -> int: - return a + x - for i in range(3): - yield normal(i) - -def triple() -> Callable: - def generator() -> Generator: - x = 0 - def inner() -> int: - x += 1 - return x - while x < 3: - yield inner() - return generator - -def another_triple() -> Callable: - def generator() -> Generator: - x = 0 - def inner_generator() -> Generator: - x += 1 - yield x - yield next(inner_generator()) - return generator - -def outer() -> Generator: - def recursive(n: int) -> Generator: - if n < 10: - for i in range(n): - yield i - return - for i in recursive(5): - yield i - return recursive(10) - -[file driver.py] -from native import normal, generator, triple, another_triple, outer -from testutil import run_generator - -assert run_generator(normal(1, 2.0)(3, '4.00')) == ((1, 2.0, 3, '4.00'), None) -assert run_generator(generator(1)) == ((1, 2, 3), None) -assert run_generator(triple()()) == ((1, 2, 3), None) -assert run_generator(another_triple()()) == ((1,), None) -assert run_generator(outer()) == ((0, 1, 2, 3, 4), None) - -[case testYieldThrow] -from typing import Generator, Iterable, Any -from traceback import print_tb -from contextlib import contextmanager -import wrapsys - -def generator() -> Iterable[int]: - try: - yield 1 - yield 2 - yield 3 - except Exception as e: - print_tb(wrapsys.exc_info()[2]) - s = str(e) - if s: - print('caught exception with value ' + s) - else: - print('caught exception without value') - return 0 - -def no_except() -> Iterable[int]: - yield 1 - yield 2 - -def raise_something() -> Iterable[int]: - yield 1 - yield 2 - raise Exception('failure') - -def wrapper(x: Any) -> Any: - return (yield from x) - -def foo() -> Generator[int, None, None]: - try: - yield 1 - except Exception as e: - print(str(e)) - finally: - print('goodbye') - -ctx_manager = contextmanager(foo) - -[file wrapsys.py] -# This is a gross hack around some limitations of the test system/mypyc. -from typing import Any -import sys -def exc_info() -> Any: - return sys.exc_info() # type: ignore - -[file driver.py] -import sys -from typing import Generator, Tuple, TypeVar, Sequence -from native import generator, ctx_manager, wrapper, no_except, raise_something - -T = TypeVar('T') -U = TypeVar('U') - -def run_generator_and_throw(gen: Generator[T, None, U], - num_times: int, - value: object = None, - traceback: object = None) -> Tuple[Sequence[T], U]: - res = [] - try: - for i in range(num_times): - res.append(next(gen)) - if value is not None and traceback is not None: - gen.throw(Exception, value, traceback) - elif value is not None: - gen.throw(Exception, value) - else: - gen.throw(Exception) - except StopIteration as e: - return (tuple(res), e.value) - except Exception as e: - return (tuple(res), str(e)) - -assert run_generator_and_throw(generator(), 0, 'hello') == ((), 'hello') -assert run_generator_and_throw(generator(), 3) == ((1, 2, 3), 0) -assert run_generator_and_throw(generator(), 2, 'some string') == ((1, 2), 0) -try: - raise Exception -except Exception as e: - tb = sys.exc_info()[2] - assert run_generator_and_throw(generator(), 1, 'some other string', tb) == ((1,), 0) - -assert run_generator_and_throw(wrapper(generator()), 0, 'hello') == ((), 'hello') -assert run_generator_and_throw(wrapper(generator()), 3) == ((1, 2, 3), 0) -assert run_generator_and_throw(wrapper(generator()), 2, 'some string') == ((1, 2), 0) -# Make sure we aren't leaking exc_info -assert sys.exc_info()[0] is None - -assert run_generator_and_throw(wrapper([1, 2, 3]), 3, 'lol') == ((1, 2, 3), 'lol') -assert run_generator_and_throw(wrapper(no_except()), 2, 'lol') == ((1, 2), 'lol') - -assert run_generator_and_throw(wrapper(raise_something()), 3) == ((1, 2), 'failure') - -with ctx_manager() as c: - raise Exception('exception') - -[out] - File "native.py", line 10, in generator - yield 3 - File "native.py", line 9, in generator - yield 2 - File "native.py", line 8, in generator - yield 1 - File "driver.py", line 31, in - raise Exception - File "native.py", line 10, in generator - yield 3 - File "native.py", line 30, in wrapper - return (yield from x) - File "native.py", line 9, in generator - yield 2 - File "native.py", line 30, in wrapper - return (yield from x) -caught exception without value -caught exception with value some string -caught exception with value some other string -caught exception without value -caught exception with value some string -exception -goodbye - -[case testYieldSend] -from typing import Generator - -def basic() -> Generator[int, int, int]: - x = yield 1 - y = yield (x + 1) - return y - -def use_from() -> Generator[int, int, int]: - return (yield from basic()) - -[file driver.py] -from native import basic, use_from -from testutil import run_generator - -assert run_generator(basic(), [5, 50]) == ((1, 6), 50) -assert run_generator(use_from(), [5, 50]) == ((1, 6), 50) - -[case testYieldFrom] -from typing import Generator, Iterator, List - -def basic() -> Iterator[int]: - yield from [1, 2, 3] - -def call_next() -> int: - x = [] # type: List[int] - return next(iter(x)) - -def inner(b: bool) -> Generator[int, None, int]: - if b: - yield from [1, 2, 3] - return 10 - -def with_return(b: bool) -> Generator[int, None, int]: - x = yield from inner(b) - for a in [1, 2]: - pass - return x - -[file driver.py] -from native import basic, call_next, with_return -from testutil import run_generator, assertRaises - -assert run_generator(basic()) == ((1, 2, 3), None) - -with assertRaises(StopIteration): - call_next() - -assert run_generator(with_return(True)) == ((1, 2, 3), 10) -assert run_generator(with_return(False)) == ((), 10) - [case testDecorators1] from typing import Generator, Callable, Iterator from contextlib import contextmanager @@ -3644,76 +3224,6 @@ assert call_all(mixed_110) == 1 assert call_any_nested([[1, 1, 1], [1, 1], []]) == 1 assert call_any_nested([[1, 1, 1], [0, 1], []]) == 0 -[case testNextGenerator] -from typing import Iterable - -def f(x: int) -> int: - print(x) - return x - -def call_next_loud(l: Iterable[int], val: int) -> int: - return next(i for i in l if f(i) == val) - -def call_next_default(l: Iterable[int], val: int) -> int: - return next((i*2 for i in l if i == val), -1) - -def call_next_default_list(l: Iterable[int], val: int) -> int: - return next((i*2 for i in l if i == val), -1) -[file driver.py] -from native import call_next_loud, call_next_default, call_next_default_list -from testutil import assertRaises - -assert call_next_default([0, 1, 2], 0) == 0 -assert call_next_default([0, 1, 2], 1) == 2 -assert call_next_default([0, 1, 2], 2) == 4 -assert call_next_default([0, 1, 2], 3) == -1 -assert call_next_default([], 0) == -1 -assert call_next_default_list([0, 1, 2], 0) == 0 -assert call_next_default_list([0, 1, 2], 1) == 2 -assert call_next_default_list([0, 1, 2], 2) == 4 -assert call_next_default_list([0, 1, 2], 3) == -1 -assert call_next_default_list([], 0) == -1 - -assert call_next_loud([0, 1, 2], 0) == 0 -assert call_next_loud([0, 1, 2], 1) == 1 -assert call_next_loud([0, 1, 2], 2) == 2 -with assertRaises(StopIteration): - call_next_loud([42], 3) -with assertRaises(StopIteration): - call_next_loud([], 3) - -[out] -0 -0 -1 -0 -1 -2 -42 - -[case testGeneratorSuper] -from typing import Iterator, Callable, Any - -class A(): - def testA(self) -> int: - return 2 - -class B(A): - def testB(self) -> Iterator[int]: - x = super().testA() - while True: - yield x - -def testAsserts(): - b = B() - b_gen = b.testB() - assert next(b_gen) == 2 - -[file driver.py] -from native import testAsserts - -testAsserts() - [case testAssignModule] import a assert a.x == 20 @@ -3880,33 +3390,6 @@ try: except RuntimeError: assert version == (3, 5), "only 3.5 should fail!" -[case testNameClashIssues] -class A: - def foo(self) -> object: - yield -class B: - def foo(self) -> object: - yield - -class C: - def foo(self) -> None: - def bar(self) -> None: - pass - -def C___foo() -> None: pass - -class D: - def foo(self) -> None: - def bar(self) -> None: - pass - -class E: - default: int - switch: int - -[file driver.py] -# really I only care it builds - [case testIterTypeTrickiness] # Test inferring the type of a for loop body doesn't cause us grief # Extracted from somethings that broke in mypy diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index 86ac379984e1..db0b89a5e5bc 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -30,8 +30,8 @@ from mypyc.test.test_serialization import check_serialization_roundtrip files = [ - 'run-functions.test', 'run.test', + 'run-functions.test', 'run-integers.test', 'run-strings.test', 'run-tuples.test', @@ -39,6 +39,7 @@ 'run-dicts.test', 'run-classes.test', 'run-traits.test', + 'run-generators.test', 'run-multimodule.test', 'run-bench.test', 'run-mypy-sim.test', From 2fecbcbbcb438721f86d0e3fcabc84dde341fe6a Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 20:17:41 +0100 Subject: [PATCH 05/14] Move loop run tests to a new file --- mypyc/test-data/run-loops.test | 454 +++++++++++++++++++++++++++++++++ mypyc/test-data/run.test | 453 -------------------------------- mypyc/test/test_run.py | 1 + 3 files changed, 455 insertions(+), 453 deletions(-) create mode 100644 mypyc/test-data/run-loops.test diff --git a/mypyc/test-data/run-loops.test b/mypyc/test-data/run-loops.test new file mode 100644 index 000000000000..933d4a3f8311 --- /dev/null +++ b/mypyc/test-data/run-loops.test @@ -0,0 +1,454 @@ +# Test cases for for and while loops (compile and run) + +[case testFor] +from typing import List, Tuple +def count(n: int) -> None: + for i in range(n): + print(i) +def count_between(n: int, k: int) -> None: + for i in range(n, k): + print(i) + print('n=', n) +def count_down(n: int, k: int) -> None: + for i in range(n, k, -1): + print(i) +def count_double(n: int, k: int) -> None: + for i in range(n, k, 2): + print(i) +def list_iter(l: List[int]) -> None: + for i in l: + print(i) +def tuple_iter(l: Tuple[int, ...]) -> None: + for i in l: + print(i) +def str_iter(l: str) -> None: + for i in l: + print(i) +def list_rev_iter(l: List[int]) -> None: + for i in reversed(l): + print(i) +def list_rev_iter_lol(l: List[int]) -> None: + for i in reversed(l): + print(i) + if i == 3: + while l: + l.pop() +def count_down_short() -> None: + for i in range(10, 0, -1): + print(i) +[file driver.py] +from native import ( + count, list_iter, list_rev_iter, list_rev_iter_lol, count_between, count_down, count_double, + count_down_short, tuple_iter, str_iter, +) +count(5) +list_iter(list(reversed(range(5)))) +list_rev_iter(list(reversed(range(5)))) +count_between(11, 15) +count_between(10**20, 10**20+3) +count_down(20, 10) +count_double(10, 15) +count_down_short() +print('==') +list_rev_iter_lol(list(reversed(range(5)))) +tuple_iter((1, 2, 3)) +str_iter("abc") +[out] +0 +1 +2 +3 +4 +4 +3 +2 +1 +0 +0 +1 +2 +3 +4 +11 +12 +13 +14 +n= 11 +100000000000000000000 +100000000000000000001 +100000000000000000002 +n= 100000000000000000000 +20 +19 +18 +17 +16 +15 +14 +13 +12 +11 +10 +12 +14 +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +== +0 +1 +2 +3 +1 +2 +3 +a +b +c + +[case testLoopElse] +from typing import Iterator +def run_for_range(n: int) -> None: + for i in range(n): + if i == 3: + break + print(i) + else: + print(n+1) + +def run_for_list(n: int) -> None: + for i in list(range(n)): + if i == 3: + break + print(i) + else: + print(n+1) + +def run_for_iter(n: int) -> None: + def identity(x: Iterator[int]) -> Iterator[int]: + return x + for i in identity(range(n)): + if i == 3: + break + print(i) + else: + print(n+1) + +def count(n: int) -> int: + i = 1 + while i <= n: + i = i + 1 + if i == 5: + break + else: + i *= -1 + return i + +def nested_while() -> int: + while True: + while False: + pass + else: + break + else: + return -1 + return 0 + +def nested_for() -> int: + for x in range(1000): + for y in [1,2,3]: + pass + else: + break + else: + return -1 + return 0 + +[file driver.py] +from native import run_for_range, run_for_list, run_for_iter, count, nested_while, nested_for +assert nested_while() == 0 +assert nested_for() == 0 +assert count(0) == -1 +assert count(1) == -2 +assert count(5) == 5 +assert count(6) == 5 +run_for_range(3) +run_for_range(5) +print('==') +run_for_list(3) +run_for_list(5) +print('==') +run_for_iter(3) +run_for_iter(5) +[out] +0 +1 +2 +4 +0 +1 +2 +== +0 +1 +2 +4 +0 +1 +2 +== +0 +1 +2 +4 +0 +1 +2 + +[case testNestedLoopSameIdx] +from typing import List, Generator + +def nested_enumerate() -> None: + l1 = [0,1,2] + l2 = [0,1,2] + outer_seen = [] + outer = 0 + for i, j in enumerate(l1): + assert i == outer + outer_seen.append(i) + inner = 0 + for i, k in enumerate(l2): + assert i == inner + inner += 1 + outer += 1 + assert outer_seen == l1 + +def nested_range() -> None: + outer = 0 + outer_seen = [] + for i in range(3): + assert i == outer + outer_seen.append(i) + inner = 0 + for i in range(3): + assert i == inner + inner += 1 + outer += 1 + assert outer_seen == [0,1,2] + +def nested_list() -> None: + l1 = [0,1,2] + l2 = [0,1,2] + outer_seen = [] + outer = 0 + for i in l1: + assert i == outer + outer_seen.append(i) + inner = 0 + for i in l2: + assert i == inner + inner += 1 + outer += 1 + assert outer_seen == l1 + +def nested_yield() -> Generator: + for i in range(3): + for i in range(3): + yield i + yield i + + +[file driver.py] +from native import nested_enumerate, nested_range, nested_list, nested_yield +nested_enumerate() +nested_range() +nested_list() +gen = nested_yield() +for k in range(12): + assert next(gen) == k % 4 +[out] + +[case testForIterable] +from typing import Iterable, Dict, Any, Tuple +def iterate_over_any(a: Any) -> None: + for element in a: + print(element) + +def iterate_over_iterable(iterable: Iterable[T]) -> None: + for element in iterable: + print(element) + +def iterate_and_delete(d: Dict[int, int]) -> None: + for key in d: + d.pop(key) + +def sum_over_values(d: Dict[int, int]) -> int: + s = 0 + for key in d: + s = s + d[key] + return s + +def sum_over_even_values(d: Dict[int, int]) -> int: + s = 0 + for key in d: + if d[key] % 2: + continue + s = s + d[key] + return s + +def sum_over_two_values(d: Dict[int, int]) -> int: + s = 0 + i = 0 + for key in d: + if i == 2: + break + s = s + d[key] + i = i + 1 + return s + +def iterate_over_tuple(iterable: Tuple[int, int, int]) -> None: + for element in iterable: + print(element) + +[file driver.py] +from native import iterate_over_any, iterate_over_iterable, iterate_and_delete, sum_over_values, sum_over_even_values, sum_over_two_values, iterate_over_tuple +import traceback +def broken_generator(n): + num = 0 + while num < n: + yield num + num += 1 + raise Exception('Exception Manually Raised') + +d = {1:1, 2:2, 3:3, 4:4, 5:5} +print(sum_over_values(d)) +print(sum_over_even_values(d)) +print(sum_over_two_values(d)) + +try: + iterate_over_any(5) +except TypeError: + traceback.print_exc() +try: + iterate_over_iterable(broken_generator(5)) +except Exception: + traceback.print_exc() +try: + iterate_and_delete(d) +except RuntimeError: + traceback.print_exc() + +iterate_over_tuple((1, 2, 3)) +[out] +Traceback (most recent call last): + File "driver.py", line 16, in + iterate_over_any(5) + File "native.py", line 3, in iterate_over_any + for element in a: +TypeError: 'int' object is not iterable +Traceback (most recent call last): + File "driver.py", line 20, in + iterate_over_iterable(broken_generator(5)) + File "native.py", line 7, in iterate_over_iterable + for element in iterable: + File "driver.py", line 8, in broken_generator + raise Exception('Exception Manually Raised') +Exception: Exception Manually Raised +Traceback (most recent call last): + File "driver.py", line 24, in + iterate_and_delete(d) + File "native.py", line 11, in iterate_and_delete + for key in d: +RuntimeError: dictionary changed size during iteration +15 +6 +3 +0 +1 +2 +3 +4 +1 +2 +3 + +[case testContinueFor] +def f() -> None: + for n in range(5): + continue +[file driver.py] +from native import f +f() + +[case testMultipleVarsWithLoops] +# Test comprehensions and for loops with multiple index variables +l = [(1, 2, 'a'), (3, 4, 'b'), (5, 6, 'c')] +l2 = [str(a*100+b)+' '+c for a, b, c in l] +l3 = [] +for a, b, c in l: + l3.append(str(a*1000+b)+' '+c) +[file driver.py] +from native import l, l2, l3 +for a in l2 + l3: + print(a) +[out] +102 a +304 b +506 c +1002 a +3004 b +5006 c + +[case testForZipAndEnumerate] +from typing import Iterable, List, Any +def f(a: Iterable[int], b: List[int]) -> List[Any]: + res = [] + for (x, y), z in zip(enumerate(a), b): + res.append((x, y, z)) + return res +def g(a: Iterable[int], b: Iterable[str]) -> List[Any]: + res = [] + for x, (y, z) in enumerate(zip(a, b)): + res.append((x, y, z)) + return res + +[file driver.py] +from native import f, g + +assert f([6, 7], [8, 9]) == [(0, 6, 8), (1, 7, 9)] +assert g([6, 7], ['a', 'b']) == [(0, 6, 'a'), (1, 7, 'b')] +assert f([6, 7], [8]) == [(0, 6, 8)] +assert f([6], [8, 9]) == [(0, 6, 8)] + +[case testIterTypeTrickiness] +# Test inferring the type of a for loop body doesn't cause us grief +# Extracted from somethings that broke in mypy + +from typing import Optional + +# really I only care that this one build +def foo(x: object) -> None: + if isinstance(x, dict): + for a in x: + pass + +def bar(x: Optional[str]) -> None: + vars = ( + ("a", 'lol'), + ("b", 'asdf'), + ("lol", x), + ("an int", 10), + ) + for name, value in vars: + pass + +[file driver.py] +from native import bar +bar(None) diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index 8b1ad0d92246..1afcf2fdfe7f 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -15,281 +15,6 @@ print(f(-10**20)) 100000000000000000000 -100000000000000000000 -[case testFor] -from typing import List, Tuple -def count(n: int) -> None: - for i in range(n): - print(i) -def count_between(n: int, k: int) -> None: - for i in range(n, k): - print(i) - print('n=', n) -def count_down(n: int, k: int) -> None: - for i in range(n, k, -1): - print(i) -def count_double(n: int, k: int) -> None: - for i in range(n, k, 2): - print(i) -def list_iter(l: List[int]) -> None: - for i in l: - print(i) -def tuple_iter(l: Tuple[int, ...]) -> None: - for i in l: - print(i) -def str_iter(l: str) -> None: - for i in l: - print(i) -def list_rev_iter(l: List[int]) -> None: - for i in reversed(l): - print(i) -def list_rev_iter_lol(l: List[int]) -> None: - for i in reversed(l): - print(i) - if i == 3: - while l: - l.pop() -def count_down_short() -> None: - for i in range(10, 0, -1): - print(i) -[file driver.py] -from native import ( - count, list_iter, list_rev_iter, list_rev_iter_lol, count_between, count_down, count_double, - count_down_short, tuple_iter, str_iter, -) -count(5) -list_iter(list(reversed(range(5)))) -list_rev_iter(list(reversed(range(5)))) -count_between(11, 15) -count_between(10**20, 10**20+3) -count_down(20, 10) -count_double(10, 15) -count_down_short() -print('==') -list_rev_iter_lol(list(reversed(range(5)))) -tuple_iter((1, 2, 3)) -str_iter("abc") -[out] -0 -1 -2 -3 -4 -4 -3 -2 -1 -0 -0 -1 -2 -3 -4 -11 -12 -13 -14 -n= 11 -100000000000000000000 -100000000000000000001 -100000000000000000002 -n= 100000000000000000000 -20 -19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -12 -14 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 -== -0 -1 -2 -3 -1 -2 -3 -a -b -c - -[case testLoopElse] -from typing import Iterator -def run_for_range(n: int) -> None: - for i in range(n): - if i == 3: - break - print(i) - else: - print(n+1) - -def run_for_list(n: int) -> None: - for i in list(range(n)): - if i == 3: - break - print(i) - else: - print(n+1) - -def run_for_iter(n: int) -> None: - def identity(x: Iterator[int]) -> Iterator[int]: - return x - for i in identity(range(n)): - if i == 3: - break - print(i) - else: - print(n+1) - -def count(n: int) -> int: - i = 1 - while i <= n: - i = i + 1 - if i == 5: - break - else: - i *= -1 - return i - -def nested_while() -> int: - while True: - while False: - pass - else: - break - else: - return -1 - return 0 - -def nested_for() -> int: - for x in range(1000): - for y in [1,2,3]: - pass - else: - break - else: - return -1 - return 0 - -[file driver.py] -from native import run_for_range, run_for_list, run_for_iter, count, nested_while, nested_for -assert nested_while() == 0 -assert nested_for() == 0 -assert count(0) == -1 -assert count(1) == -2 -assert count(5) == 5 -assert count(6) == 5 -run_for_range(3) -run_for_range(5) -print('==') -run_for_list(3) -run_for_list(5) -print('==') -run_for_iter(3) -run_for_iter(5) -[out] -0 -1 -2 -4 -0 -1 -2 -== -0 -1 -2 -4 -0 -1 -2 -== -0 -1 -2 -4 -0 -1 -2 - -[case testNestedLoopSameIdx] -from typing import List, Generator - -def nested_enumerate() -> None: - l1 = [0,1,2] - l2 = [0,1,2] - outer_seen = [] - outer = 0 - for i, j in enumerate(l1): - assert i == outer - outer_seen.append(i) - inner = 0 - for i, k in enumerate(l2): - assert i == inner - inner += 1 - outer += 1 - assert outer_seen == l1 - -def nested_range() -> None: - outer = 0 - outer_seen = [] - for i in range(3): - assert i == outer - outer_seen.append(i) - inner = 0 - for i in range(3): - assert i == inner - inner += 1 - outer += 1 - assert outer_seen == [0,1,2] - -def nested_list() -> None: - l1 = [0,1,2] - l2 = [0,1,2] - outer_seen = [] - outer = 0 - for i in l1: - assert i == outer - outer_seen.append(i) - inner = 0 - for i in l2: - assert i == inner - inner += 1 - outer += 1 - assert outer_seen == l1 - -def nested_yield() -> Generator: - for i in range(3): - for i in range(3): - yield i - yield i - - -[file driver.py] -from native import nested_enumerate, nested_range, nested_list, nested_yield -nested_enumerate() -nested_range() -nested_list() -gen = nested_yield() -for k in range(12): - assert next(gen) == k % 4 -[out] - [case testAsync] import asyncio @@ -1530,118 +1255,6 @@ assert not eq(b'123', b'1234') assert neq(b'123', b'1234') assert join() == b'1\x07"\x07\xf0' -[case testForIterable] -from typing import Iterable, Dict, Any, Tuple -def iterate_over_any(a: Any) -> None: - for element in a: - print(element) - -def iterate_over_iterable(iterable: Iterable[T]) -> None: - for element in iterable: - print(element) - -def iterate_and_delete(d: Dict[int, int]) -> None: - for key in d: - d.pop(key) - -def sum_over_values(d: Dict[int, int]) -> int: - s = 0 - for key in d: - s = s + d[key] - return s - -def sum_over_even_values(d: Dict[int, int]) -> int: - s = 0 - for key in d: - if d[key] % 2: - continue - s = s + d[key] - return s - -def sum_over_two_values(d: Dict[int, int]) -> int: - s = 0 - i = 0 - for key in d: - if i == 2: - break - s = s + d[key] - i = i + 1 - return s - -def iterate_over_tuple(iterable: Tuple[int, int, int]) -> None: - for element in iterable: - print(element) - -[file driver.py] -from native import iterate_over_any, iterate_over_iterable, iterate_and_delete, sum_over_values, sum_over_even_values, sum_over_two_values, iterate_over_tuple -import traceback -def broken_generator(n): - num = 0 - while num < n: - yield num - num += 1 - raise Exception('Exception Manually Raised') - -d = {1:1, 2:2, 3:3, 4:4, 5:5} -print(sum_over_values(d)) -print(sum_over_even_values(d)) -print(sum_over_two_values(d)) - -try: - iterate_over_any(5) -except TypeError: - traceback.print_exc() -try: - iterate_over_iterable(broken_generator(5)) -except Exception: - traceback.print_exc() -try: - iterate_and_delete(d) -except RuntimeError: - traceback.print_exc() - -iterate_over_tuple((1, 2, 3)) -[out] -Traceback (most recent call last): - File "driver.py", line 16, in - iterate_over_any(5) - File "native.py", line 3, in iterate_over_any - for element in a: -TypeError: 'int' object is not iterable -Traceback (most recent call last): - File "driver.py", line 20, in - iterate_over_iterable(broken_generator(5)) - File "native.py", line 7, in iterate_over_iterable - for element in iterable: - File "driver.py", line 8, in broken_generator - raise Exception('Exception Manually Raised') -Exception: Exception Manually Raised -Traceback (most recent call last): - File "driver.py", line 24, in - iterate_and_delete(d) - File "native.py", line 11, in iterate_and_delete - for key in d: -RuntimeError: dictionary changed size during iteration -15 -6 -3 -0 -1 -2 -3 -4 -1 -2 -3 - -[case testContinueFor] -def f() -> None: - for n in range(5): - continue -[file driver.py] -from native import f -f() - [case testDisplays] from typing import List, Set, Tuple, Sequence, Dict, Any @@ -2346,25 +1959,6 @@ for a in sorted(s): 9 7 63 9 8 72 -[case testMultipleVarsWithLoops] -# Test comprehensions and for loops with multiple index variables -l = [(1, 2, 'a'), (3, 4, 'b'), (5, 6, 'c')] -l2 = [str(a*100+b)+' '+c for a, b, c in l] -l3 = [] -for a, b, c in l: - l3.append(str(a*1000+b)+' '+c) -[file driver.py] -from native import l, l2, l3 -for a in l2 + l3: - print(a) -[out] -102 a -304 b -506 c -1002 a -3004 b -5006 c - [case testDel] from typing import List from testutil import assertRaises @@ -3277,27 +2871,6 @@ def test(): test() -[case testForZipAndEnumerate] -from typing import Iterable, List, Any -def f(a: Iterable[int], b: List[int]) -> List[Any]: - res = [] - for (x, y), z in zip(enumerate(a), b): - res.append((x, y, z)) - return res -def g(a: Iterable[int], b: Iterable[str]) -> List[Any]: - res = [] - for x, (y, z) in enumerate(zip(a, b)): - res.append((x, y, z)) - return res - -[file driver.py] -from native import f, g - -assert f([6, 7], [8, 9]) == [(0, 6, 8), (1, 7, 9)] -assert g([6, 7], ['a', 'b']) == [(0, 6, 'a'), (1, 7, 'b')] -assert f([6, 7], [8]) == [(0, 6, 8)] -assert f([6], [8, 9]) == [(0, 6, 8)] - [case testFinalStaticRunFail] if False: from typing import Final @@ -3390,32 +2963,6 @@ try: except RuntimeError: assert version == (3, 5), "only 3.5 should fail!" -[case testIterTypeTrickiness] -# Test inferring the type of a for loop body doesn't cause us grief -# Extracted from somethings that broke in mypy - -from typing import Optional - -# really I only care that this one build -def foo(x: object) -> None: - if isinstance(x, dict): - for a in x: - pass - -def bar(x: Optional[str]) -> None: - vars = ( - ("a", 'lol'), - ("b", 'asdf'), - ("lol", x), - ("an int", 10), - ) - for name, value in vars: - pass - -[file driver.py] -from native import bar -bar(None) - [case testComplicatedArgs] from typing import Tuple, Dict diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index db0b89a5e5bc..9fff2c694212 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -37,6 +37,7 @@ 'run-tuples.test', 'run-lists.test', 'run-dicts.test', + 'run-loops.test', 'run-classes.test', 'run-traits.test', 'run-generators.test', From c5435f4b2b14bfe9d68c26a5fd5e63f39fe4a8d1 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 20:20:28 +0100 Subject: [PATCH 06/14] Move exception run tests to a new file --- mypyc/test-data/run-exceptions.test | 448 ++++++++++++++++++++++++++++ mypyc/test-data/run.test | 447 --------------------------- mypyc/test/test_run.py | 1 + 3 files changed, 449 insertions(+), 447 deletions(-) create mode 100644 mypyc/test-data/run-exceptions.test diff --git a/mypyc/test-data/run-exceptions.test b/mypyc/test-data/run-exceptions.test new file mode 100644 index 000000000000..c591fc1d8c15 --- /dev/null +++ b/mypyc/test-data/run-exceptions.test @@ -0,0 +1,448 @@ +# Test cases for exceptions (compile and run) + +[case testException] +from typing import List +def f(x: List[int]) -> None: + g(x) + +def g(x: List[int]) -> bool: + x[5] = 2 + return True + +def r1() -> None: + q1() + +def q1() -> None: + raise Exception("test") + +def r2() -> None: + q2() + +def q2() -> None: + raise Exception + +class A: + def __init__(self) -> None: + raise Exception + +def hey() -> None: + A() + +[file driver.py] +from native import f, r1, r2, hey +import traceback +try: + f([]) +except IndexError: + traceback.print_exc() +try: + r1() +except Exception: + traceback.print_exc() +try: + r2() +except Exception: + traceback.print_exc() +try: + hey() +except Exception: + traceback.print_exc() +[out] +Traceback (most recent call last): + File "driver.py", line 4, in + f([]) + File "native.py", line 3, in f + g(x) + File "native.py", line 6, in g + x[5] = 2 +IndexError: list assignment index out of range +Traceback (most recent call last): + File "driver.py", line 8, in + r1() + File "native.py", line 10, in r1 + q1() + File "native.py", line 13, in q1 + raise Exception("test") +Exception: test +Traceback (most recent call last): + File "driver.py", line 12, in + r2() + File "native.py", line 16, in r2 + q2() + File "native.py", line 19, in q2 + raise Exception +Exception +Traceback (most recent call last): + File "driver.py", line 16, in + hey() + File "native.py", line 26, in hey + A() + File "native.py", line 23, in __init__ + raise Exception +Exception + +[case testTryExcept] +from typing import Any, Iterator +import wrapsys +def g(b: bool) -> None: + try: + if b: + x = [0] + x[1] + else: + raise Exception('hi') + except: + print("caught!") + +def r(x: int) -> None: + if x == 0: + [0][1] + elif x == 1: + raise Exception('hi') + elif x == 2: + {1: 1}[0] + elif x == 3: + a = object() # type: Any + a.lol + +def f(b: bool) -> None: + try: + r(int(b)) + except AttributeError: + print('no') + except: + print(str(wrapsys.exc_info()[1])) + print(str(wrapsys.exc_info()[1])) + +def h() -> None: + while True: + try: + raise Exception('gonna break') + except: + print(str(wrapsys.exc_info()[1])) + break + print(str(wrapsys.exc_info()[1])) + +def i() -> None: + try: + r(0) + except: + print(type(wrapsys.exc_info()[1])) + raise + +def j(n: int) -> None: + try: + r(n) + except (IndexError, KeyError): + print("lookup!") + except AttributeError as e: + print("attr! --", e) + +def k() -> None: + try: + r(1) + except: + r(0) + +def l() -> None: + try: + r(0) + except IndexError: + try: + r(2) + except KeyError as e: + print("key! --", e) + +def m(x: object) -> int: + try: + st = id(x) + except Exception: + return -1 + return st + 1 + +def iter_exception() -> Iterator[str]: + try: + r(0) + except KeyError as e: + yield 'lol' + +[file wrapsys.py] +# This is a gross hack around some limitations of the test system/mypyc. +from typing import Any +import sys +def exc_info() -> Any: + return sys.exc_info() # type: ignore + +[file driver.py] +import sys, traceback +from native import g, f, h, i, j, k, l, m, iter_exception +from testutil import assertRaises +print("== i ==") +try: + i() +except: + traceback.print_exc(file=sys.stdout) + +print("== k ==") +try: + k() +except: + traceback.print_exc(file=sys.stdout) + +print("== g ==") +g(True) +g(False) + +print("== f ==") +f(True) +f(False) + +print("== h ==") +h() + +print("== j ==") +j(0) +j(2) +j(3) +try: + j(1) +except: + print("out!") + +print("== l ==") +l() + +m('lol') + +with assertRaises(IndexError): + list(iter_exception()) + +[out] +== i == + +Traceback (most recent call last): + File "driver.py", line 6, in + i() + File "native.py", line 44, in i + r(0) + File "native.py", line 15, in r + [0][1] +IndexError: list index out of range +== k == +Traceback (most recent call last): + File "native.py", line 59, in k + r(1) + File "native.py", line 17, in r + raise Exception('hi') +Exception: hi + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "driver.py", line 12, in + k() + File "native.py", line 61, in k + r(0) + File "native.py", line 15, in r + [0][1] +IndexError: list index out of range +== g == +caught! +caught! +== f == +hi +None +list index out of range +None +== h == +gonna break +None +== j == +lookup! +lookup! +attr! -- 'object' object has no attribute 'lol' +out! +== l == +key! -- 0 + +[case testTryFinally] +from typing import Any +import wrapsys + +def a(b1: bool, b2: int) -> None: + try: + if b1: + raise Exception('hi') + finally: + print('finally:', str(wrapsys.exc_info()[1])) + if b2 == 2: + return + if b2 == 1: + raise Exception('again!') + +def b(b1: int, b2: int) -> str: + try: + if b1 == 1: + raise Exception('hi') + elif b1 == 2: + [0][1] + elif b1 == 3: + return 'try' + except IndexError: + print('except') + finally: + print('finally:', str(wrapsys.exc_info()[1])) + if b2 == 2: + return 'finally' + if b2 == 1: + raise Exception('again!') + return 'outer' + +def c() -> str: + try: + try: + return 'wee' + finally: + print("out a") + finally: + print("out b") + + +[file wrapsys.py] +# This is a gross hack around some limitations of the test system/mypyc. +from typing import Any +import sys +def exc_info() -> Any: + return sys.exc_info() # type: ignore + +[file driver.py] +import traceback +import sys +from native import a, b, c + +def run(f): + try: + x = f() + if x: + print("returned:", x) + except Exception as e: + print("caught:", type(e).__name__ + ": " + str(e)) + +print("== a ==") +for i in range(3): + for b1 in [False, True]: + run(lambda: a(b1, i)) + +print("== b ==") +for i in range(4): + for j in range(3): + run(lambda: b(i, j)) + +print("== b ==") +print(c()) + +[out] +== a == +finally: None +finally: hi +caught: Exception: hi +finally: None +caught: Exception: again! +finally: hi +caught: Exception: again! +finally: None +finally: hi +== b == +finally: None +returned: outer +finally: None +caught: Exception: again! +finally: None +returned: finally +finally: hi +caught: Exception: hi +finally: hi +caught: Exception: again! +finally: hi +returned: finally +except +finally: None +returned: outer +except +finally: None +caught: Exception: again! +except +finally: None +returned: finally +finally: None +returned: try +finally: None +caught: Exception: again! +finally: None +returned: finally +== b == +out a +out b +wee + +[case testCustomException] +from typing import List + +class ListOutOfBounds(IndexError): + pass + +class UserListWarning(UserWarning): + pass + +def f(l: List[int], k: int) -> int: + try: + return l[k] + except IndexError: + raise ListOutOfBounds("Ruh-roh from f!") + +def g(l: List[int], k: int) -> int: + try: + return f([1,2,3], 3) + except ListOutOfBounds: + raise ListOutOfBounds("Ruh-roh from g!") + +def k(l: List[int], k: int) -> int: + try: + return g([1,2,3], 3) + except IndexError: + raise UserListWarning("Ruh-roh from k!") + +def h() -> int: + try: + return k([1,2,3], 3) + except UserWarning: + return -1 + +[file driver.py] +from native import h +assert h() == -1 + +[case testExceptionAtModuleTopLevel] +from typing import Any + +def f(x: int) -> None: pass + +y: Any = '' +f(y) + +[file driver.py] +import traceback +try: + import native +except TypeError: + traceback.print_exc() +else: + assert False + +[out] +Traceback (most recent call last): + File "driver.py", line 3, in + import native + File "native.py", line 6, in + f(y) +TypeError: int object expected; got str diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index 1afcf2fdfe7f..0945ecfa7c1f 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -444,428 +444,6 @@ import native native.test_native_method_call_with_kwargs() native.test_module_method_call_with_kwargs() -[case testException] -from typing import List -def f(x: List[int]) -> None: - g(x) - -def g(x: List[int]) -> bool: - x[5] = 2 - return True - -def r1() -> None: - q1() - -def q1() -> None: - raise Exception("test") - -def r2() -> None: - q2() - -def q2() -> None: - raise Exception - -class A: - def __init__(self) -> None: - raise Exception - -def hey() -> None: - A() - -[file driver.py] -from native import f, r1, r2, hey -import traceback -try: - f([]) -except IndexError: - traceback.print_exc() -try: - r1() -except Exception: - traceback.print_exc() -try: - r2() -except Exception: - traceback.print_exc() -try: - hey() -except Exception: - traceback.print_exc() -[out] -Traceback (most recent call last): - File "driver.py", line 4, in - f([]) - File "native.py", line 3, in f - g(x) - File "native.py", line 6, in g - x[5] = 2 -IndexError: list assignment index out of range -Traceback (most recent call last): - File "driver.py", line 8, in - r1() - File "native.py", line 10, in r1 - q1() - File "native.py", line 13, in q1 - raise Exception("test") -Exception: test -Traceback (most recent call last): - File "driver.py", line 12, in - r2() - File "native.py", line 16, in r2 - q2() - File "native.py", line 19, in q2 - raise Exception -Exception -Traceback (most recent call last): - File "driver.py", line 16, in - hey() - File "native.py", line 26, in hey - A() - File "native.py", line 23, in __init__ - raise Exception -Exception - -[case testTryExcept] -from typing import Any, Iterator -import wrapsys -def g(b: bool) -> None: - try: - if b: - x = [0] - x[1] - else: - raise Exception('hi') - except: - print("caught!") - -def r(x: int) -> None: - if x == 0: - [0][1] - elif x == 1: - raise Exception('hi') - elif x == 2: - {1: 1}[0] - elif x == 3: - a = object() # type: Any - a.lol - -def f(b: bool) -> None: - try: - r(int(b)) - except AttributeError: - print('no') - except: - print(str(wrapsys.exc_info()[1])) - print(str(wrapsys.exc_info()[1])) - -def h() -> None: - while True: - try: - raise Exception('gonna break') - except: - print(str(wrapsys.exc_info()[1])) - break - print(str(wrapsys.exc_info()[1])) - -def i() -> None: - try: - r(0) - except: - print(type(wrapsys.exc_info()[1])) - raise - -def j(n: int) -> None: - try: - r(n) - except (IndexError, KeyError): - print("lookup!") - except AttributeError as e: - print("attr! --", e) - -def k() -> None: - try: - r(1) - except: - r(0) - -def l() -> None: - try: - r(0) - except IndexError: - try: - r(2) - except KeyError as e: - print("key! --", e) - -def m(x: object) -> int: - try: - st = id(x) - except Exception: - return -1 - return st + 1 - -def iter_exception() -> Iterator[str]: - try: - r(0) - except KeyError as e: - yield 'lol' - -[file wrapsys.py] -# This is a gross hack around some limitations of the test system/mypyc. -from typing import Any -import sys -def exc_info() -> Any: - return sys.exc_info() # type: ignore - -[file driver.py] -import sys, traceback -from native import g, f, h, i, j, k, l, m, iter_exception -from testutil import assertRaises -print("== i ==") -try: - i() -except: - traceback.print_exc(file=sys.stdout) - -print("== k ==") -try: - k() -except: - traceback.print_exc(file=sys.stdout) - -print("== g ==") -g(True) -g(False) - -print("== f ==") -f(True) -f(False) - -print("== h ==") -h() - -print("== j ==") -j(0) -j(2) -j(3) -try: - j(1) -except: - print("out!") - -print("== l ==") -l() - -m('lol') - -with assertRaises(IndexError): - list(iter_exception()) - -[out] -== i == - -Traceback (most recent call last): - File "driver.py", line 6, in - i() - File "native.py", line 44, in i - r(0) - File "native.py", line 15, in r - [0][1] -IndexError: list index out of range -== k == -Traceback (most recent call last): - File "native.py", line 59, in k - r(1) - File "native.py", line 17, in r - raise Exception('hi') -Exception: hi - -During handling of the above exception, another exception occurred: - -Traceback (most recent call last): - File "driver.py", line 12, in - k() - File "native.py", line 61, in k - r(0) - File "native.py", line 15, in r - [0][1] -IndexError: list index out of range -== g == -caught! -caught! -== f == -hi -None -list index out of range -None -== h == -gonna break -None -== j == -lookup! -lookup! -attr! -- 'object' object has no attribute 'lol' -out! -== l == -key! -- 0 - -[case testTryFinally] -from typing import Any -import wrapsys - -def a(b1: bool, b2: int) -> None: - try: - if b1: - raise Exception('hi') - finally: - print('finally:', str(wrapsys.exc_info()[1])) - if b2 == 2: - return - if b2 == 1: - raise Exception('again!') - -def b(b1: int, b2: int) -> str: - try: - if b1 == 1: - raise Exception('hi') - elif b1 == 2: - [0][1] - elif b1 == 3: - return 'try' - except IndexError: - print('except') - finally: - print('finally:', str(wrapsys.exc_info()[1])) - if b2 == 2: - return 'finally' - if b2 == 1: - raise Exception('again!') - return 'outer' - -def c() -> str: - try: - try: - return 'wee' - finally: - print("out a") - finally: - print("out b") - - -[file wrapsys.py] -# This is a gross hack around some limitations of the test system/mypyc. -from typing import Any -import sys -def exc_info() -> Any: - return sys.exc_info() # type: ignore - -[file driver.py] -import traceback -import sys -from native import a, b, c - -def run(f): - try: - x = f() - if x: - print("returned:", x) - except Exception as e: - print("caught:", type(e).__name__ + ": " + str(e)) - -print("== a ==") -for i in range(3): - for b1 in [False, True]: - run(lambda: a(b1, i)) - -print("== b ==") -for i in range(4): - for j in range(3): - run(lambda: b(i, j)) - -print("== b ==") -print(c()) - -[out] -== a == -finally: None -finally: hi -caught: Exception: hi -finally: None -caught: Exception: again! -finally: hi -caught: Exception: again! -finally: None -finally: hi -== b == -finally: None -returned: outer -finally: None -caught: Exception: again! -finally: None -returned: finally -finally: hi -caught: Exception: hi -finally: hi -caught: Exception: again! -finally: hi -returned: finally -except -finally: None -returned: outer -except -finally: None -caught: Exception: again! -except -finally: None -returned: finally -finally: None -returned: try -finally: None -caught: Exception: again! -finally: None -returned: finally -== b == -out a -out b -wee - -[case testCustomException] -from typing import List - -class ListOutOfBounds(IndexError): - pass - -class UserListWarning(UserWarning): - pass - -def f(l: List[int], k: int) -> int: - try: - return l[k] - except IndexError: - raise ListOutOfBounds("Ruh-roh from f!") - -def g(l: List[int], k: int) -> int: - try: - return f([1,2,3], 3) - except ListOutOfBounds: - raise ListOutOfBounds("Ruh-roh from g!") - -def k(l: List[int], k: int) -> int: - try: - return g([1,2,3], 3) - except IndexError: - raise UserListWarning("Ruh-roh from k!") - -def h() -> int: - try: - return k([1,2,3], 3) - except UserWarning: - return -1 - -[file driver.py] -from native import h -assert h() == -1 - [case testWith] from typing import Any class Thing: @@ -1829,31 +1407,6 @@ print(native.x) 6 77 -[case testExceptionAtModuleTopLevel] -from typing import Any - -def f(x: int) -> None: pass - -y: Any = '' -f(y) - -[file driver.py] -import traceback -try: - import native -except TypeError: - traceback.print_exc() -else: - assert False - -[out] -Traceback (most recent call last): - File "driver.py", line 3, in - import native - File "native.py", line 6, in - f(y) -TypeError: int object expected; got str - [case testComprehensions] # A list comprehension l = [str(x) + " " + str(y) + " " + str(x*y) for x in range(10) diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index 9fff2c694212..6a6ac10c5c3d 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -38,6 +38,7 @@ 'run-lists.test', 'run-dicts.test', 'run-loops.test', + 'run-exceptions.test', 'run-classes.test', 'run-traits.test', 'run-generators.test', From 8a82de5e25ab9e11eb19c31d243541beda7c0574 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 20:26:46 +0100 Subject: [PATCH 07/14] Move some function related run tests to run-functions.test --- mypyc/test-data/run-functions.test | 846 +++++++++++++++++++++++++++++ mypyc/test-data/run.test | 843 ---------------------------- 2 files changed, 846 insertions(+), 843 deletions(-) diff --git a/mypyc/test-data/run-functions.test b/mypyc/test-data/run-functions.test index dfc9ff7c875c..7f192d8cf7e2 100644 --- a/mypyc/test-data/run-functions.test +++ b/mypyc/test-data/run-functions.test @@ -1,3 +1,39 @@ +# 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) + return 0 # TODO: This should be unnecessary +[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 @@ -243,3 +279,813 @@ 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 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 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) diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index 0945ecfa7c1f..25c0a33c4ff0 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -1,20 +1,5 @@ # Misc test cases (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 testAsync] import asyncio @@ -41,25 +26,6 @@ loop = asyncio.get_event_loop() result = loop.run_until_complete(f()) assert result == 1 -[case testRecursiveFibonacci] -def fib(n: int) -> int: - if n <= 1: - return 1 - else: - return fib(n - 1) + fib(n - 2) - return 0 # TODO: This should be unnecessary -[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 testTrue] def f() -> bool: return True @@ -129,83 +95,6 @@ with assertRaises(NameError): [out] lol -[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 testImports] import testmodule @@ -403,47 +292,6 @@ s = {1, 2, 3} update(s, [5, 4, 3]) assert s == {1, 2, 3, 4, 5} -[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 testWith] from typing import Any class Thing: @@ -760,25 +608,6 @@ except AttributeError: else: assert False -[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 testFloat] def assign_and_return_float_sum() -> float: f1 = 1.0 @@ -855,164 +684,6 @@ assert setDisplay({4}, {5}) == {1, 2, 3, 4, 5} assert tupleDisplay(['4', '5'], ['6']) == ('1', '2', '4', '5', '6', '3') assert dictDisplay('x', {'y1': 1}, {'y2': 2, 'z': 5}) == {'x': 2, 'y1': 1, 'y2': 2, 'z': 5} -[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 testArbitraryLvalues] from typing import List, Dict, Any @@ -1050,165 +721,6 @@ assert increment_attr_o(O()).x == 2 assert increment_all_indices([1, 2, 3]) == [2, 3, 4] assert increment_all_keys({'a':1, 'b':2, 'c':3}) == {'a':2, 'b':3, 'c':4} -[case testNestedFunctions] -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 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 testControlFlowExprs] from typing import Tuple def foo() -> object: @@ -2137,190 +1649,6 @@ except TypeError: else: assert False -[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 testAnyAll] from typing import Iterable @@ -2474,16 +1802,6 @@ print(z) 1 2 -[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 testCheckVersion] import sys @@ -2516,167 +1834,6 @@ try: except RuntimeError: assert version == (3, 5), "only 3.5 should fail!" -[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 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 testTypeErrorMessages] from typing import Tuple class A: From 774ebb32cd0592865a033b849ec14cbe3b01e330 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 20:29:46 +0100 Subject: [PATCH 08/14] Move property run tests to run-classes.test --- mypyc/test-data/run-classes.test | 306 +++++++++++++++++++++++++++++++ mypyc/test-data/run.test | 306 ------------------------------- 2 files changed, 306 insertions(+), 306 deletions(-) diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index 42b41e219b7c..5369ab0f0455 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -1443,3 +1443,309 @@ with patch("interp.Bar.spam", lambda self: 20): with assertRaises(TypeError, "int object expected; got str"): y.x = "test" + +[case testProperty] +from typing import Callable +from mypy_extensions import trait +class Temperature: + @property + def celsius(self) -> float: + return 5.0 * (self.farenheit - 32.0) / 9.0 + + def __init__(self, farenheit: float) -> None: + self.farenheit = farenheit + + def print_temp(self) -> None: + print("F:", self.farenheit, "C:", self.celsius) + + @property + def rankine(self) -> float: + raise NotImplementedError + +class Access: + @property + def number_of_accesses(self) -> int: + self._count += 1 + return self._count + def __init__(self) -> None: + self._count = 0 + +from typing import Callable +class BaseProperty: + @property + def doc(self) -> str: + return "Represents a sequence of values. Updates itself by next, which is a new value." + + @property + def value(self) -> object: + return self._incrementer + + @property + def bad_value(self) -> object: + return self._incrementer + + @property + def next(self) -> BaseProperty: + return BaseProperty(self._incrementer + 1) + + def __init__(self, value: int) -> None: + self._incrementer = value + +class DerivedProperty(BaseProperty): + @property + def value(self) -> int: + return self._incrementer + + @property + def bad_value(self) -> object: + return self._incrementer + + def __init__(self, incr_func: Callable[[int], int], value: int) -> None: + BaseProperty.__init__(self, value) + self._incr_func = incr_func + + @property + def next(self) -> DerivedProperty: + return DerivedProperty(self._incr_func, self._incr_func(self.value)) + +class AgainProperty(DerivedProperty): + @property + def next(self) -> AgainProperty: + return AgainProperty(self._incr_func, self._incr_func(self._incr_func(self.value))) + + @property + def bad_value(self) -> int: + return self._incrementer + +def print_first_n(n: int, thing: BaseProperty) -> None: + vals = [] + cur_thing = thing + for _ in range(n): + vals.append(cur_thing.value) + cur_thing = cur_thing.next + print ('', vals) + +@trait +class Trait: + @property + def value(self) -> int: + return 3 + +class Printer(Trait): + def print_value(self) -> None: + print(self.value) + +[file driver.py] +from native import Temperature, Access +import traceback +x = Temperature(32.0) +try: + print (x.rankine) +except NotImplementedError as e: + traceback.print_exc() +print (x.celsius) +x.print_temp() + +y = Temperature(212.0) +print (y.celsius) +y.print_temp() + +z = Access() +print (z.number_of_accesses) +print (z.number_of_accesses) +print (z.number_of_accesses) +print (z.number_of_accesses) + +from native import BaseProperty, DerivedProperty, AgainProperty, print_first_n +a = BaseProperty(7) +b = DerivedProperty((lambda x: x // 2 if (x % 2 == 0) else 3 * x + 1), 7) +c = AgainProperty((lambda x: x // 2 if (x % 2 == 0) else 3 * x + 1), 7) + +def py_print_first_n(n: int, thing: BaseProperty) -> None: + vals = [] + cur_thing = thing + for _ in range(n): + vals.append(cur_thing.value) + cur_thing = cur_thing.next + print ('', vals) + +py_print_first_n(20, a) +py_print_first_n(20, b) +py_print_first_n(20, c) + +print(a.next.next.next.bad_value) +print(b.next.next.next.bad_value) +print(c.next.next.next.bad_value) + +print_first_n(20, a) +print_first_n(20, b) +print_first_n(20, c) + +print (a.doc) +print (b.doc) +print (c.doc) + +from native import Printer +Printer().print_value() +print (Printer().value) +[out] +Traceback (most recent call last): + File "driver.py", line 5, in + print (x.rankine) + File "native.py", line 16, in rankine + raise NotImplementedError +NotImplementedError +0.0 +F: 32.0 C: 0.0 +100.0 +F: 212.0 C: 100.0 +1 +2 +3 +4 + [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] + [7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, 4, 2, 1] + [7, 11, 17, 26, 40, 10, 16, 4, 1, 2, 4, 1, 2, 4, 1, 2, 4, 1, 2, 4] +10 +34 +26 + [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] + [7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, 4, 2, 1] + [7, 11, 17, 26, 40, 10, 16, 4, 1, 2, 4, 1, 2, 4, 1, 2, 4, 1, 2, 4] +Represents a sequence of values. Updates itself by next, which is a new value. +Represents a sequence of values. Updates itself by next, which is a new value. +Represents a sequence of values. Updates itself by next, which is a new value. +3 +3 + +[case testPropertySetters] + +from mypy_extensions import trait + +class Foo(): + def __init__(self) -> None: + self.attr = "unmodified" + +class A: + def __init__(self) -> None: + self._x = 0 + self._foo = Foo() + + @property + def x(self) -> int: + return self._x + + @x.setter + def x(self, val : int) -> None: + self._x = val + + @property + def foo(self) -> Foo: + return self._foo + + @foo.setter + def foo(self, val : Foo) -> None: + self._foo = val + +# Overrides base property setters and getters +class B(A): + def __init__(self) -> None: + self._x = 10 + + @property + def x(self) -> int: + return self._x + 1 + + @x.setter + def x(self, val : int) -> None: + self._x = val + 1 + +#Inerits base property setters and getters +class C(A): + def __init__(self) -> None: + A.__init__(self) + +@trait +class D(): + def __init__(self) -> None: + self._x = 0 + + @property + def x(self) -> int: + return self._x + + @x.setter + def x(self, val : int) -> None: + self._x = val + +#Inherits trait property setters and getters +class E(D): + def __init__(self) -> None: + D.__init__(self) + +#Overrides trait property setters and getters +class F(D): + def __init__(self) -> None: + self._x = 10 + + @property + def x(self) -> int: + return self._x + 10 + + @x.setter + def x(self, val : int) -> None: + self._x = val + 10 + +# # Property setter and getter are subtypes of base property setters and getters +# # class G(A): +# # def __init__(self) -> None: +# # A.__init__(self) + +# # @property +# # def y(self) -> int: +# # return self._y + +# # @y.setter +# # def y(self, val : object) -> None: +# # self._y = val + +[file other.py] +# Run in both interpreted and compiled mode + +from native import A, B, C, D, E, F + +a = A() +assert a.x == 0 +assert a._x == 0 +a.x = 1 +assert a.x == 1 +assert a._x == 1 +a._x = 0 +assert a.x == 0 +assert a._x == 0 +b = B() +assert b.x == 11 +assert b._x == 10 +b.x = 11 +assert b.x == 13 +b._x = 11 +assert b.x == 12 +c = C() +assert c.x == 0 +c.x = 1000 +assert c.x == 1000 +e = E() +assert e.x == 0 +e.x = 1000 +assert e.x == 1000 +f = F() +assert f.x == 20 +f.x = 30 +assert f.x == 50 + +[file driver.py] +# Run the tests in both interpreted and compiled mode +import other +import other_interpreted + +[out] diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index 25c0a33c4ff0..bfd89edb9998 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -1141,312 +1141,6 @@ three 3 8 16 -[case testProperty] -from typing import Callable -from mypy_extensions import trait -class Temperature: - @property - def celsius(self) -> float: - return 5.0 * (self.farenheit - 32.0) / 9.0 - - def __init__(self, farenheit: float) -> None: - self.farenheit = farenheit - - def print_temp(self) -> None: - print("F:", self.farenheit, "C:", self.celsius) - - @property - def rankine(self) -> float: - raise NotImplementedError - -class Access: - @property - def number_of_accesses(self) -> int: - self._count += 1 - return self._count - def __init__(self) -> None: - self._count = 0 - -from typing import Callable -class BaseProperty: - @property - def doc(self) -> str: - return "Represents a sequence of values. Updates itself by next, which is a new value." - - @property - def value(self) -> object: - return self._incrementer - - @property - def bad_value(self) -> object: - return self._incrementer - - @property - def next(self) -> BaseProperty: - return BaseProperty(self._incrementer + 1) - - def __init__(self, value: int) -> None: - self._incrementer = value - -class DerivedProperty(BaseProperty): - @property - def value(self) -> int: - return self._incrementer - - @property - def bad_value(self) -> object: - return self._incrementer - - def __init__(self, incr_func: Callable[[int], int], value: int) -> None: - BaseProperty.__init__(self, value) - self._incr_func = incr_func - - @property - def next(self) -> DerivedProperty: - return DerivedProperty(self._incr_func, self._incr_func(self.value)) - -class AgainProperty(DerivedProperty): - @property - def next(self) -> AgainProperty: - return AgainProperty(self._incr_func, self._incr_func(self._incr_func(self.value))) - - @property - def bad_value(self) -> int: - return self._incrementer - -def print_first_n(n: int, thing: BaseProperty) -> None: - vals = [] - cur_thing = thing - for _ in range(n): - vals.append(cur_thing.value) - cur_thing = cur_thing.next - print ('', vals) - -@trait -class Trait: - @property - def value(self) -> int: - return 3 - -class Printer(Trait): - def print_value(self) -> None: - print(self.value) - -[file driver.py] -from native import Temperature, Access -import traceback -x = Temperature(32.0) -try: - print (x.rankine) -except NotImplementedError as e: - traceback.print_exc() -print (x.celsius) -x.print_temp() - -y = Temperature(212.0) -print (y.celsius) -y.print_temp() - -z = Access() -print (z.number_of_accesses) -print (z.number_of_accesses) -print (z.number_of_accesses) -print (z.number_of_accesses) - -from native import BaseProperty, DerivedProperty, AgainProperty, print_first_n -a = BaseProperty(7) -b = DerivedProperty((lambda x: x // 2 if (x % 2 == 0) else 3 * x + 1), 7) -c = AgainProperty((lambda x: x // 2 if (x % 2 == 0) else 3 * x + 1), 7) - -def py_print_first_n(n: int, thing: BaseProperty) -> None: - vals = [] - cur_thing = thing - for _ in range(n): - vals.append(cur_thing.value) - cur_thing = cur_thing.next - print ('', vals) - -py_print_first_n(20, a) -py_print_first_n(20, b) -py_print_first_n(20, c) - -print(a.next.next.next.bad_value) -print(b.next.next.next.bad_value) -print(c.next.next.next.bad_value) - -print_first_n(20, a) -print_first_n(20, b) -print_first_n(20, c) - -print (a.doc) -print (b.doc) -print (c.doc) - -from native import Printer -Printer().print_value() -print (Printer().value) -[out] -Traceback (most recent call last): - File "driver.py", line 5, in - print (x.rankine) - File "native.py", line 16, in rankine - raise NotImplementedError -NotImplementedError -0.0 -F: 32.0 C: 0.0 -100.0 -F: 212.0 C: 100.0 -1 -2 -3 -4 - [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] - [7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, 4, 2, 1] - [7, 11, 17, 26, 40, 10, 16, 4, 1, 2, 4, 1, 2, 4, 1, 2, 4, 1, 2, 4] -10 -34 -26 - [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] - [7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, 4, 2, 1] - [7, 11, 17, 26, 40, 10, 16, 4, 1, 2, 4, 1, 2, 4, 1, 2, 4, 1, 2, 4] -Represents a sequence of values. Updates itself by next, which is a new value. -Represents a sequence of values. Updates itself by next, which is a new value. -Represents a sequence of values. Updates itself by next, which is a new value. -3 -3 - -[case testPropertySetters] - -from mypy_extensions import trait - -class Foo(): - def __init__(self) -> None: - self.attr = "unmodified" - -class A: - def __init__(self) -> None: - self._x = 0 - self._foo = Foo() - - @property - def x(self) -> int: - return self._x - - @x.setter - def x(self, val : int) -> None: - self._x = val - - @property - def foo(self) -> Foo: - return self._foo - - @foo.setter - def foo(self, val : Foo) -> None: - self._foo = val - -# Overrides base property setters and getters -class B(A): - def __init__(self) -> None: - self._x = 10 - - @property - def x(self) -> int: - return self._x + 1 - - @x.setter - def x(self, val : int) -> None: - self._x = val + 1 - -#Inerits base property setters and getters -class C(A): - def __init__(self) -> None: - A.__init__(self) - -@trait -class D(): - def __init__(self) -> None: - self._x = 0 - - @property - def x(self) -> int: - return self._x - - @x.setter - def x(self, val : int) -> None: - self._x = val - -#Inherits trait property setters and getters -class E(D): - def __init__(self) -> None: - D.__init__(self) - -#Overrides trait property setters and getters -class F(D): - def __init__(self) -> None: - self._x = 10 - - @property - def x(self) -> int: - return self._x + 10 - - @x.setter - def x(self, val : int) -> None: - self._x = val + 10 - -# # Property setter and getter are subtypes of base property setters and getters -# # class G(A): -# # def __init__(self) -> None: -# # A.__init__(self) - -# # @property -# # def y(self) -> int: -# # return self._y - -# # @y.setter -# # def y(self, val : object) -> None: -# # self._y = val - -[file other.py] -# Run in both interpreted and compiled mode - -from native import A, B, C, D, E, F - -a = A() -assert a.x == 0 -assert a._x == 0 -a.x = 1 -assert a.x == 1 -assert a._x == 1 -a._x = 0 -assert a.x == 0 -assert a._x == 0 -b = B() -assert b.x == 11 -assert b._x == 10 -b.x = 11 -assert b.x == 13 -b._x = 11 -assert b.x == 12 -c = C() -assert c.x == 0 -c.x = 1000 -assert c.x == 1000 -e = E() -assert e.x == 0 -e.x = 1000 -assert e.x == 1000 -f = F() -assert f.x == 20 -f.x = 30 -assert f.x == 50 - -[file driver.py] -# Run the tests in both interpreted and compiled mode -import other -import other_interpreted - -[out] - [case testDunders] from typing import Any class Item: From e179cd94b72f58fc02a7206f4d2435186d484154 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 20:33:58 +0100 Subject: [PATCH 09/14] Move import run test cases to a new file --- mypyc/test-data/run-imports.test | 89 ++++++++++++++++++++++++++++++++ mypyc/test-data/run-lists.test | 2 +- mypyc/test-data/run.test | 88 ------------------------------- mypyc/test/test_run.py | 1 + 4 files changed, 91 insertions(+), 89 deletions(-) create mode 100644 mypyc/test-data/run-imports.test diff --git a/mypyc/test-data/run-imports.test b/mypyc/test-data/run-imports.test new file mode 100644 index 000000000000..6b5a70cf6ced --- /dev/null +++ b/mypyc/test-data/run-imports.test @@ -0,0 +1,89 @@ +# Test cases for imports and related features (compile and run) + +[case testImports] +import testmodule + +def f(x: int) -> int: + return testmodule.factorial(5) +def g(x: int) -> int: + from welp import foo + return foo(x) +[file testmodule.py] +def factorial(x: int) -> int: + if x == 0: + return 1 + else: + return x * factorial(x-1) +[file welp.py] +def foo(x: int) -> int: + return x +[file driver.py] +from native import f, g +print(f(5)) +print(g(5)) +[out] +120 +5 + +[case testImportMissing] +# The unchecked module is configured by the test harness to not be +# picked up by mypy, so we can test that we do that right thing when +# calling library modules without stubs. +import unchecked # type: ignore +import unchecked as lol # type: ignore +assert unchecked.x == 10 +assert lol.x == 10 +[file unchecked.py] +x = 10 + +[file driver.py] +import native + +[case testFromImport] +from testmodule import g + +def f(x: int) -> int: + return g(x) +[file testmodule.py] +def g(x: int) -> int: + return x + 1 +[file driver.py] +from native import f +assert f(1) == 2 + +[case testReexport] +# Test that we properly handle accessing values that have been reexported +import a +def f(x: int) -> int: + return a.g(x) + a.foo + a.b.foo + +whatever = a.A() + +[file a.py] +from b import g as g, A as A, foo as foo +import b + +[file b.py] +def g(x: int) -> int: + return x + 1 + +class A: + pass + +foo = 20 + +[file driver.py] +from native import f, whatever +import b + +assert f(20) == 61 +assert isinstance(whatever, b.A) + +[case testAssignModule] +import a +assert a.x == 20 +a.x = 10 +[file a.py] +x = 20 +[file driver.py] +import native diff --git a/mypyc/test-data/run-lists.test b/mypyc/test-data/run-lists.test index ac1f9b392007..25fb993e601b 100644 --- a/mypyc/test-data/run-lists.test +++ b/mypyc/test-data/run-lists.test @@ -1,4 +1,4 @@ -# Test cases for strings (compile and run) +# Test cases for lists (compile and run) [case testListPlusEquals] from typing import Any diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index bfd89edb9998..05d235854d6f 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -95,31 +95,6 @@ with assertRaises(NameError): [out] lol -[case testImports] -import testmodule - -def f(x: int) -> int: - return testmodule.factorial(5) -def g(x: int) -> int: - from welp import foo - return foo(x) -[file testmodule.py] -def factorial(x: int) -> int: - if x == 0: - return 1 - else: - return x * factorial(x-1) -[file welp.py] -def foo(x: int) -> int: - return x -[file driver.py] -from native import f, g -print(f(5)) -print(g(5)) -[out] -120 -5 - [case testBuiltins] y = 10 def f(x: int) -> None: @@ -134,20 +109,6 @@ f(5) [out] 5 -[case testImportMissing] -# The unchecked module is configured by the test harness to not be -# picked up by mypy, so we can test that we do that right thing when -# calling library modules without stubs. -import unchecked # type: ignore -import unchecked as lol # type: ignore -assert unchecked.x == 10 -assert lol.x == 10 -[file unchecked.py] -x = 10 - -[file driver.py] -import native - [case testOptional] from typing import Optional @@ -174,18 +135,6 @@ assert f(a) is a assert g(None) == 1 assert g(a) == 2 -[case testFromImport] -from testmodule import g - -def f(x: int) -> int: - return g(x) -[file testmodule.py] -def g(x: int) -> int: - return x + 1 -[file driver.py] -from native import f -assert f(1) == 2 - [case testSets] from typing import Set, List def instantiateLiteral() -> Set[int]: @@ -1393,15 +1342,6 @@ assert call_all(mixed_110) == 1 assert call_any_nested([[1, 1, 1], [1, 1], []]) == 1 assert call_any_nested([[1, 1, 1], [0, 1], []]) == 0 -[case testAssignModule] -import a -assert a.x == 20 -a.x = 10 -[file a.py] -x = 20 -[file driver.py] -import native - [case testNoneStuff] from typing import Optional class A: @@ -1575,31 +1515,3 @@ from native import foo assert foo(None) == None assert foo([1, 2, 3]) == ((1, 2, 3), [1, 2, 3]) - -[case testReexport] -# Test that we properly handle accessing values that have been reexported -import a -def f(x: int) -> int: - return a.g(x) + a.foo + a.b.foo - -whatever = a.A() - -[file a.py] -from b import g as g, A as A, foo as foo -import b - -[file b.py] -def g(x: int) -> int: - return x + 1 - -class A: - pass - -foo = 20 - -[file driver.py] -from native import f, whatever -import b - -assert f(20) == 61 -assert isinstance(whatever, b.A) diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index 6a6ac10c5c3d..8304450c881b 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -39,6 +39,7 @@ 'run-dicts.test', 'run-loops.test', 'run-exceptions.test', + 'run-imports.test', 'run-classes.test', 'run-traits.test', 'run-generators.test', From ae25bdc9d4f7c32efb6fcf3acdf753ba43df6c24 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 20:36:36 +0100 Subject: [PATCH 10/14] Move set run tests to a new file --- mypyc/test-data/run-sets.test | 107 ++++++++++++++++++++++++++++++++++ mypyc/test-data/run.test | 106 --------------------------------- mypyc/test/test_run.py | 1 + 3 files changed, 108 insertions(+), 106 deletions(-) create mode 100644 mypyc/test-data/run-sets.test diff --git a/mypyc/test-data/run-sets.test b/mypyc/test-data/run-sets.test new file mode 100644 index 000000000000..93b86771b19f --- /dev/null +++ b/mypyc/test-data/run-sets.test @@ -0,0 +1,107 @@ +# Test cases for sets (compile and run) + +[case testSets] +from typing import Set, List +def instantiateLiteral() -> Set[int]: + return {1, 2, 3, 5, 8} + +def fromIterator() -> List[Set[int]]: + x = set([1, 3, 5]) + y = set((1, 3, 5)) + z = set({1: '1', 3: '3', 5: '5'}) + return [x, y, z] + +def addIncrementing(s : Set[int]) -> None: + for a in [1, 2, 3]: + if a not in s: + s.add(a) + return + +def replaceWith1(s : Set[int]) -> None: + s.clear() + s.add(1) + +def remove1(s : Set[int]) -> None: + s.remove(1) + +def discard1(s: Set[int]) -> None: + s.discard(1) + +def pop(s : Set[int]) -> int: + return s.pop() + +def update(s: Set[int], x: List[int]) -> None: + s.update(x) + +[file driver.py] +from native import instantiateLiteral +from testutil import assertRaises + +val = instantiateLiteral() +assert 1 in val +assert 2 in val +assert 3 in val +assert 5 in val +assert 8 in val +assert len(val) == 5 +assert val == {1, 2, 3, 5, 8} +s = 0 +for i in val: + s += i +assert s == 19 + +from native import fromIterator +sets = fromIterator() +for s in sets: + assert s == {1, 3, 5} + +from native import addIncrementing +s = set() +addIncrementing(s) +assert s == {1} +addIncrementing(s) +assert s == {1, 2} +addIncrementing(s) +assert s == {1, 2, 3} + +from native import replaceWith1 +s = {3, 7, 12} +replaceWith1(s) +assert s == {1} + +from native import remove1 +import traceback +s = {1, 4, 6} +remove1(s) +assert s == {4, 6} +with assertRaises(KeyError, '1'): + remove1(s) + +from native import discard1 +s = {1, 4, 6} +discard1(s) +assert s == {4, 6} +discard1(s) +assert s == {4, 6} + +from native import pop +s = {1, 2, 3} +x = pop(s) +assert len(s) == 2 +assert x in [1, 2, 3] +y = pop(s) +assert len(s) == 1 +assert y in [1, 2, 3] +assert x != y +z = pop(s) +assert len(s) == 0 +assert z in [1, 2, 3] +assert x != z +assert y != z +with assertRaises(KeyError, 'pop from an empty set'): + pop(s) + +from native import update +s = {1, 2, 3} +update(s, [5, 4, 3]) +assert s == {1, 2, 3, 4, 5} diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index 05d235854d6f..78b057512435 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -135,112 +135,6 @@ assert f(a) is a assert g(None) == 1 assert g(a) == 2 -[case testSets] -from typing import Set, List -def instantiateLiteral() -> Set[int]: - return {1, 2, 3, 5, 8} - -def fromIterator() -> List[Set[int]]: - x = set([1, 3, 5]) - y = set((1, 3, 5)) - z = set({1: '1', 3: '3', 5: '5'}) - return [x, y, z] - -def addIncrementing(s : Set[int]) -> None: - for a in [1, 2, 3]: - if a not in s: - s.add(a) - return - -def replaceWith1(s : Set[int]) -> None: - s.clear() - s.add(1) - -def remove1(s : Set[int]) -> None: - s.remove(1) - -def discard1(s: Set[int]) -> None: - s.discard(1) - -def pop(s : Set[int]) -> int: - return s.pop() - -def update(s: Set[int], x: List[int]) -> None: - s.update(x) - -[file driver.py] -from native import instantiateLiteral -from testutil import assertRaises - -val = instantiateLiteral() -assert 1 in val -assert 2 in val -assert 3 in val -assert 5 in val -assert 8 in val -assert len(val) == 5 -assert val == {1, 2, 3, 5, 8} -s = 0 -for i in val: - s += i -assert s == 19 - -from native import fromIterator -sets = fromIterator() -for s in sets: - assert s == {1, 3, 5} - -from native import addIncrementing -s = set() -addIncrementing(s) -assert s == {1} -addIncrementing(s) -assert s == {1, 2} -addIncrementing(s) -assert s == {1, 2, 3} - -from native import replaceWith1 -s = {3, 7, 12} -replaceWith1(s) -assert s == {1} - -from native import remove1 -import traceback -s = {1, 4, 6} -remove1(s) -assert s == {4, 6} -with assertRaises(KeyError, '1'): - remove1(s) - -from native import discard1 -s = {1, 4, 6} -discard1(s) -assert s == {4, 6} -discard1(s) -assert s == {4, 6} - -from native import pop -s = {1, 2, 3} -x = pop(s) -assert len(s) == 2 -assert x in [1, 2, 3] -y = pop(s) -assert len(s) == 1 -assert y in [1, 2, 3] -assert x != y -z = pop(s) -assert len(s) == 0 -assert z in [1, 2, 3] -assert x != z -assert y != z -with assertRaises(KeyError, 'pop from an empty set'): - pop(s) - -from native import update -s = {1, 2, 3} -update(s, [5, 4, 3]) -assert s == {1, 2, 3, 4, 5} - [case testWith] from typing import Any class Thing: diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index 8304450c881b..486ab582bf4a 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -37,6 +37,7 @@ 'run-tuples.test', 'run-lists.test', 'run-dicts.test', + 'run-sets.test', 'run-loops.test', 'run-exceptions.test', 'run-imports.test', From 07f2103b9405d3f43b6b1f907619b1b40ce28db6 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 20:39:28 +0100 Subject: [PATCH 11/14] Move one more test case to run-classes.test --- mypyc/test-data/run-classes.test | 19 +++++++++++++++++++ mypyc/test-data/run.test | 19 ------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index 5369ab0f0455..66b527bb507a 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -1749,3 +1749,22 @@ import other import other_interpreted [out] + +[case testSubclassAttributeAccess] +from mypy_extensions import trait + +class A: + v = 0 + +class B(A): + v = 1 + +class C(B): + v = 2 + +[file driver.py] +from native import A, B, C + +a = A() +b = B() +c = C() diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index 78b057512435..bf87d2d080d9 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -383,25 +383,6 @@ assert get_item(d, 'x') == 5 set_item(d, 'y', 6) assert d['y'] == 6 -[case testSubclassAttributeAccess] -from mypy_extensions import trait - -class A: - v = 0 - -class B(A): - v = 1 - -class C(B): - v = 2 - -[file driver.py] -from native import A, B, C - -a = A() -b = B() -c = C() - [case testAnyAttributeAndMethodAccess] from typing import Any, List class C: From d83b85b50e7c5f512a828900ecc4108a72ef649c Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 21:34:53 +0100 Subject: [PATCH 12/14] More some primitive-related run tests to a new file --- mypyc/test-data/run-primitives.test | 399 ++++++++++++++++++++++++++++ mypyc/test-data/run.test | 395 --------------------------- mypyc/test/test_run.py | 1 + 3 files changed, 400 insertions(+), 395 deletions(-) create mode 100644 mypyc/test-data/run-primitives.test diff --git a/mypyc/test-data/run-primitives.test b/mypyc/test-data/run-primitives.test new file mode 100644 index 000000000000..450480d3f0a6 --- /dev/null +++ b/mypyc/test-data/run-primitives.test @@ -0,0 +1,399 @@ +# Test cases for misc primitives (compile and run) +# +# Please only add tests that don't have an obvious place in type-specific test +# files such as run-strings.test, run-lists.test, etc. + +[case testGenericEquality] +def eq(a: object, b: object) -> bool: + if a == b: + return True + else: + return False +def ne(a: object, b: object) -> bool: + if a != b: + return True + else: + return False +def f(o: object) -> bool: + if [1, 2] == o: + return True + else: + return False +[file driver.py] +from native import eq, ne, f +assert eq('xz', 'x' + 'z') +assert not eq('x', 'y') +assert not ne('xz', 'x' + 'z') +assert ne('x', 'y') +assert f([1, 2]) +assert not f([2, 2]) +assert not f(1) + +[case testGenericBinaryOps] +from typing import Any +def add(x: Any, y: Any) -> Any: + return x + y +def subtract(x: Any, y: Any) -> Any: + return x - y +def multiply(x: Any, y: Any) -> Any: + return x * y +def floor_div(x: Any, y: Any) -> Any: + return x // y +def true_div(x: Any, y: Any) -> Any: + return x / y +def remainder(x: Any, y: Any) -> Any: + return x % y +def power(x: Any, y: Any) -> Any: + return x ** y +def lshift(x: Any, y: Any) -> Any: + return x << y +def rshift(x: Any, y: Any) -> Any: + return x >> y +def num_and(x: Any, y: Any) -> Any: + return x & y +def num_xor(x: Any, y: Any) -> Any: + return x ^ y +def num_or(x: Any, y: Any) -> Any: + return x | y +def lt(x: Any, y: Any) -> Any: + if x < y: + return True + else: + return False +def le(x: Any, y: Any) -> Any: + if x <= y: + return True + else: + return False +def gt(x: Any, y: Any) -> Any: + if x > y: + return True + else: + return False +def ge(x: Any, y: Any) -> Any: + if x >= y: + return True + else: + return False +def contains(x: Any, y: Any) -> Any: + if x in y: + return True + else: + return False +def identity(x: Any, y: Any) -> Any: + if x is y: + return True + else: + return False +def disidentity(x: Any, y: Any) -> Any: + if x is not y: + return True + else: + return False +def not_eq_cond(a: Any, b: Any) -> bool: + if not (a == b): + return True + else: + return False +def eq2(a: Any, b: Any) -> bool: + return a == b +def slice1(x: Any) -> Any: + return x[:] +def slice2(x: Any, y: Any) -> Any: + return x[y:] +def slice3(x: Any, y: Any) -> Any: + return x[:y] +def slice4(x: Any, y: Any, z: Any) -> Any: + return x[y:z] +def slice5(x: Any, y: Any, z: Any, zz: Any) -> Any: + return x[y:z:zz] +[file driver.py] +from native import * +assert add(5, 6) == 11 +assert add('x', 'y') == 'xy' +assert subtract(8, 3) == 5 +assert multiply(8, 3) == 24 +assert floor_div(8, 3) == 2 +assert true_div(7, 2) == 3.5 +assert remainder(11, 4) == 3 +assert remainder('%.3d', 5) == '005' +assert remainder('%d-%s', (5, 'xy')) == '5-xy' +assert power(3, 4) == 81 +assert lshift(5, 3) == 40 +assert rshift(41, 3) == 5 +assert num_and(99, 56) == 32 +assert num_xor(99, 56) == 91 +assert num_or(99, 56) == 123 +assert lt('a', 'b') +assert not lt('a', 'a') +assert not lt('b', 'a') +assert not gt('a', 'b') +assert not gt('a', 'a') +assert gt('b', 'a') +assert le('a', 'b') +assert le('a', 'a') +assert not le('b', 'a') +assert not ge('a', 'b') +assert ge('a', 'a') +assert ge('b', 'a') +assert contains('x', 'axb') +assert not contains('X', 'axb') +assert contains('x', {'x', 'y'}) +a = [1, 3, 5] +assert slice1(a) == a +assert slice1(a) is not a +assert slice2(a, 1) == [3, 5] +assert slice3(a, -1) == [1, 3] +assert slice4(a, 1, -1) == [3] +assert slice5(a, 2, 0, -1) == [5, 3] +o1, o2 = object(), object() +assert identity(o1, o1) +assert not identity(o1, o2) +assert not disidentity(o1, o1) +assert disidentity(o1, o2) +assert eq2('xz', 'x' + 'z') +assert not eq2('x', 'y') +assert not not_eq_cond('xz', 'x' + 'z') +assert not_eq_cond('x', 'y') + +[case testGenericMiscOps] +from typing import Any +def neg(x: Any) -> Any: + return -x +def pos(x: Any) -> Any: + return +x +def invert(x: Any) -> Any: + return ~x +def get_item(o: Any, k: Any) -> Any: + return o[k] +def set_item(o: Any, k: Any, v: Any) -> Any: + o[k] = v +[file driver.py] +from native import * +assert neg(6) == -6 +assert pos(6) == 6 +assert invert(6) == -7 +d = {'x': 5} +assert get_item(d, 'x') == 5 +set_item(d, 'y', 6) +assert d['y'] == 6 + +[case testAnyAttributeAndMethodAccess] +from typing import Any, List +class C: + a: int + def m(self, x: int, a: List[int]) -> int: + return self.a + x + a[0] +def get_a(x: Any) -> Any: + return x.a +def set_a(x: Any, y: Any) -> None: + x.a = y +def call_m(x: Any) -> Any: + return x.m(1, [3]) +[file driver.py] +from native import C, get_a, set_a, call_m +class D: + def m(self, x, a): + return self.a + x + a[0] + +c = C() +c.a = 6 +d = D() +d.a = 2 +assert get_a(c) == 6 +assert get_a(d) == 2 +assert call_m(c) == 10 +assert call_m(d) == 6 +set_a(c, 5) +assert c.a == 5 +set_a(d, 4) +assert d.a == 4 +try: + get_a(object()) +except AttributeError: + pass +else: + assert False +try: + call_m(object()) +except AttributeError: + pass +else: + assert False +try: + set_a(object(), 5) +except AttributeError: + pass +else: + assert False + +[case testFloat] +def assign_and_return_float_sum() -> float: + f1 = 1.0 + f2 = 2.0 + f3 = 3.0 + return f1 * f2 + f3 + +def from_int(i: int) -> float: + return float(i) + +def to_int(x: float) -> int: + return int(x) + +def get_complex() -> complex: + return 5.0j + 3.0 + +[file driver.py] +from native import assign_and_return_float_sum, from_int, to_int, get_complex +sum = 0.0 +for i in range(10): + sum += assign_and_return_float_sum() +assert sum == 50.0 + +assert str(from_int(10)) == '10.0' +assert str(to_int(3.14)) == '3' +assert str(to_int(3)) == '3' +assert get_complex() == 3+5j + +[case testBytes] +def f(x: bytes) -> bytes: + return x + +def concat(a: bytes, b: bytes) -> bytes: + return a + b + +def eq(a: bytes, b: bytes) -> bool: + return a == b + +def neq(a: bytes, b: bytes) -> bool: + return a != b + +def join() -> bytes: + seq = (b'1', b'"', b'\xf0') + return b'\x07'.join(seq) +[file driver.py] +from native import f, concat, eq, neq, join +assert f(b'123') == b'123' +assert f(b'\x07 \x0b " \t \x7f \xf0') == b'\x07 \x0b " \t \x7f \xf0' +assert concat(b'123', b'456') == b'123456' +assert eq(b'123', b'123') +assert not eq(b'123', b'1234') +assert neq(b'123', b'1234') +assert join() == b'1\x07"\x07\xf0' + +[case testDel] +from typing import List +from testutil import assertRaises + +def printDict(dict) -> None: + l = list(dict.keys()) # type: List[str] + l.sort() + for key in l: + print(key, dict[key]) + print("#########") + +def delList() -> None: + l = [1, 2, 3] + print(tuple(l)) + del l[1] + print(tuple(l)) + +def delDict() -> None: + d = {"one":1, "two":2} + printDict(d) + del d["one"] + printDict(d) + +def delListMultiple() -> None: + l = [1, 2, 3, 4, 5, 6, 7] + print(tuple(l)) + del l[1], l[2], l[3] + print(tuple(l)) + +def delDictMultiple() -> None: + d = {"one":1, "two":2, "three":3, "four":4} + printDict(d) + del d["two"], d["four"] + printDict(d) + +class Dummy(): + def __init__(self, x: int, y: int) -> None: + self.x = x + self.y = y + +def delAttribute() -> None: + dummy = Dummy(1, 2) + del dummy.x + with assertRaises(AttributeError): + dummy.x + +def delAttributeMultiple() -> None: + dummy = Dummy(1, 2) + del dummy.x, dummy.y + with assertRaises(AttributeError): + dummy.x + with assertRaises(AttributeError): + dummy.y + +def delLocal(b: bool) -> int: + dummy = 10 + if b: + del dummy + return dummy + +def delLocalLoop() -> None: + # Try deleting a local in a loop to make sure the control flow analysis works + dummy = 1 + for i in range(10): + print(dummy) + dummy *= 2 + if i == 4: + del dummy + +global_var = 10 +del global_var + +[file driver.py] +from native import ( + delList, delDict, delListMultiple, delDictMultiple, delAttribute, + delAttributeMultiple, delLocal, delLocalLoop, +) +import native +from testutil import assertRaises + +delList() +delDict() +delListMultiple() +delDictMultiple() +delAttribute() +delAttributeMultiple() +with assertRaises(AttributeError): + native.global_var +with assertRaises(NameError, "local variable 'dummy' referenced before assignment"): + delLocal(True) +assert delLocal(False) == 10 +with assertRaises(NameError, "local variable 'dummy' referenced before assignment"): + delLocalLoop() +[out] +(1, 2, 3) +(1, 3) +one 1 +two 2 +######### +two 2 +######### +(1, 2, 3, 4, 5, 6, 7) +(1, 3, 5, 7) +four 4 +one 1 +three 3 +two 2 +######### +one 1 +three 3 +######### +1 +2 +4 +8 +16 diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run.test index bf87d2d080d9..d0b66920658d 100644 --- a/mypyc/test-data/run.test +++ b/mypyc/test-data/run.test @@ -208,284 +208,6 @@ enter! crash exit! a ohno caught -[case testGenericEquality] -def eq(a: object, b: object) -> bool: - if a == b: - return True - else: - return False -def ne(a: object, b: object) -> bool: - if a != b: - return True - else: - return False -def f(o: object) -> bool: - if [1, 2] == o: - return True - else: - return False -[file driver.py] -from native import eq, ne, f -assert eq('xz', 'x' + 'z') -assert not eq('x', 'y') -assert not ne('xz', 'x' + 'z') -assert ne('x', 'y') -assert f([1, 2]) -assert not f([2, 2]) -assert not f(1) - -[case testGenericBinaryOps] -from typing import Any -def add(x: Any, y: Any) -> Any: - return x + y -def subtract(x: Any, y: Any) -> Any: - return x - y -def multiply(x: Any, y: Any) -> Any: - return x * y -def floor_div(x: Any, y: Any) -> Any: - return x // y -def true_div(x: Any, y: Any) -> Any: - return x / y -def remainder(x: Any, y: Any) -> Any: - return x % y -def power(x: Any, y: Any) -> Any: - return x ** y -def lshift(x: Any, y: Any) -> Any: - return x << y -def rshift(x: Any, y: Any) -> Any: - return x >> y -def num_and(x: Any, y: Any) -> Any: - return x & y -def num_xor(x: Any, y: Any) -> Any: - return x ^ y -def num_or(x: Any, y: Any) -> Any: - return x | y -def lt(x: Any, y: Any) -> Any: - if x < y: - return True - else: - return False -def le(x: Any, y: Any) -> Any: - if x <= y: - return True - else: - return False -def gt(x: Any, y: Any) -> Any: - if x > y: - return True - else: - return False -def ge(x: Any, y: Any) -> Any: - if x >= y: - return True - else: - return False -def contains(x: Any, y: Any) -> Any: - if x in y: - return True - else: - return False -def identity(x: Any, y: Any) -> Any: - if x is y: - return True - else: - return False -def disidentity(x: Any, y: Any) -> Any: - if x is not y: - return True - else: - return False -def not_eq_cond(a: Any, b: Any) -> bool: - if not (a == b): - return True - else: - return False -def eq2(a: Any, b: Any) -> bool: - return a == b -def slice1(x: Any) -> Any: - return x[:] -def slice2(x: Any, y: Any) -> Any: - return x[y:] -def slice3(x: Any, y: Any) -> Any: - return x[:y] -def slice4(x: Any, y: Any, z: Any) -> Any: - return x[y:z] -def slice5(x: Any, y: Any, z: Any, zz: Any) -> Any: - return x[y:z:zz] -[file driver.py] -from native import * -assert add(5, 6) == 11 -assert add('x', 'y') == 'xy' -assert subtract(8, 3) == 5 -assert multiply(8, 3) == 24 -assert floor_div(8, 3) == 2 -assert true_div(7, 2) == 3.5 -assert remainder(11, 4) == 3 -assert remainder('%.3d', 5) == '005' -assert remainder('%d-%s', (5, 'xy')) == '5-xy' -assert power(3, 4) == 81 -assert lshift(5, 3) == 40 -assert rshift(41, 3) == 5 -assert num_and(99, 56) == 32 -assert num_xor(99, 56) == 91 -assert num_or(99, 56) == 123 -assert lt('a', 'b') -assert not lt('a', 'a') -assert not lt('b', 'a') -assert not gt('a', 'b') -assert not gt('a', 'a') -assert gt('b', 'a') -assert le('a', 'b') -assert le('a', 'a') -assert not le('b', 'a') -assert not ge('a', 'b') -assert ge('a', 'a') -assert ge('b', 'a') -assert contains('x', 'axb') -assert not contains('X', 'axb') -assert contains('x', {'x', 'y'}) -a = [1, 3, 5] -assert slice1(a) == a -assert slice1(a) is not a -assert slice2(a, 1) == [3, 5] -assert slice3(a, -1) == [1, 3] -assert slice4(a, 1, -1) == [3] -assert slice5(a, 2, 0, -1) == [5, 3] -o1, o2 = object(), object() -assert identity(o1, o1) -assert not identity(o1, o2) -assert not disidentity(o1, o1) -assert disidentity(o1, o2) -assert eq2('xz', 'x' + 'z') -assert not eq2('x', 'y') -assert not not_eq_cond('xz', 'x' + 'z') -assert not_eq_cond('x', 'y') - -[case testGenericMiscOps] -from typing import Any -def neg(x: Any) -> Any: - return -x -def pos(x: Any) -> Any: - return +x -def invert(x: Any) -> Any: - return ~x -def get_item(o: Any, k: Any) -> Any: - return o[k] -def set_item(o: Any, k: Any, v: Any) -> Any: - o[k] = v -[file driver.py] -from native import * -assert neg(6) == -6 -assert pos(6) == 6 -assert invert(6) == -7 -d = {'x': 5} -assert get_item(d, 'x') == 5 -set_item(d, 'y', 6) -assert d['y'] == 6 - -[case testAnyAttributeAndMethodAccess] -from typing import Any, List -class C: - a: int - def m(self, x: int, a: List[int]) -> int: - return self.a + x + a[0] -def get_a(x: Any) -> Any: - return x.a -def set_a(x: Any, y: Any) -> None: - x.a = y -def call_m(x: Any) -> Any: - return x.m(1, [3]) -[file driver.py] -from native import C, get_a, set_a, call_m -class D: - def m(self, x, a): - return self.a + x + a[0] - -c = C() -c.a = 6 -d = D() -d.a = 2 -assert get_a(c) == 6 -assert get_a(d) == 2 -assert call_m(c) == 10 -assert call_m(d) == 6 -set_a(c, 5) -assert c.a == 5 -set_a(d, 4) -assert d.a == 4 -try: - get_a(object()) -except AttributeError: - pass -else: - assert False -try: - call_m(object()) -except AttributeError: - pass -else: - assert False -try: - set_a(object(), 5) -except AttributeError: - pass -else: - assert False - -[case testFloat] -def assign_and_return_float_sum() -> float: - f1 = 1.0 - f2 = 2.0 - f3 = 3.0 - return f1 * f2 + f3 - -def from_int(i: int) -> float: - return float(i) - -def to_int(x: float) -> int: - return int(x) - -def get_complex() -> complex: - return 5.0j + 3.0 - -[file driver.py] -from native import assign_and_return_float_sum, from_int, to_int, get_complex -sum = 0.0 -for i in range(10): - sum += assign_and_return_float_sum() -assert sum == 50.0 - -assert str(from_int(10)) == '10.0' -assert str(to_int(3.14)) == '3' -assert str(to_int(3)) == '3' -assert get_complex() == 3+5j - -[case testBytes] -def f(x: bytes) -> bytes: - return x - -def concat(a: bytes, b: bytes) -> bytes: - return a + b - -def eq(a: bytes, b: bytes) -> bool: - return a == b - -def neq(a: bytes, b: bytes) -> bool: - return a != b - -def join() -> bytes: - seq = (b'1', b'"', b'\xf0') - return b'\x07'.join(seq) -[file driver.py] -from native import f, concat, eq, neq, join -assert f(b'123') == b'123' -assert f(b'\x07 \x0b " \t \x7f \xf0') == b'\x07 \x0b " \t \x7f \xf0' -assert concat(b'123', b'456') == b'123456' -assert eq(b'123', b'123') -assert not eq(b'123', b'1234') -assert neq(b'123', b'1234') -assert join() == b'1\x07"\x07\xf0' - [case testDisplays] from typing import List, Set, Tuple, Sequence, Dict, Any @@ -848,123 +570,6 @@ for a in sorted(s): 9 7 63 9 8 72 -[case testDel] -from typing import List -from testutil import assertRaises - -def printDict(dict) -> None: - l = list(dict.keys()) # type: List[str] - l.sort() - for key in l: - print(key, dict[key]) - print("#########") - -def delList() -> None: - l = [1, 2, 3] - print(tuple(l)) - del l[1] - print(tuple(l)) - -def delDict() -> None: - d = {"one":1, "two":2} - printDict(d) - del d["one"] - printDict(d) - -def delListMultiple() -> None: - l = [1, 2, 3, 4, 5, 6, 7] - print(tuple(l)) - del l[1], l[2], l[3] - print(tuple(l)) - -def delDictMultiple() -> None: - d = {"one":1, "two":2, "three":3, "four":4} - printDict(d) - del d["two"], d["four"] - printDict(d) - -class Dummy(): - def __init__(self, x: int, y: int) -> None: - self.x = x - self.y = y - -def delAttribute() -> None: - dummy = Dummy(1, 2) - del dummy.x - with assertRaises(AttributeError): - dummy.x - -def delAttributeMultiple() -> None: - dummy = Dummy(1, 2) - del dummy.x, dummy.y - with assertRaises(AttributeError): - dummy.x - with assertRaises(AttributeError): - dummy.y - -def delLocal(b: bool) -> int: - dummy = 10 - if b: - del dummy - return dummy - -def delLocalLoop() -> None: - # Try deleting a local in a loop to make sure the control flow analysis works - dummy = 1 - for i in range(10): - print(dummy) - dummy *= 2 - if i == 4: - del dummy - -global_var = 10 -del global_var - -[file driver.py] -from native import ( - delList, delDict, delListMultiple, delDictMultiple, delAttribute, - delAttributeMultiple, delLocal, delLocalLoop, -) -import native -from testutil import assertRaises - -delList() -delDict() -delListMultiple() -delDictMultiple() -delAttribute() -delAttributeMultiple() -with assertRaises(AttributeError): - native.global_var -with assertRaises(NameError, "local variable 'dummy' referenced before assignment"): - delLocal(True) -assert delLocal(False) == 10 -with assertRaises(NameError, "local variable 'dummy' referenced before assignment"): - delLocalLoop() -[out] -(1, 2, 3) -(1, 3) -one 1 -two 2 -######### -two 2 -######### -(1, 2, 3, 4, 5, 6, 7) -(1, 3, 5, 7) -four 4 -one 1 -three 3 -two 2 -######### -one 1 -three 3 -######### -1 -2 -4 -8 -16 - [case testDunders] from typing import Any class Item: diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index 486ab582bf4a..ad828fdc6d81 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -38,6 +38,7 @@ 'run-lists.test', 'run-dicts.test', 'run-sets.test', + 'run-primitives.test', 'run-loops.test', 'run-exceptions.test', 'run-imports.test', From a1bb8c45cd9ff0a55ffee503cf9e1fe91a811c76 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 4 Jul 2020 21:37:22 +0100 Subject: [PATCH 13/14] Rename run.test -> run-misc.test --- mypyc/test-data/{run.test => run-misc.test} | 0 mypyc/test/test_run.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename mypyc/test-data/{run.test => run-misc.test} (100%) diff --git a/mypyc/test-data/run.test b/mypyc/test-data/run-misc.test similarity index 100% rename from mypyc/test-data/run.test rename to mypyc/test-data/run-misc.test diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index ad828fdc6d81..ee9cdf176af9 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -30,7 +30,7 @@ from mypyc.test.test_serialization import check_serialization_roundtrip files = [ - 'run.test', + 'run-misc.test', 'run-functions.test', 'run-integers.test', 'run-strings.test', From 8b8b7745f604b0f2f4feeb5cc63c198c5de1b861 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sat, 11 Jul 2020 12:06:16 +0100 Subject: [PATCH 14/14] Minor updates --- mypyc/test-data/run-functions.test | 1 - mypyc/test-data/run-loops.test | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mypyc/test-data/run-functions.test b/mypyc/test-data/run-functions.test index 7f192d8cf7e2..5dd5face6b0e 100644 --- a/mypyc/test-data/run-functions.test +++ b/mypyc/test-data/run-functions.test @@ -280,7 +280,6 @@ assert A(3).outer(4) == 12 assert toplevel_lambda(5) == 35 - [case testNestedFunctions2] from typing import Callable diff --git a/mypyc/test-data/run-loops.test b/mypyc/test-data/run-loops.test index 933d4a3f8311..b83853bc6d16 100644 --- a/mypyc/test-data/run-loops.test +++ b/mypyc/test-data/run-loops.test @@ -1,4 +1,4 @@ -# Test cases for for and while loops (compile and run) +# Test cases for "for" and "while" loops (compile and run) [case testFor] from typing import List, Tuple