blob: d505bda2d70554027efce0fb93f9c0942c4df6f3 [file] [log] [blame]
[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