[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 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 import enum class Pokemon(enum.Enum): magikarp = 1 squirtle = 2 slowbro = 3 assert Pokemon.magikarp.value == 1 assert Pokemon.squirtle.name == 'squirtle' [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 A().x AttributeError: attribute 'x' of 'X' undefined [case testClassMethods] from typing import ClassVar, Any from typing_extensions import final from mypy_extensions import mypyc_attr from interp import make_interpreted_subclass 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 @classmethod def call_other(cls, x: int) -> int: return cls.quux(x, 3) class D(C): def f(self) -> int: return super().foo(1) + super().bar(2) + super().baz(10) + super().quux(10) def ctest1() -> int: return C.foo(1) + C.bar(2) + C.baz(10) + C.quux(10) + C.quux(y=10, x=9) def ctest2() -> int: c = C() return c.foo(1) + c.bar(2) + c.baz(10) CAny: Any = C def test_classmethod_using_any() -> None: assert CAny.foo(10) == 20 assert CAny.bar(10) == 19 def test_classmethod_on_instance() -> None: c = C() assert c.foo(10) == 20 assert c.bar(10) == 19 assert c.call_other(1) == 2 def test_classmethod_misc() -> None: assert ctest1() == 23 assert ctest2() == 22 assert C.call_other(2) == 1 def test_classmethod_using_super() -> None: d = D() assert d.f() == 22 @final class F1: @classmethod def f(cls, x: int) -> int: return cls.g(x) @classmethod def g(cls, x: int) -> int: return x + 1 class F2: # Implicitly final (no subclasses) @classmethod def f(cls, x: int) -> int: return cls.g(x) @classmethod def g(cls, x: int) -> int: return x + 1 def test_classmethod_of_final_class() -> None: assert F1.f(5) == 6 assert F2.f(7) == 8 @mypyc_attr(allow_interpreted_subclasses=True) class CI: @classmethod def f(cls, x: int) -> int: return cls.g(x) @classmethod def g(cls, x: int) -> int: return x + 1 def test_classmethod_with_allow_interpreted() -> None: assert CI.f(4) == 5 sub = make_interpreted_subclass(CI) assert sub.f(4) == 7 [file interp.py] def make_interpreted_subclass(base): class Sub(base): @classmethod def g(cls, x: int) -> int: return x + 3 return Sub [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 class Nothing(metaclass=Meta): pass def ident(x): return x @ident class Test: pass [file meta.py] 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 Nothing assert Nothing.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 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 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 testAttributeOverridesProperty] from typing import Any from mypy_extensions import trait @trait class T1: @property def x(self) -> int: ... @property def y(self) -> int: ... class C1(T1): x: int = 1 y: int = 4 def test_read_only_property_in_trait_implemented_as_attribute() -> None: c = C1() c.x = 5 assert c.x == 5 assert c.y == 4 c.y = 6 assert c.y == 6 t: T1 = C1() assert t.y == 4 t = c assert t.x == 5 assert t.y == 6 a: Any = c assert a.x == 5 assert a.y == 6 a.x = 7 a.y = 8 assert a.x == 7 assert a.y == 8 class B2: @property def x(self) -> int: return 11 @property def y(self) -> int: return 25 class C2(B2): x: int = 1 y: int = 4 def test_read_only_property_in_class_implemented_as_attribute() -> None: c = C2() c.x = 5 assert c.x == 5 assert c.y == 4 c.y = 6 assert c.y == 6 b: B2 = C2() assert b.y == 4 b = c assert b.x == 5 assert b.y == 6 a: Any = c assert a.x == 5 assert a.y == 6 a.x = 7 a.y = 8 assert a.x == 7 assert a.y == 8 @trait class T3: @property def x(self) -> int: ... @property def y(self) -> int: ... class B3: x: int = 1 y: int = 4 class C3(B3, T3): pass def test_read_only_property_implemented_as_attribute_indirectly() -> None: c = C3() c.x = 5 assert c.x == 5 assert c.y == 4 c.y = 6 assert c.y == 6 t: T3 = C3() assert t.y == 4 t = c assert t.x == 5 assert t.y == 6 a: Any = c assert a.x == 5 assert a.y == 6 a.x = 7 a.y = 8 assert a.x == 7 assert a.y == 8 @trait class T4: @property def x(self) -> int: ... @x.setter def x(self, v1: int) -> None: ... @property def y(self) -> int: ... @y.setter def y(self, v2: int) -> None: ... class C4(T4): x: int = 1 y: int = 4 def test_read_write_property_implemented_as_attribute() -> None: c = C4() c.x = 5 assert c.x == 5 assert c.y == 4 c.y = 6 assert c.y == 6 t: T4 = C4() assert t.y == 4 t.x = 5 assert t.x == 5 t.y = 6 assert t.y == 6 a: Any = c assert a.x == 5 assert a.y == 6 a.x = 7 a.y = 8 assert a.x == 7 assert a.y == 8 @trait class T5: @property def x(self) -> int: ... @x.setter def x(self, v1: int) -> None: ... @property def y(self) -> int: ... @y.setter def y(self, v2: int) -> None: ... class B5: x: int = 1 y: int = 4 class BB5(B5): pass class C5(BB5, T5): pass def test_read_write_property_indirectly_implemented_as_attribute() -> None: c = C5() c.x = 5 assert c.x == 5 assert c.y == 4 c.y = 6 assert c.y == 6 t: T5 = C5() assert t.y == 4 t.x = 5 assert t.x == 5 t.y = 6 assert t.y == 6 a: Any = c assert a.x == 5 assert a.y == 6 a.x = 7 a.y = 8 assert a.x == 7 assert a.y == 8 [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 [case testClassWithFinalAttribute] from typing_extensions import Final class C: A: Final = -1 a: Final = [A] def test_final_attribute() -> None: assert C.A == -1 assert C.a == [-1]