| [case testEmptyClass] |
| class Empty: pass |
| |
| def f(e: Empty) -> Empty: |
| return e |
| [file driver.py] |
| from native import Empty, f |
| |
| print(isinstance(Empty, type)) |
| print(Empty) |
| print(str(Empty())[:20]) |
| |
| e = Empty() |
| print(f(e) is e) |
| [out] |
| True |
| <class 'native.Empty'> |
| <native.Empty object |
| True |
| |
| [case testClassWithFields] |
| class C: |
| x: int |
| y: int |
| z: 'D' |
| class D: |
| pass |
| [file driver.py] |
| from native import C |
| from testutil import assertRaises |
| |
| c = C() |
| assert not hasattr(c, 'x') |
| assert not hasattr(c, 'y') |
| c.x = 1 |
| c.y = 2 |
| print(c.x) |
| print(c.y) |
| c.x = 10**30 |
| print(c.x) |
| c.x = 10**30+1 |
| print(c.x) |
| assert hasattr(c, 'x') |
| assert hasattr(c, 'y') |
| assert not hasattr(c, 'z') |
| with assertRaises(AttributeError, "'C' object attribute 'x' cannot be deleted"): |
| del c.x |
| assert hasattr(c, 'x') |
| assert hasattr(c, 'y') |
| with assertRaises(AttributeError, "'C' object attribute 'y' cannot be deleted"): |
| del c.y |
| assert hasattr(c, 'y') |
| c.x = 10**30+2 |
| print(c.x) |
| assert hasattr(c, 'x') |
| [out] |
| 1 |
| 2 |
| 1000000000000000000000000000000 |
| 1000000000000000000000000000001 |
| 1000000000000000000000000000002 |
| |
| [case testClassWithDeletableAttributes] |
| from typing import Any, cast |
| from testutil import assertRaises |
| |
| class C: |
| __deletable__ = ['x', 'y'] |
| x: int |
| y: int |
| z: int |
| |
| def test_delete() -> None: |
| c = C() |
| c.x = 1 |
| c.y = 2 |
| c.z = 3 |
| del c.x |
| del c.y |
| assert c.z == 3 |
| with assertRaises(AttributeError, "attribute 'x' of 'C' undefined"): |
| c.x |
| with assertRaises(AttributeError, "attribute 'y' of 'C' undefined"): |
| c.y |
| |
| def test_delete_any() -> None: |
| c: Any = C() |
| c.x = 1 |
| c.y = 2 |
| c.z = 3 |
| del c.x |
| del c.y |
| with assertRaises(AttributeError, "'C' object attribute 'z' cannot be deleted"): |
| del c.z |
| assert c.z == 3 |
| with assertRaises(AttributeError): |
| c.x |
| with assertRaises(AttributeError): |
| c.y |
| |
| class Base: |
| __deletable__ = ['a'] |
| a: int |
| b: int |
| |
| class Deriv(Base): |
| __deletable__ = ('c',) |
| c: str |
| d: str |
| |
| def test_delete_with_inheritance() -> None: |
| d = Deriv() |
| d.a = 0 |
| d.b = 1 |
| d.c = 'X' |
| d.d = 'Y' |
| del d.a |
| with assertRaises(AttributeError): |
| d.a |
| del d.c |
| with assertRaises(AttributeError): |
| d.c |
| assert d.b == 1 |
| assert d.d == 'Y' |
| |
| def test_delete_with_inheritance_any() -> None: |
| d: Any = Deriv() |
| d.a = 0 |
| d.b = 1 |
| d.c = 'X' |
| d.d = 'Y' |
| del d.a |
| with assertRaises(AttributeError): |
| d.a |
| del d.c |
| with assertRaises(AttributeError): |
| d.c |
| with assertRaises(AttributeError): |
| del d.b |
| assert d.b == 1 |
| with assertRaises(AttributeError): |
| del d.d |
| assert d.d == 'Y' |
| |
| def decorator(cls): |
| return cls |
| |
| @decorator |
| class NonExt: |
| x: int |
| y: int |
| |
| # No effect in a non-native class |
| __deletable__ = ['x'] |
| |
| def test_non_ext() -> None: |
| n = NonExt() |
| n.x = 2 |
| n.y = 3 |
| del n.x |
| del n.y |
| with assertRaises(AttributeError): |
| n.x |
| with assertRaises(AttributeError): |
| n.y |
| |
| def test_non_ext_any() -> None: |
| n: Any = NonExt() |
| n.x = 2 |
| n.y = 3 |
| del n.x |
| del n.y |
| with assertRaises(AttributeError): |
| n.x |
| with assertRaises(AttributeError): |
| n.y |
| |
| [case testNonExtMisc] |
| from typing import Any, overload |
| |
| def decorator(cls) -> Any: |
| return cls |
| |
| @decorator |
| class C: |
| def __init__(self) -> None: |
| self.c = 3 |
| |
| def get_c(self) -> int: |
| return self.c |
| |
| @decorator |
| class B(C): |
| def __init__(self) -> None: |
| super().__init__() |
| self.b = 2 |
| |
| def get_b(self) -> int: |
| return self.b |
| |
| @decorator |
| class A(B): |
| def __init__(self) -> None: |
| super().__init__() |
| self.a = 1 |
| |
| @classmethod |
| def constant(cls) -> int: |
| return 4 |
| |
| def get_a(self) -> int: |
| return self.a |
| |
| @decorator |
| class Overload: |
| @overload |
| def get(self, index: int) -> int: ... |
| |
| @overload |
| def get(self, index: str) -> str: ... |
| |
| def get(self, index: Any) -> Any: |
| return index |
| |
| def get(c: Overload, s: str) -> str: |
| return c.get(s) |
| |
| @decorator |
| class Var: |
| x = 'xy' |
| |
| def get_class_var() -> str: |
| return Var.x |
| |
| [file driver.py] |
| from native import A, Overload, get, get_class_var |
| a = A() |
| assert a.a == 1 |
| assert a.b == 2 |
| assert a.c == 3 |
| assert a.get_a() == 1 |
| assert a.get_b() == 2 |
| assert a.get_c() == 3 |
| assert A.constant() == 4 |
| |
| o = Overload() |
| assert get(o, "test") == "test" |
| assert o.get(20) == 20 |
| |
| assert get_class_var() == 'xy' |
| |
| [case testEnum] |
| from enum import Enum |
| |
| class TestEnum(Enum): |
| _order_ = "a b" |
| a : int = 1 |
| b : int = 2 |
| |
| @classmethod |
| def test(cls) -> int: |
| return 3 |
| |
| assert TestEnum.test() == 3 |
| |
| [file other.py] |
| # Force a multi-module test to make sure we can compile multi-file with |
| # non-extension classes |
| |
| [file driver.py] |
| import sys |
| # "_order_" isn't supported in 3.5 |
| if sys.version_info[:2] > (3, 5): |
| from native import TestEnum |
| assert TestEnum.a.name == 'a' |
| assert TestEnum.a.value == 1 |
| assert TestEnum.b.name == 'b' |
| assert TestEnum.b.value == 2 |
| |
| [case testGetAttribute] |
| class C: |
| x: int |
| y: int |
| |
| def getx(c: C) -> int: |
| return c.x |
| |
| def gety(c: C) -> int: |
| return c.y |
| [file driver.py] |
| from native import C, getx, gety |
| c = C() |
| c.x = 10**30 |
| c.y = 10**30 + 1 |
| print(getx(c)) |
| print(gety(c)) |
| [out] |
| 1000000000000000000000000000000 |
| 1000000000000000000000000000001 |
| |
| [case testSetAttribute] |
| class C: |
| x: int |
| y: int |
| |
| def setx(c: C, v: int) -> None: |
| c.x = v |
| |
| def sety(c: C, v: int) -> None: |
| c.y = v |
| [file driver.py] |
| from native import C, setx, sety |
| c = C() |
| setx(c, 10**30) |
| sety(c, 10**30 + 1) |
| print(c.x) |
| print(c.y) |
| setx(c, 4) |
| sety(c, 5) |
| print(c.x, c.y) |
| setx(c, 10**30 + 2) |
| sety(c, 10**30 + 3) |
| print(c.x) |
| print(c.y) |
| [out] |
| 1000000000000000000000000000000 |
| 1000000000000000000000000000001 |
| 4 5 |
| 1000000000000000000000000000002 |
| 1000000000000000000000000000003 |
| |
| [case testAttributeTypes] |
| from typing import List, Tuple |
| class C: |
| a: List[int] |
| b: bool |
| c: C |
| d: object |
| e: int |
| |
| def setattrs(o: C, a: List[int], b: bool, c: C) -> None: |
| o.a = a |
| o.b = b |
| o.c = c |
| |
| def getattrs(o: C) -> Tuple[List[int], bool, C]: |
| return o.a, o.b, o.c |
| [file driver.py] |
| from native import C, setattrs, getattrs |
| from testutil import assertRaises |
| |
| c1 = C() |
| c2 = C() |
| aa = [2] |
| setattrs(c1, aa, True, c2) |
| a, b, c = getattrs(c1) |
| assert a is aa |
| assert b is True |
| assert c is c2 |
| |
| o = object() |
| c1.d = o |
| assert c1.d is o |
| |
| c3 = C() |
| with assertRaises(AttributeError, "attribute 'a' of 'C' undefined"): |
| c3.a |
| with assertRaises(AttributeError, "attribute 'b' of 'C' undefined"): |
| c3.b |
| with assertRaises(AttributeError, "attribute 'c' of 'C' undefined"): |
| c3.c |
| with assertRaises(AttributeError, "attribute 'd' of 'C' undefined"): |
| c3.d |
| with assertRaises(AttributeError, "attribute 'e' of 'C' undefined"): |
| c3.e |
| |
| [case testInitMethodWithMissingNoneReturnAnnotation] |
| class C: |
| def __init__(self): |
| self.x = 42 |
| [file driver.py] |
| from native import C |
| c = C() |
| assert c is not None |
| assert c.x == 42 |
| |
| [case testConstructClassWithDefaultConstructor] |
| class C: |
| a: int |
| b: int |
| |
| def f() -> C: |
| c = C() |
| c.a = 13 |
| return c |
| [file driver.py] |
| from native import f, C |
| c = f() |
| assert c.a == 13 |
| assert type(c) == C |
| assert not hasattr(c, 'b') |
| |
| [case testCastUserClass] |
| from typing import List |
| |
| class C: |
| x: int |
| |
| def f(a: List[C]) -> C: |
| return a[0] |
| [file driver.py] |
| from native import f, C |
| c = C() |
| assert f([c]) is c |
| |
| [case testClass1] |
| class A: |
| def __init__(self, x: int) -> None: |
| self.x = x |
| def foo(self) -> int: |
| return self.x+1 |
| def foo() -> int: |
| a = A(20) |
| return a.foo() |
| [file driver.py] |
| from native import A, foo |
| a = A(10) |
| assert a.foo() == 11 |
| assert foo() == 21 |
| |
| [case testGenericClass] |
| from typing import TypeVar, Generic, Sequence |
| T = TypeVar('T') |
| class C(Generic[T]): |
| x: T |
| def __init__(self, x: T) -> None: |
| self.x = x |
| def get(self) -> T: |
| return self.x |
| def set(self, y: T) -> None: |
| self.x = y |
| |
| # Test subclassing generic classes both with and without a generic param |
| class A(Sequence[int]): |
| pass |
| class B(Sequence[T]): |
| pass |
| |
| def f(c: C[int]) -> int: |
| y = c.get() |
| d = C[int](2) |
| c.set(c.get() + 1 + d.get()) |
| c.x = c.x + 2 |
| return c.x |
| |
| [file driver.py] |
| from native import C, f |
| c = C(6) |
| assert f(c) == 11 |
| c.x = 'x' |
| assert c.x == 'x' |
| c.set([1]) |
| assert c.x == [1] |
| assert c.get() == [1] |
| |
| [case testSubclass1] |
| from typing import Tuple |
| |
| class A: |
| def __init__(self) -> None: |
| self.x = 10 |
| def hi(self, suffix: str) -> str: |
| return str(self.x) + suffix |
| class B(A): |
| def __init__(self) -> None: |
| self.x = 20 |
| self.y = 'world' |
| def hi(self, suffix: str) -> str: |
| return 'hello ' + str(self.y) + suffix |
| |
| def use_a(x: A) -> Tuple[int, str]: |
| return (x.x, x.hi('')) |
| def use_b(x: B) -> str: |
| return x.hi('') |
| |
| [file driver.py] |
| from native import A, B, use_a, use_b |
| a = A() |
| b = B() |
| assert use_a(a) == (10, '10') |
| assert use_a(b) == (20, 'hello world') |
| assert a.x == 10 |
| assert b.x == 20 |
| assert b.y == 'world' |
| assert a.hi('!') == '10!' |
| assert b.hi('!') == 'hello world!' |
| assert use_b(b) == 'hello world' |
| |
| [case testSubclassSpecialize1] |
| class A: |
| def foo(self, x: int) -> object: |
| print('A') |
| return str(x) |
| def bar(self, x: int) -> None: |
| print(x + 1) |
| class B(A): |
| def foo(self, x: object) -> int: |
| print('B') |
| return id(x) |
| def bar(self, x: object) -> None: |
| print(x) |
| |
| def use_a(x: A, y: int) -> object: |
| x.bar(10) |
| return x.foo(y) |
| |
| def use_b(x: B, y: object) -> int: |
| return x.foo(y) |
| |
| [file driver.py] |
| from native import A, B, use_a, use_b |
| a = A() |
| b = B() |
| o = object() |
| i = 10 |
| assert a.foo(10) == '10' |
| assert b.foo(o) == id(o) |
| assert use_a(a, 10) == '10' |
| assert use_b(b, o) == id(o) |
| assert use_a(b, i) == id(i) |
| [out] |
| A |
| B |
| 11 |
| A |
| B |
| 10 |
| B |
| |
| [case testSubclassSpecialize2] |
| class A: |
| def foo(self, x: int) -> object: |
| print('A') |
| return str(x) |
| class B(A): |
| def foo(self, x: object) -> object: |
| print('B') |
| return x |
| class C(B): |
| def foo(self, x: object) -> int: |
| print('C') |
| return id(x) |
| |
| def use_a(x: A, y: int) -> object: |
| return x.foo(y) |
| |
| def use_b(x: B, y: object) -> object: |
| return x.foo(y) |
| |
| def use_c(x: C, y: object) -> int: |
| return x.foo(y) |
| |
| [file driver.py] |
| from native import A, B, C, use_a, use_b, use_c |
| a = A() |
| b = B() |
| c = C() |
| o = object() |
| i = 10 |
| assert a.foo(10) == '10' |
| assert b.foo(o) == o |
| assert c.foo(o) == id(o) |
| assert use_a(a, 10) == '10' |
| assert use_a(b, i) is i |
| assert use_a(c, i) == id(i) |
| assert use_b(b, o) == o |
| assert use_b(c, o) == id(o) |
| assert use_c(c, o) == id(o) |
| [out] |
| A |
| B |
| C |
| A |
| B |
| C |
| B |
| C |
| C |
| |
| [case testIsInstance] |
| from typing import Optional |
| class X: pass |
| class A(X): pass |
| class B(A): pass |
| |
| def isa(x: object) -> bool: |
| return isinstance(x, A) |
| def isint(x: object) -> bool: |
| return isinstance(x, int) |
| def isstr(x: object) -> bool: |
| return isinstance(x, str) |
| def islist(x: object) -> bool: |
| return isinstance(x, list) |
| def ist(x: object, t: object) -> bool: # TODO: Second argument should be 'type' |
| return isinstance(x, t) |
| def pointless(x: Optional[X]) -> str: |
| if isinstance(x, A): |
| return str(x) |
| return '' |
| [file driver.py] |
| from native import X, A, B, isa, isint, isstr, islist, ist |
| assert isa(1) == False |
| assert isa(A()) == True |
| assert isa(B()) == True |
| assert isa(X()) == False |
| |
| assert isint(1) == True |
| assert isint('') == False |
| assert isint(A()) == False |
| |
| assert isstr(1) == False |
| assert isstr('') == True |
| |
| assert islist(1) == False |
| assert islist([]) == True |
| |
| assert ist(1, int) == True |
| assert ist(1, str) == False |
| try: |
| ist(1, 2) |
| except TypeError: |
| pass |
| else: |
| assert False |
| |
| [case testSubclassUninitAttr] |
| class X: |
| x: int |
| class A(X): |
| pass |
| [file driver.py] |
| import traceback |
| from native import A |
| try: |
| A().x |
| except AttributeError: |
| traceback.print_exc() |
| [out] |
| Traceback (most recent call last): |
| File "driver.py", line 4, in <module> |
| A().x |
| AttributeError: attribute 'x' of 'X' undefined |
| |
| [case testClassMethods] |
| MYPY = False |
| if MYPY: |
| from typing import ClassVar |
| class C: |
| lurr: 'ClassVar[int]' = 9 |
| @staticmethod |
| def foo(x: int) -> int: return 10 + x |
| @classmethod |
| def bar(cls, x: int) -> int: return cls.lurr + x |
| @staticmethod |
| def baz(x: int, y: int = 10) -> int: return y - x |
| @classmethod |
| def quux(cls, x: int, y: int = 10) -> int: return y - x |
| |
| class D(C): |
| def f(self) -> int: |
| return super().foo(1) + super().bar(2) + super().baz(10) + super().quux(10) |
| |
| def test1() -> int: |
| return C.foo(1) + C.bar(2) + C.baz(10) + C.quux(10) + C.quux(y=10, x=9) |
| def test2() -> int: |
| c = C() |
| return c.foo(1) + c.bar(2) + c.baz(10) |
| [file driver.py] |
| from native import * |
| assert C.foo(10) == 20 |
| assert C.bar(10) == 19 |
| c = C() |
| assert c.foo(10) == 20 |
| assert c.bar(10) == 19 |
| |
| assert test1() == 23 |
| assert test2() == 22 |
| |
| d = D() |
| assert d.f() == 22 |
| |
| [case testSuper] |
| from mypy_extensions import trait |
| from typing import List |
| |
| class A: |
| def __init__(self, x: int) -> None: |
| self.x = x |
| |
| def foo(self, x: int) -> int: |
| return x |
| |
| class B(A): |
| def __init__(self, x: int, y: int) -> None: |
| super().__init__(x) |
| self.y = y |
| |
| def foo(self, x: int) -> int: |
| return super().foo(x+1) |
| |
| class C(B): |
| def __init__(self, x: int, y: int) -> None: |
| super(C, self).__init__(x, y + 1) |
| |
| def foo(self, x: int) -> int: |
| # should go to A, not B |
| return super(B, self).foo(x+1) |
| |
| class X: |
| def __init__(self, x: int) -> None: |
| self.x = x |
| class Y(X): |
| pass |
| class Z(Y): |
| def __init__(self, x: int, y: int) -> None: |
| super().__init__(x) |
| self.y = y |
| |
| @trait |
| class T: |
| def v_int(self, x: int) -> None: pass |
| def v_list(self, x: List[int]) -> None: |
| if x: |
| self.v_int(x[0]) |
| self.v_list(x[1:]) |
| |
| class PrintList(T): |
| def v_int(self, x: int) -> None: |
| print(x) |
| def v_list(self, x: List[int]) -> None: |
| print('yo!') |
| super().v_list(x) |
| |
| [file driver.py] |
| import traceback |
| from native import * |
| b = B(10, 20) |
| assert b.x == 10 and b.y == 20 |
| c = C(10, 20) |
| assert c.x == 10 and c.y == 21 |
| z = Z(10, 20) |
| assert z.x == 10 and z.y == 20 |
| |
| assert c.foo(10) == 11 |
| |
| PrintList().v_list([1,2,3]) |
| [out] |
| yo! |
| 1 |
| yo! |
| 2 |
| yo! |
| 3 |
| yo! |
| |
| [case testSubclassException] |
| class Failure(Exception): |
| def __init__(self, x: int) -> None: |
| self.x = x |
| |
| def foo() -> None: |
| raise Failure(10) |
| |
| def heyo() -> int: |
| try: |
| foo() |
| except Failure as e: |
| return e.x |
| return -1 |
| |
| [file driver.py] |
| from native import foo, heyo, Failure |
| try: |
| foo() |
| except Failure as e: |
| assert str(e) == '10' |
| assert e.x == 10 |
| heyo() |
| |
| [case testSubclassDict] |
| from typing import Dict |
| class WelpDict(Dict[str, int]): |
| def __init__(self) -> None: |
| self.emarhavil = 3 |
| def foo(self) -> int: |
| return self.emarhavil |
| |
| def welp() -> int: |
| x = WelpDict() |
| x['a'] = 10 |
| x['b'] = 15 |
| x.emarhavil = 5 |
| return x['a'] + x['b'] + x.emarhavil + x.foo() |
| |
| [file driver.py] |
| from native import welp |
| assert welp() == 35 |
| |
| [case testSubclassPy] |
| from b import B, V |
| class A(B): |
| def __init__(self, x: int, y: int) -> None: |
| super().__init__(y) |
| self.x = x |
| |
| def foo(self, x: int) -> int: |
| print("hi", x) |
| return x+1 |
| |
| class C(V[int]): |
| def f(self) -> int: return 10 |
| |
| assert isinstance(C(), V) |
| |
| def f(x: A) -> None: |
| print(x.x) |
| print(x.y) |
| print(x.foo(20)) |
| |
| [file b.py] |
| from typing import Generic, TypeVar |
| T = TypeVar('T') |
| |
| class B: |
| def __init__(self, y: int) -> None: |
| self.y = y |
| def foo(self, x: int) -> int: |
| print("parent!") |
| return x + self.y |
| def bar(self) -> None: |
| print("hello!", self.y) |
| |
| class V(Generic[T]): |
| def f(self) -> T: |
| raise Exception('unimplemented') |
| [file driver.py] |
| import native |
| a = native.A(10, 20) |
| a.foo(10) |
| a.bar() |
| native.f(a) |
| [out] |
| hi 10 |
| hello! 20 |
| 10 |
| 20 |
| hi 20 |
| 21 |
| |
| [case testDisallowSubclassFromPy] |
| # We'll want to allow this at some point but right now we need to |
| # disallow it because it doesn't work. |
| class A: |
| pass |
| [file b.py] |
| from native import A |
| |
| # It would be better if we disallowed it at class decl time but it is |
| # really easy to do in __new__ |
| |
| class B(A): |
| pass |
| |
| [file driver.py] |
| from b import B |
| try: |
| B() |
| except TypeError: |
| pass |
| else: |
| assert False, "instantiating was supposed to fail" |
| |
| [case testClassVariable] |
| MYPY = False |
| if MYPY: |
| from typing import ClassVar |
| class A: |
| x = 10 # type: ClassVar[int] |
| |
| def g(x: int) -> None: |
| A.x = 10 |
| def f() -> int: |
| return A.x |
| [file driver.py] |
| from native import A, f |
| assert f() == 10 |
| A.x = 200 |
| assert f() == 200 |
| |
| [case testDefaultVars] |
| from typing import Optional |
| class A: |
| x = 10 |
| w: object = 10 |
| def lol(self) -> None: |
| self.x = 100 |
| |
| LOL = 'lol' |
| class B(A): |
| y = LOL |
| z = None # type: Optional[str] |
| b = True |
| bogus = None # type: int |
| |
| def g() -> None: |
| a = A() |
| assert a.x == 10 |
| a.x = 20 |
| assert a.x == 20 |
| b = B() |
| assert b.x == 10 |
| b.x = 20 |
| assert b.x == 20 |
| assert b.y == 'lol' |
| b.y = 'rofl' |
| assert b.y == 'rofl' |
| assert b.z is None |
| [file driver.py] |
| from native import * |
| g() |
| |
| a = A() |
| assert a.x == 10 |
| a.x = 20 |
| assert a.x == 20 |
| b = B() |
| assert b.x == 10 |
| b.x = 20 |
| assert b.x == 20 |
| assert b.y == 'lol' |
| b.y = 'rofl' |
| assert b.y == 'rofl' |
| assert b.z is None |
| # N.B: this doesn't match cpython |
| assert not hasattr(b, 'bogus') |
| |
| [case testProtocol] |
| from typing_extensions import Protocol |
| |
| class Proto(Protocol): |
| def foo(self, x: int) -> None: |
| pass |
| |
| def bar(self, x: int) -> None: |
| pass |
| |
| class A: |
| def foo(self, x: int) -> None: |
| print("A:", x) |
| |
| def bar(self, *args: int, **kwargs: int) -> None: |
| print("A:", args, kwargs) |
| |
| class B(A, Proto): |
| def foo(self, x: int) -> None: |
| print("B:", x) |
| |
| def bar(self, *args: int, **kwargs: int) -> None: |
| print("B:", args, kwargs) |
| |
| def f(x: Proto) -> None: |
| x.foo(20) |
| x.bar(x=20) |
| |
| [file driver.py] |
| from native import A, B, f |
| |
| f(A()) |
| f(B()) |
| |
| # ... this exploits a bug in glue methods to distinguish whether we |
| # are making a direct call or a pycall... |
| [out] |
| A: 20 |
| A: () {'x': 20} |
| B: 20 |
| B: (20,) {} |
| |
| [case testMethodOverrideDefault1] |
| class A: |
| def foo(self, x: int) -> None: |
| pass |
| class B(A): |
| def foo(self, x: int, y: int = 10) -> None: |
| print(x, y) |
| |
| def a(x: A) -> None: |
| x.foo(1) |
| def b(x: B) -> None: |
| x.foo(2) |
| x.foo(2, 3) |
| |
| [file driver.py] |
| from native import B, a, b |
| a(B()) |
| b(B()) |
| [out] |
| 1 10 |
| 2 10 |
| 2 3 |
| |
| [case testMethodOverrideDefault2] |
| class A: |
| def foo(self, *, x: int = -1) -> None: |
| pass |
| def bar(self, *, x: int = -1, y: int = -1) -> None: |
| pass |
| def baz(self, x: int = -1) -> None: |
| pass |
| class B(A): |
| def foo(self, *, y: int = 0, x: int = 0) -> None: |
| print(x, y) |
| def bar(self, *, y: int = 0, x: int = 0) -> None: |
| print(x, y) |
| def baz(self, x: int = 0, *, y: int = 0) -> None: |
| print(x, y) |
| |
| def a(x: A) -> None: |
| x.foo(x=1) |
| x.bar(x=1, y=2) |
| x.bar(x=2, y=1) |
| x.baz() |
| x.baz(1) |
| x.baz(x=2) |
| |
| [file driver.py] |
| from native import B, a |
| a(B()) |
| [out] |
| 1 0 |
| 1 2 |
| 2 1 |
| 0 0 |
| 1 0 |
| 2 0 |
| |
| [case testMethodOverrideDefault3] |
| class A: |
| @classmethod |
| def foo(cls, *, x: int = 0) -> None: |
| pass |
| @staticmethod |
| def bar(*, x: int = 0) -> None: |
| pass |
| @staticmethod |
| def baz() -> object: |
| pass |
| class B(A): |
| @classmethod |
| def foo(cls, *, y: int = 0, x: int = 0) -> None: |
| print(x, y) |
| print(cls.__name__) # type: ignore |
| @staticmethod |
| def bar(*, y: int = 0, x: int = 0) -> None: |
| print(x, y) |
| @staticmethod |
| def baz() -> int: |
| return 10 |
| |
| # This is just to make sure that this stuff works even when the |
| # methods might be overridden. |
| class C(B): |
| @classmethod |
| def foo(cls, *, y: int = 0, x: int = 0) -> None: |
| pass |
| @staticmethod |
| def bar(*, y: int = 0, x: int = 0) -> None: |
| pass |
| @staticmethod |
| def baz() -> int: |
| return 10 |
| |
| def a(x: A) -> None: |
| x.foo(x=1) |
| x.bar(x=1) |
| print(x.baz()) |
| |
| [file driver.py] |
| from native import B, a |
| a(B()) |
| [out] |
| 1 0 |
| B |
| 1 0 |
| 10 |
| |
| [case testMethodOverrideDefault4] |
| class Foo: |
| def f(self, x: int=20, *, z: int=10) -> None: |
| pass |
| |
| class Bar(Foo): |
| def f(self, *args: int, **kwargs: int) -> None: |
| print("stuff", args, kwargs) |
| |
| z: Foo = Bar() |
| z.f(1, z=50) |
| z.f() |
| |
| [out] |
| stuff (1,) {'z': 50} |
| stuff () {} |
| |
| [case testMethodOverrideDefault5] |
| from testutil import make_python_function |
| from mypy_extensions import mypyc_attr |
| from typing import TypeVar, Any |
| |
| @mypyc_attr(allow_interpreted_subclasses=True) |
| class Foo: |
| def f(self, x: int=20, *, z: int=10) -> None: |
| print("Foo", x, z) |
| |
| @make_python_function |
| def baz_f(self: Any, *args: int, **kwargs: int) -> None: |
| print("Baz", args, kwargs) |
| |
| # Make an "interpreted" subtype of Foo |
| type2: Any = type |
| Bar = type2('Bar', (Foo,), {}) |
| Baz = type2('Baz', (Foo,), {'f': baz_f}) |
| |
| y: Foo = Bar() |
| y.f(1, z=2) |
| y.f() |
| |
| z: Foo = Baz() |
| z.f(1, z=2) |
| z.f() |
| |
| [out] |
| Foo 1 2 |
| Foo 20 10 |
| Baz (1,) {'z': 2} |
| Baz () {} |
| |
| [case testMethodOverrideDefault6] |
| from typing import Optional |
| |
| class Foo: |
| def f(self, x: int=20) -> None: |
| pass |
| |
| class Bar(Foo): |
| def f(self, x: Optional[int]=None) -> None: |
| print(x) |
| |
| z: Foo = Bar() |
| z.f(1) |
| z.f() |
| |
| [out] |
| 1 |
| None |
| |
| [case testMethodOverrideDefault7] |
| from typing import TypeVar, Any |
| |
| class Foo: |
| def f(self, x: int, *args: int, **kwargs: int) -> None: |
| print("Foo", x, args, kwargs) |
| |
| class Bar(Foo): |
| def f(self, *args: int, **kwargs: int) -> None: |
| print("Bar", args, kwargs) |
| |
| z: Foo = Bar() |
| z.f(1, z=2) |
| z.f(1, 2, 3) |
| # z.f(x=5) # Not tested because we (knowingly) do the wrong thing and pass it as positional |
| |
| [out] |
| Bar (1,) {'z': 2} |
| Bar (1, 2, 3) {} |
| --Bar () {'x': 5} |
| |
| [case testMethodOverrideDefault8] |
| from typing import TypeVar, Any |
| |
| class Foo: |
| def f(self, *args: int, **kwargs: int) -> None: |
| print("Foo", args, kwargs) |
| |
| class Bar(Foo): |
| def f(self, x: int = 10, *args: int, **kwargs: int) -> None: |
| print("Bar", x, args, kwargs) |
| |
| z: Foo = Bar() |
| z.f(1, z=2) |
| z.f(1, 2, 3) |
| z.f() |
| |
| [out] |
| Bar 1 () {'z': 2} |
| Bar 1 (2, 3) {} |
| Bar 10 () {} |
| |
| [case testMethodOverrideDefault9] |
| from testutil import make_python_function |
| from mypy_extensions import mypyc_attr |
| from typing import TypeVar, Any |
| |
| @mypyc_attr(allow_interpreted_subclasses=True) |
| class Foo: |
| def f(self, x: int=20, y: int=40) -> None: |
| print("Foo", x, y) |
| |
| # This sort of argument renaming is dodgy and not really sound but we |
| # shouldn't break it when they aren't actually used by name... |
| # (They *ought* to be positional only!) |
| @make_python_function |
| def baz_f(self, a: int=30, y: int=50) -> None: |
| print("Baz", a, y) |
| |
| # Make an "interpreted" subtype of Foo |
| type2: Any = type |
| Baz = type2('Baz', (Foo,), {'f': baz_f}) |
| |
| z: Foo = Baz() |
| z.f() |
| z.f(y=1) |
| z.f(1, 2) |
| # Not tested because we don't (and probably won't) match cpython here |
| # from testutil import assertRaises |
| # with assertRaises(TypeError): |
| # z.f(x=7) |
| |
| [out] |
| Baz 30 50 |
| Baz 30 1 |
| Baz 1 2 |
| |
| [case testOverride] |
| class A: |
| def f(self) -> int: |
| return 0 |
| def g(self) -> int: |
| return 1 |
| |
| class B(A): |
| def g(self) -> int: |
| return 2 |
| |
| class C(B): |
| def f(self) -> int: |
| return 3 |
| |
| def test() -> None: |
| ba: A = B() |
| ca: A = C() |
| assert ba.f() == 0 |
| assert ba.g() == 2 |
| assert ca.f() == 3 |
| assert ca.g() == 2 |
| cc = C() |
| assert cc.f() == 3 |
| assert cc.g() == 2 |
| print('ok') |
| [file driver.py] |
| import native |
| native.test() |
| [out] |
| ok |
| |
| [case testNoMetaclass] |
| from foo import Base |
| |
| class Nothing(Base): # type: ignore |
| pass |
| |
| [file foo.py] |
| from typing import Any |
| class Meta(type): |
| pass |
| |
| class _Base(metaclass=Meta): |
| pass |
| Base = _Base # type: Any |
| |
| [file driver.py] |
| try: |
| import native |
| except TypeError as e: |
| assert(str(e) == "mypyc classes can't have a metaclass") |
| |
| [case testMetaclass] |
| from meta import Meta |
| import six |
| |
| class Nothing1(metaclass=Meta): |
| pass |
| |
| def ident(x): return x |
| |
| @ident |
| class Test: |
| pass |
| |
| class Nothing2(six.with_metaclass(Meta, Test)): |
| pass |
| |
| @six.add_metaclass(Meta) |
| class Nothing3: |
| pass |
| |
| [file meta.py] |
| from typing import Any |
| class Meta(type): |
| def __new__(mcs, name, bases, dct): |
| dct['X'] = 10 |
| return super().__new__(mcs, name, bases, dct) |
| |
| |
| [file driver.py] |
| from native import Nothing1, Nothing2, Nothing3 |
| assert Nothing1.X == 10 |
| assert Nothing2.X == 10 |
| assert Nothing3.X == 10 |
| |
| [case testPickling] |
| from mypy_extensions import trait, mypyc_attr |
| from typing import Any, TypeVar, Generic |
| |
| def dec(x: Any) -> Any: |
| return x |
| |
| @mypyc_attr(allow_interpreted_subclasses=True) |
| class A: |
| x: int |
| y: str |
| |
| @mypyc_attr(allow_interpreted_subclasses=True) |
| class B(A): |
| z: bool |
| |
| def __init__(self, x: int, y: str, z: bool) -> None: |
| self.x = x |
| self.y = y |
| self.z = z |
| |
| @trait |
| class T: |
| a: str |
| |
| class C(B, T): |
| w: object |
| |
| # property shouldn't go in |
| @property |
| def foo(self) -> int: |
| return 0 |
| |
| @dec |
| class D: |
| x: int |
| |
| class E(D): |
| y: int |
| |
| |
| U = TypeVar('U') |
| |
| class F(Generic[U]): |
| y: int |
| |
| class G(F[int]): |
| pass |
| |
| [file driver.py] |
| from native import A, B, T, C, D, E, F, G |
| |
| import copy |
| import pickle |
| |
| assert A.__mypyc_attrs__ == ('x', 'y') |
| assert B.__mypyc_attrs__ == ('z', 'x', 'y') |
| assert T.__mypyc_attrs__ == ('a',) |
| assert C.__mypyc_attrs__ == ('w', 'z', 'x', 'y', 'a') |
| assert not hasattr(D, '__mypyc_attrs__') |
| assert E.__mypyc_attrs__ == ('y', '__dict__') |
| assert F.__mypyc_attrs__ == ('y', '__dict__') |
| assert G.__mypyc_attrs__ == ('y', '__dict__') |
| |
| b = B(10, '20', False) |
| assert b.__getstate__() == {'z': False, 'x': 10, 'y': '20'} |
| b2 = copy.copy(b) |
| assert b is not b2 and b.y == b2.y |
| |
| b3 = pickle.loads(pickle.dumps(b)) |
| assert b is not b3 and b.y == b3.y |
| |
| e = E() |
| e.x = 10 |
| e.y = 20 |
| |
| assert e.__getstate__() == {'y': 20, '__dict__': {'x': 10}} |
| e2 = pickle.loads(pickle.dumps(e)) |
| assert e is not e2 and e.x == e2.x and e.y == e2.y |
| |
| |
| [case testInterpretedParentInit] |
| from interp import C |
| from typing import TypeVar |
| |
| T = TypeVar('T') |
| |
| def dec(x: T) -> T: |
| return x |
| |
| @dec |
| class A: |
| def __init__(self, x: int) -> None: |
| self.x = x |
| |
| class B(A): |
| s = 'test' |
| |
| def b(x: int) -> B: return B(x) |
| |
| class D(C): |
| s = 'test' |
| |
| def d(x: int) -> D: return D(x) |
| |
| |
| [file interp.py] |
| class C: |
| def __init__(self, x: int) -> None: |
| self.x = x |
| |
| [file driver.py] |
| from native import b, d, B, D |
| |
| def test(f, v): |
| x = f(v) |
| assert x.x == v |
| assert x.s == 'test' |
| |
| test(b, 20) |
| test(d, 30) |
| test(B, -1) |
| test(D, -2) |
| |
| [case testInterpretedInherit] |
| from typing import TypeVar, Any, overload |
| from mypy_extensions import mypyc_attr, trait |
| |
| T = TypeVar('T') |
| def dec(x: T) -> T: return x |
| |
| @mypyc_attr(allow_interpreted_subclasses=True) |
| class Top: |
| def spam(self) -> str: |
| return "grandparent" |
| |
| @mypyc_attr(allow_interpreted_subclasses=True) |
| @trait |
| class Trait: |
| def trait_method(self) -> str: |
| return "trait" |
| |
| @mypyc_attr(allow_interpreted_subclasses=True) |
| class Foo(Top, Trait): |
| def __init__(self, x: int) -> None: |
| self.x = x |
| |
| def foo(self) -> str: |
| return "parent foo: " + self.bar(self.x) |
| |
| def bar(self, x: int) -> str: |
| return "parent bar: {}".format(x + self.x) |
| |
| @dec |
| def decorated(self) -> str: |
| return "decorated parent" |
| |
| @property |
| def read_property(self) -> str: |
| return "parent prop" |
| |
| @overload |
| def overloaded(self, index: int) -> int: ... |
| |
| @overload |
| def overloaded(self, index: str) -> str: ... |
| |
| def overloaded(self, index: Any) -> Any: |
| return index |
| |
| def foo(x: Foo) -> str: |
| return x.foo() |
| |
| def bar(x: Foo, y: int) -> str: |
| return x.bar(y) |
| |
| def spam(x: Top) -> str: |
| return x.spam() |
| |
| def decorated(x: Foo) -> str: |
| return x.decorated() |
| |
| def prop(x: Foo) -> str: |
| return x.read_property |
| |
| def trait_method(x: Trait) -> str: |
| return x.trait_method() |
| |
| def overloaded(x: Foo, s: str) -> str: |
| return x.overloaded(s) |
| |
| [file interp.py] |
| from typing import Any |
| from native import Foo |
| |
| class Bar(Foo): |
| def bar(self, x: int) -> str: |
| return "child bar: {}".format(x + self.x) |
| |
| def spam(self) -> str: |
| assert super().spam() == "grandparent" |
| return "child" |
| |
| @property |
| def read_property(self) -> str: |
| return "child prop" |
| |
| def decorated(self) -> str: |
| return "decorated child" |
| |
| def trait_method(self) -> str: |
| return "child" |
| |
| def overloaded(self, index: Any) -> Any: |
| return index + index |
| |
| |
| class InterpBase: |
| def eggs(self) -> str: |
| return "eggs" |
| |
| class Baz(InterpBase, Bar): |
| def __init__(self) -> None: |
| super().__init__(1000) |
| self.z = self.read_property |
| |
| [file driver.py] |
| from native import Foo, foo, bar, spam, decorated, overloaded, prop, trait_method |
| from interp import Bar, Baz |
| from unittest.mock import patch |
| from testutil import assertRaises |
| |
| x = Foo(10) |
| y = Bar(20) |
| z = Baz() |
| |
| assert isinstance(y, Bar) |
| assert y.x == 20 |
| assert y.bar(10) == "child bar: 30" |
| assert y.foo() == "parent foo: child bar: 40" |
| assert foo(y) == "parent foo: child bar: 40" |
| assert bar(y, 30) == "child bar: 50" |
| y.x = 30 |
| assert bar(y, 30) == "child bar: 60" |
| |
| assert spam(y) == "child" |
| assert y.read_property == "child prop" |
| assert prop(x) == "parent prop" |
| assert prop(y) == "child prop" |
| assert y.decorated() == "decorated child" |
| assert decorated(y) == "decorated child" |
| assert y.overloaded("test") == "testtest" |
| assert overloaded(y, "test") == "testtest" |
| |
| assert y.trait_method() == "child" |
| assert trait_method(y) == "child" |
| |
| assert z.bar(10) == "child bar: 1010" |
| assert bar(z, 10) == "child bar: 1010" |
| assert z.z == "child prop" |
| assert z.eggs() == "eggs" |
| |
| with patch("interp.Bar.spam", lambda self: "monkey patched"): |
| assert y.spam() == "monkey patched" |
| spam(y) == "monkey patched" |
| |
| with patch("interp.Bar.spam", lambda self: 20): |
| assert y.spam() == 20 |
| with assertRaises(TypeError, "str object expected; got int"): |
| spam(y) |
| |
| 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.fahrenheit - 32.0) / 9.0 |
| |
| def __init__(self, fahrenheit: float) -> None: |
| self.fahrenheit = fahrenheit |
| |
| def print_temp(self) -> None: |
| print("F:", self.fahrenheit, "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 <module> |
| 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 |
| [out version>=3.11] |
| Traceback (most recent call last): |
| File "driver.py", line 5, in <module> |
| 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 |
| |
| # Inherits 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 |
| |
| # No inheritance, just plain setter/getter |
| class G: |
| def __init__(self, x: int) -> None: |
| self._x = x |
| |
| @property |
| def x(self) -> int: |
| return self._x |
| |
| @x.setter |
| def x(self, x: int) -> None: |
| self._x = x |
| |
| class H: |
| def __init__(self, g: G) -> None: |
| self.g = g |
| self.g.x = 5 # Should not be treated as initialization |
| |
| [file other.py] |
| # Run in both interpreted and compiled mode |
| |
| from native import A, B, C, D, E, F, G |
| |
| 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 |
| g = G(4) |
| g.x = 20 |
| assert g.x == 20 |
| |
| [file driver.py] |
| # Run the tests in both interpreted and compiled mode |
| 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() |
| |
| [case testCopyAlwaysDefinedAttributes] |
| import copy |
| from typing import Union |
| |
| class A: pass |
| |
| class C: |
| def __init__(self, n: int = 0) -> None: |
| self.n = n |
| self.s = "" |
| self.t = ("", 0) |
| self.u: Union[str, bytes] = '' |
| self.a = A() |
| |
| def test_copy() -> None: |
| c1 = C() |
| c1.n = 1 |
| c1.s = "x" |
| c2 = copy.copy(c1) |
| assert c2.n == 1 |
| assert c2.s == "x" |
| assert c2.t == ("", 0) |
| assert c2.u == '' |
| assert c2.a is c1.a |
| |
| [case testNonNativeCallsToDunderNewAndInit] |
| from typing import Any |
| from testutil import assertRaises |
| |
| count_c = 0 |
| |
| class C: |
| def __init__(self) -> None: |
| self.x = 'a' # Always defined attribute |
| global count_c |
| count_c += 1 |
| |
| def get(self) -> str: |
| return self.x |
| |
| def test_no_init_args() -> None: |
| global count_c |
| count_c = 0 |
| |
| # Use Any to get non-native semantics |
| cls: Any = C |
| # __new__ implicitly calls __init__ for native classes |
| obj = cls.__new__(cls) |
| assert obj.get() == 'a' |
| assert count_c == 1 |
| # Make sure we don't call __init__ twice |
| obj2 = cls() |
| assert obj2.get() == 'a' |
| assert count_c == 2 |
| |
| count_d = 0 |
| |
| class D: |
| def __init__(self, x: str) -> None: |
| self.x = x # Always defined attribute |
| global count_d |
| count_d += 1 |
| |
| def get(self) -> str: |
| return self.x |
| |
| def test_init_arg() -> None: |
| global count_d |
| count_d = 0 |
| |
| # Use Any to get non-native semantics |
| cls: Any = D |
| # __new__ implicitly calls __init__ for native classes |
| obj = cls.__new__(cls, 'abc') |
| assert obj.get() == 'abc' |
| assert count_d == 1 |
| # Make sure we don't call __init__ twice |
| obj2 = cls('x') |
| assert obj2.get() == 'x' |
| assert count_d == 2 |
| # Keyword args should work |
| obj = cls.__new__(cls, x='abc') |
| assert obj.get() == 'abc' |
| assert count_d == 3 |
| |
| def test_invalid_init_args() -> None: |
| # Use Any to get non-native semantics |
| cls: Any = D |
| with assertRaises(TypeError): |
| cls() |
| with assertRaises(TypeError): |
| cls(y='x') |
| with assertRaises(TypeError): |
| cls(1) |
| |
| [case testTryDeletingAlwaysDefinedAttribute] |
| from typing import Any |
| from testutil import assertRaises |
| |
| class C: |
| def __init__(self) -> None: |
| self.x = 0 |
| |
| class D(C): |
| pass |
| |
| def test_try_deleting_always_defined_attr() -> None: |
| c: Any = C() |
| with assertRaises(AttributeError): |
| del c.x |
| d: Any = D() |
| with assertRaises(AttributeError): |
| del d.x |
| |
| [case testAlwaysDefinedAttributeAndAllowInterpretedSubclasses] |
| from mypy_extensions import mypyc_attr |
| |
| from m import define_interpreted_subclass |
| |
| @mypyc_attr(allow_interpreted_subclasses=True) |
| class Base: |
| x = 5 |
| y: int |
| def __init__(self, s: str) -> None: |
| self.s = s |
| |
| class DerivedNative(Base): |
| def __init__(self) -> None: |
| super().__init__('x') |
| self.z = 3 |
| |
| def test_native_subclass() -> None: |
| o = DerivedNative() |
| assert o.x == 5 |
| assert o.s == 'x' |
| assert o.z == 3 |
| |
| def test_interpreted_subclass() -> None: |
| define_interpreted_subclass(Base) |
| |
| [file m.py] |
| from testutil import assertRaises |
| |
| def define_interpreted_subclass(b): |
| class DerivedInterpreted1(b): |
| def __init__(self): |
| # Don't call base class __init__ |
| pass |
| d1 = DerivedInterpreted1() |
| assert d1.x == 5 |
| with assertRaises(AttributeError): |
| d1.y |
| with assertRaises(AttributeError): |
| d1.s |
| with assertRaises(AttributeError): |
| del d1.x |
| |
| class DerivedInterpreted1(b): |
| def __init__(self): |
| super().__init__('y') |
| d2 = DerivedInterpreted1() |
| assert d2.x == 5 |
| assert d2.s == 'y' |
| with assertRaises(AttributeError): |
| d2.y |
| with assertRaises(AttributeError): |
| del d2.x |
| |
| [case testBaseClassSometimesDefinesAttribute] |
| class C: |
| def __init__(self, b: bool) -> None: |
| if b: |
| self.x = [1] |
| |
| class D(C): |
| def __init__(self, b: bool) -> None: |
| super().__init__(b) |
| self.x = [2] |
| |
| def test_base_class() -> None: |
| c = C(True) |
| assert c.x == [1] |
| c = C(False) |
| try: |
| c.x |
| except AttributeError: |
| return |
| assert False |
| |
| def test_subclass() -> None: |
| d = D(True) |
| assert d.x == [2] |
| d = D(False) |
| assert d.x == [2] |
| |
| [case testSerializableClass] |
| from mypy_extensions import mypyc_attr |
| from typing import Any |
| import copy |
| from testutil import assertRaises |
| |
| @mypyc_attr(serializable=True) |
| class Base: |
| def __init__(self, s: str) -> None: |
| self.s = s |
| |
| class Derived(Base): |
| def __init__(self, s: str, n: int) -> None: |
| super().__init__(s) |
| self.n = n |
| |
| def test_copy_base() -> None: |
| o = Base('xyz') |
| o2 = copy.copy(o) |
| assert isinstance(o2, Base) |
| assert o2 is not o |
| assert o2.s == 'xyz' |
| |
| def test_copy_derived() -> None: |
| d = Derived('xyz', 5) |
| d2 = copy.copy(d) |
| assert isinstance(d2, Derived) |
| assert d2 is not d |
| assert d2.s == 'xyz' |
| assert d2.n == 5 |
| |
| class NonSerializable: |
| def __init__(self, s: str) -> None: |
| self.s = s |
| |
| @mypyc_attr(serializable=True) |
| class SerializableSub(NonSerializable): |
| def __init__(self, s: str, n: int) -> None: |
| super().__init__(s) |
| self.n = n |
| |
| def test_serializable_sub_class() -> None: |
| n = NonSerializable('xyz') |
| assert n.s == 'xyz' |
| |
| with assertRaises(TypeError): |
| copy.copy(n) |
| |
| s = SerializableSub('foo', 6) |
| s2 = copy.copy(s) |
| assert s2 is not s |
| assert s2.s == 'foo' |
| assert s2.n == 6 |
| |
| def test_serializable_sub_class_call_new() -> None: |
| t: Any = SerializableSub |
| sub: SerializableSub = t.__new__(t) |
| with assertRaises(AttributeError): |
| sub.s |
| with assertRaises(AttributeError): |
| sub.n |
| base: NonSerializable = sub |
| with assertRaises(AttributeError): |
| base.s |
| |
| [case testClassWithInherited__call__] |
| class Base: |
| def __call__(self) -> int: |
| return 1 |
| |
| class Derived(Base): |
| pass |
| |
| assert Derived()() == 1 |