| [case testEmptyClass] |
| class Empty: pass |
| |
| def f(e: Empty) -> Empty: |
| return e |
| |
| class EmptyEllipsis: ... |
| |
| def g(e: EmptyEllipsis) -> EmptyEllipsis: |
| return e |
| [file driver.py] |
| from native import Empty, EmptyEllipsis, f, g |
| |
| print(isinstance(Empty, type)) |
| print(Empty) |
| print(str(Empty())[:20]) |
| |
| e = Empty() |
| print(f(e) is e) |
| |
| print(isinstance(EmptyEllipsis, type)) |
| print(EmptyEllipsis) |
| print(str(EmptyEllipsis())[:28]) |
| |
| e2 = EmptyEllipsis() |
| print(g(e2) is e2) |
| [out] |
| True |
| <class 'native.Empty'> |
| <native.Empty object |
| True |
| True |
| <class 'native.EmptyEllipsis'> |
| <native.EmptyEllipsis 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 testTypedDictWithFields] |
| import collections |
| import json |
| from typing import TypedDict |
| class C(TypedDict): |
| x: collections.deque |
| spam: json.JSONDecoder |
| [file driver.py] |
| from native import C |
| from collections import deque |
| from json import JSONDecoder |
| |
| print(C.__annotations__["x"] is deque) |
| print(C.__annotations__["spam"] is JSONDecoder) |
| [typing fixtures/typing-full.pyi] |
| [out] |
| True |
| True |
| |
| [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 = 1 |
| b = 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 testClassKwargs] |
| class X: |
| def __init__(self, msg: str, **variables: int) -> None: |
| self.msg = msg |
| self.variables = variables |
| |
| [file driver.py] |
| import traceback |
| from native import X |
| x = X('hello', a=0, b=1) |
| assert x.msg == 'hello' |
| assert x.variables == {'a': 0, 'b': 1} |
| try: |
| X('hello', msg='hello') |
| except TypeError as e: |
| print(f"{type(e).__name__}: {e}") |
| [out] |
| TypeError: argument for __init__() given by name ('msg') and position (1) |
| |
| [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] |
| from typing import ClassVar, Any, 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 testSubclassUnsupportedException] |
| from mypy_extensions import mypyc_attr |
| |
| @mypyc_attr(native_class=False) |
| class MyError(ZeroDivisionError): |
| pass |
| |
| @mypyc_attr(native_class=False) |
| class MyError2(ZeroDivisionError): |
| def __init__(self, s: str) -> None: |
| super().__init__(s + "!") |
| self.x = s.upper() |
| |
| def f() -> None: |
| raise MyError("foobar") |
| |
| def test_non_native_exception_subclass_basics() -> None: |
| e = MyError() |
| assert isinstance(e, MyError) |
| assert isinstance(e, ZeroDivisionError) |
| assert isinstance(e, Exception) |
| |
| e = MyError("x") |
| assert repr(e) == "MyError('x')" |
| |
| e2 = MyError2("ab") |
| assert repr(e2) == "MyError2('ab!')", repr(e2) |
| assert e2.x == "AB" |
| |
| def test_raise_non_native_exception_subclass_1() -> None: |
| try: |
| f() |
| except MyError: |
| x = True |
| else: |
| assert False |
| assert x |
| |
| def test_raise_non_native_exception_subclass_2() -> None: |
| try: |
| f() |
| except ZeroDivisionError: |
| x = True |
| else: |
| assert False |
| assert x |
| |
| [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 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) |
| |
| def test_override() -> None: |
| 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) |
| |
| def test_override() -> None: |
| # 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) |
| |
| def test_override() -> None: |
| 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) |
| |
| def test_override() -> None: |
| 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) |
| |
| def test_override() -> None: |
| 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) |
| |
| def test_override() -> None: |
| # 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 <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 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 |
| |
| def test_inherited() -> None: |
| assert Derived()() == 1 |
| |
| [case testClassWithFinalAttribute] |
| from typing import Final |
| |
| class C: |
| A: Final = -1 |
| a: Final = [A] |
| |
| def test_final_attribute() -> None: |
| assert C.A == -1 |
| assert C.a == [-1] |
| |
| [case testClassWithFinalDecorator] |
| from typing import final |
| |
| @final |
| class C: |
| def a(self) -> int: |
| return 1 |
| |
| def test_class_final_attribute() -> None: |
| assert C().a() == 1 |
| |
| |
| [case testClassWithFinalDecoratorCtor] |
| from typing import final |
| |
| @final |
| class C: |
| def __init__(self) -> None: |
| self.a = 1 |
| |
| def b(self) -> int: |
| return 2 |
| |
| @property |
| def c(self) -> int: |
| return 3 |
| |
| def test_class_final_attribute() -> None: |
| assert C().a == 1 |
| assert C().b() == 2 |
| assert C().c == 3 |
| |
| [case testClassWithFinalDecoratorInheritedWithProperties] |
| from typing import final |
| |
| class B: |
| def a(self) -> int: |
| return 2 |
| |
| @property |
| def b(self) -> int: |
| return self.a() + 2 |
| |
| @property |
| def c(self) -> int: |
| return 3 |
| |
| def test_class_final_attribute_basic() -> None: |
| assert B().a() == 2 |
| assert B().b == 4 |
| assert B().c == 3 |
| |
| @final |
| class C(B): |
| def a(self) -> int: |
| return 1 |
| |
| @property |
| def b(self) -> int: |
| return self.a() + 1 |
| |
| def fn(cl: B) -> int: |
| return cl.a() |
| |
| def test_class_final_attribute_inherited() -> None: |
| assert C().a() == 1 |
| assert fn(C()) == 1 |
| assert B().a() == 2 |
| assert fn(B()) == 2 |
| |
| assert B().b == 4 |
| assert C().b == 2 |
| assert B().c == 3 |
| assert C().c == 3 |
| |
| [case testClassWithFinalAttributeAccess] |
| from typing import Final |
| |
| class C: |
| a: Final = {'x': 'y'} |
| b: Final = C.a |
| |
| def test_final_attribute() -> None: |
| assert C.a['x'] == 'y' |
| assert C.b['x'] == 'y' |
| assert C.a is C.b |
| |
| [case testClassDerivedFromIntEnum] |
| from enum import IntEnum, auto |
| |
| class Player(IntEnum): |
| MIN = auto() |
| |
| print(f'{Player.MIN = }') |
| [file driver.py] |
| from native import Player |
| [out] |
| Player.MIN = <Player.MIN: 1> |
| |
| [case testBufferRoundTrip_native_libs] |
| from typing import Final |
| from mypy_extensions import u8 |
| from native_internal import ( |
| Buffer, write_bool, read_bool, write_str, read_str, write_float, read_float, |
| write_int, read_int, write_tag, read_tag |
| ) |
| |
| Tag = u8 |
| TAG_A: Final[Tag] = 33 |
| TAG_B: Final[Tag] = 255 |
| TAG_SPECIAL: Final[Tag] = 239 |
| |
| def test_buffer_basic() -> None: |
| b = Buffer(b"foo") |
| assert b.getvalue() == b"foo" |
| |
| def test_buffer_roundtrip() -> None: |
| b = Buffer() |
| write_str(b, "foo") |
| write_bool(b, True) |
| write_str(b, "bar" * 1000) |
| write_bool(b, False) |
| write_float(b, 0.1) |
| write_int(b, 0) |
| write_int(b, 1) |
| write_tag(b, TAG_A) |
| write_tag(b, TAG_SPECIAL) |
| write_tag(b, TAG_B) |
| write_int(b, 2) |
| write_int(b, 2 ** 85) |
| write_int(b, 255) |
| write_int(b, -1) |
| write_int(b, -255) |
| write_int(b, 1234512344) |
| write_int(b, 1234512345) |
| |
| b = Buffer(b.getvalue()) |
| assert read_str(b) == "foo" |
| assert read_bool(b) is True |
| assert read_str(b) == "bar" * 1000 |
| assert read_bool(b) is False |
| assert read_float(b) == 0.1 |
| assert read_int(b) == 0 |
| assert read_int(b) == 1 |
| assert read_tag(b) == TAG_A |
| assert read_tag(b) == TAG_SPECIAL |
| assert read_tag(b) == TAG_B |
| assert read_int(b) == 2 |
| assert read_int(b) == 2 ** 85 |
| assert read_int(b) == 255 |
| assert read_int(b) == -1 |
| assert read_int(b) == -255 |
| assert read_int(b) == 1234512344 |
| assert read_int(b) == 1234512345 |
| |
| def test_buffer_int_size() -> None: |
| for i in (-10, -9, 0, 116, 117): |
| b = Buffer() |
| write_int(b, i) |
| assert len(b.getvalue()) == 1 |
| b = Buffer(b.getvalue()) |
| assert read_int(b) == i |
| for i in (-12345, -12344, -11, 118, 12344, 12345): |
| b = Buffer() |
| write_int(b, i) |
| assert len(b.getvalue()) <= 9 # sizeof(size_t) + 1 |
| b = Buffer(b.getvalue()) |
| assert read_int(b) == i |
| |
| def test_buffer_str_size() -> None: |
| for s in ("", "a", "a" * 127): |
| b = Buffer() |
| write_str(b, s) |
| assert len(b.getvalue()) == len(s) + 1 |
| b = Buffer(b.getvalue()) |
| assert read_str(b) == s |
| |
| [file driver.py] |
| from native import * |
| |
| test_buffer_basic() |
| test_buffer_roundtrip() |
| test_buffer_int_size() |
| test_buffer_str_size() |
| |
| def test_buffer_basic_interpreted() -> None: |
| b = Buffer(b"foo") |
| assert b.getvalue() == b"foo" |
| |
| def test_buffer_roundtrip_interpreted() -> None: |
| b = Buffer() |
| write_str(b, "foo") |
| write_bool(b, True) |
| write_str(b, "bar" * 1000) |
| write_bool(b, False) |
| write_float(b, 0.1) |
| write_int(b, 0) |
| write_int(b, 1) |
| write_tag(b, 33) |
| write_tag(b, 239) |
| write_tag(b, 255) |
| write_int(b, 2) |
| write_int(b, 2 ** 85) |
| write_int(b, 255) |
| write_int(b, -1) |
| write_int(b, -255) |
| write_int(b, 1234512344) |
| write_int(b, 1234512345) |
| |
| b = Buffer(b.getvalue()) |
| assert read_str(b) == "foo" |
| assert read_bool(b) is True |
| assert read_str(b) == "bar" * 1000 |
| assert read_bool(b) is False |
| assert read_float(b) == 0.1 |
| assert read_int(b) == 0 |
| assert read_int(b) == 1 |
| assert read_tag(b) == 33 |
| assert read_tag(b) == 239 |
| assert read_tag(b) == 255 |
| assert read_int(b) == 2 |
| assert read_int(b) == 2 ** 85 |
| assert read_int(b) == 255 |
| assert read_int(b) == -1 |
| assert read_int(b) == -255 |
| assert read_int(b) == 1234512344 |
| assert read_int(b) == 1234512345 |
| |
| def test_buffer_int_size_interpreted() -> None: |
| for i in (-10, -9, 0, 116, 117): |
| b = Buffer() |
| write_int(b, i) |
| assert len(b.getvalue()) == 1 |
| b = Buffer(b.getvalue()) |
| assert read_int(b) == i |
| for i in (-12345, -12344, -11, 118, 12344, 12345): |
| b = Buffer() |
| write_int(b, i) |
| assert len(b.getvalue()) <= 9 # sizeof(size_t) + 1 |
| b = Buffer(b.getvalue()) |
| assert read_int(b) == i |
| |
| def test_buffer_str_size_interpreted() -> None: |
| for s in ("", "a", "a" * 127): |
| b = Buffer() |
| write_str(b, s) |
| assert len(b.getvalue()) == len(s) + 1 |
| b = Buffer(b.getvalue()) |
| assert read_str(b) == s |
| |
| test_buffer_basic_interpreted() |
| test_buffer_roundtrip_interpreted() |
| test_buffer_int_size_interpreted() |
| test_buffer_str_size_interpreted() |
| |
| [case testEnumMethodCalls] |
| from enum import Enum |
| from typing import overload, Optional, Union |
| |
| class C: |
| def foo(self, x: Test) -> bool: |
| assert Test.ONE.is_one() |
| assert x.next(2) == Test.THREE |
| assert x.prev(2) == Test.ONE |
| assert x.enigma(22) |
| assert x.enigma("22") == 22 |
| return x.is_one(inverse=True) |
| |
| class Test(Enum): |
| ONE = 1 |
| TWO = 2 |
| THREE = 3 |
| |
| def is_one(self, *, inverse: bool = False) -> bool: |
| if inverse: |
| return self != Test.ONE |
| return self == Test.ONE |
| |
| @classmethod |
| def next(cls, val: int) -> Test: |
| return cls(val + 1) |
| |
| @staticmethod |
| def prev(val: int) -> Test: |
| return Test(val - 1) |
| |
| @overload |
| def enigma(self, val: int) -> bool: ... |
| @overload |
| def enigma(self, val: Optional[str] = None) -> int: ... |
| def enigma(self, val: Union[int, str, None] = None) -> Union[int, bool]: |
| if isinstance(val, int): |
| return self.is_one() |
| return 22 |
| [file driver.py] |
| from native import Test, C |
| |
| assert Test.ONE.is_one() |
| assert Test.TWO.is_one(inverse=True) |
| assert not C().foo(Test.ONE) |
| assert Test.next(2) == Test.THREE |
| assert Test.prev(2) == Test.ONE |
| assert Test.ONE.enigma(22) |
| assert Test.ONE.enigma("22") == 22 |
| |
| [case testStaticCallsWithUnpackingArgs] |
| from typing import Tuple |
| |
| class Foo: |
| @staticmethod |
| def static(a: int, b: int, c: int) -> Tuple[int, int, int]: |
| return (c+1, a+2, b+3) |
| |
| @classmethod |
| def clsmethod(cls, a: int, b: int, c: int) -> Tuple[int, int, int]: |
| return (c+1, a+2, b+3) |
| |
| |
| print(Foo.static(*[10, 20, 30])) |
| print(Foo.static(*(40, 50), *[60])) |
| assert Foo.static(70, 80, *[90]) == Foo.clsmethod(70, *(80, 90)) |
| |
| [file driver.py] |
| import native |
| |
| [out] |
| (31, 12, 23) |
| (61, 42, 53) |
| |
| [case testDataclassInitVar] |
| import dataclasses |
| |
| @dataclasses.dataclass |
| class C: |
| init_v: dataclasses.InitVar[int] |
| v: float = dataclasses.field(init=False) |
| |
| def __post_init__(self, init_v): |
| self.v = init_v + 0.1 |
| |
| [file driver.py] |
| import native |
| print(native.C(22).v) |
| |
| [out] |
| 22.1 |
| |
| [case testLastParentEnum] |
| from enum import Enum |
| |
| class ColorCode(str, Enum): |
| OKGREEN = "okgreen" |
| |
| [file driver.py] |
| import native |
| print(native.ColorCode.OKGREEN.value) |
| |
| [out] |
| okgreen |
| |
| [case testAttrWithSlots] |
| import attr |
| |
| @attr.s(slots=True) |
| class A: |
| ints: list[int] = attr.ib() |
| |
| [file driver.py] |
| import native |
| print(native.A(ints=[1, -17]).ints) |
| |
| [out] |
| \[1, -17] |
| |
| [case testDataclassClassReference] |
| from __future__ import annotations |
| from dataclasses import dataclass |
| |
| class BackwardDefinedClass: |
| pass |
| |
| @dataclass |
| class Data: |
| bitem: BackwardDefinedClass |
| bitems: 'BackwardDefinedClass' |
| fitem: ForwardDefinedClass |
| fitems: 'ForwardDefinedClass' |
| |
| class ForwardDefinedClass: |
| pass |
| |
| def test_function(): |
| d = Data( |
| bitem=BackwardDefinedClass(), |
| bitems=BackwardDefinedClass(), |
| fitem=ForwardDefinedClass(), |
| fitems=ForwardDefinedClass(), |
| ) |
| assert(isinstance(d.bitem, BackwardDefinedClass)) |
| assert(isinstance(d.bitems, BackwardDefinedClass)) |
| assert(isinstance(d.fitem, ForwardDefinedClass)) |
| assert(isinstance(d.fitems, ForwardDefinedClass)) |
| |
| [case testDelForDictSubclass-xfail] |
| # The crash in issue mypy#19175 is fixed. |
| # But, for classes that derive from built-in Python classes, user-defined __del__ method is not |
| # being invoked. |
| class DictSubclass(dict): |
| def __del__(self): |
| print("deleting DictSubclass...") |
| |
| [file driver.py] |
| import native |
| native.DictSubclass() |
| |
| [out] |
| deleting DictSubclass... |
| |
| [case testDel] |
| class A: |
| def __del__(self): |
| print("deleting A...") |
| |
| class B: |
| def __del__(self): |
| print("deleting B...") |
| |
| class C(B): |
| def __init__(self): |
| self.a = A() |
| |
| def __del__(self): |
| print("deleting C...") |
| super().__del__() |
| |
| class D(A): |
| pass |
| |
| # Just make sure that this class compiles (see issue mypy#19175). testDelForDictSubclass tests for |
| # correct output. |
| class NormDict(dict): |
| def __del__(self) -> None: |
| pass |
| |
| [file driver.py] |
| import native |
| native.C() |
| native.D() |
| |
| [out] |
| deleting C... |
| deleting B... |
| deleting A... |
| deleting A... |
| |
| [case testDelCircular] |
| import dataclasses |
| import typing |
| |
| i: int = 1 |
| |
| @dataclasses.dataclass |
| class C: |
| var: typing.Optional["C"] = dataclasses.field(default=None) |
| |
| def __del__(self): |
| global i |
| print(f"deleting C{i}...") |
| i = i + 1 |
| |
| [file driver.py] |
| import native |
| import gc |
| |
| c1 = native.C() |
| c2 = native.C() |
| c1.var = c2 |
| c2.var = c1 |
| del c1 |
| del c2 |
| gc.collect() |
| |
| [out] |
| deleting C1... |
| deleting C2... |
| |
| [case testDelException] |
| # The error message in the expected output of this test does not match CPython's error message due to the way mypyc compiles Python classes. If the error message is fixed, the expected output of this test will also change. |
| class F: |
| def __del__(self): |
| if True: |
| raise Exception("e2") |
| |
| [file driver.py] |
| import native |
| f = native.F() |
| del f |
| |
| [out] |
| Exception ignored in: <native.F object at 0x000000000000> |
| Traceback (most recent call last): |
| File "native.py", line 5, in __del__ |
| raise Exception("e2") |
| Exception: e2 |
| |
| [case testMypycAttrNativeClass] |
| from mypy_extensions import mypyc_attr |
| from testutil import assertRaises |
| |
| @mypyc_attr(native_class=False) |
| class AnnontatedNonExtensionClass: |
| pass |
| |
| class DerivedClass(AnnontatedNonExtensionClass): |
| pass |
| |
| class ImplicitExtensionClass(): |
| pass |
| |
| @mypyc_attr(native_class=True) |
| class AnnotatedExtensionClass(): |
| pass |
| |
| def test_function(): |
| setattr(AnnontatedNonExtensionClass, 'attr_class', 5) |
| assert(hasattr(AnnontatedNonExtensionClass, 'attr_class') == True) |
| assert(getattr(AnnontatedNonExtensionClass, 'attr_class') == 5) |
| delattr(AnnontatedNonExtensionClass, 'attr_class') |
| assert(hasattr(AnnontatedNonExtensionClass, 'attr_class') == False) |
| |
| inst = AnnontatedNonExtensionClass() |
| setattr(inst, 'attr_instance', 6) |
| assert(hasattr(inst, 'attr_instance') == True) |
| assert(getattr(inst, 'attr_instance') == 6) |
| delattr(inst, 'attr_instance') |
| assert(hasattr(inst, 'attr_instance') == False) |
| |
| setattr(DerivedClass, 'attr_class', 5) |
| assert(hasattr(DerivedClass, 'attr_class') == True) |
| assert(getattr(DerivedClass, 'attr_class') == 5) |
| delattr(DerivedClass, 'attr_class') |
| assert(hasattr(DerivedClass, 'attr_class') == False) |
| |
| derived_inst = DerivedClass() |
| setattr(derived_inst, 'attr_instance', 6) |
| assert(hasattr(derived_inst, 'attr_instance') == True) |
| assert(getattr(derived_inst, 'attr_instance') == 6) |
| delattr(derived_inst, 'attr_instance') |
| assert(hasattr(derived_inst, 'attr_instance') == False) |
| |
| ext_inst = ImplicitExtensionClass() |
| with assertRaises(AttributeError): |
| setattr(ext_inst, 'attr_instance', 6) |
| |
| explicit_ext_inst = AnnotatedExtensionClass() |
| with assertRaises(AttributeError): |
| setattr(explicit_ext_inst, 'attr_instance', 6) |
| |
| [case testMypycAttrNativeClassDunder] |
| from mypy_extensions import mypyc_attr |
| from typing import Generic, Optional, TypeVar |
| |
| _T = TypeVar("_T") |
| |
| get_count = set_count = del_count = 0 |
| |
| @mypyc_attr(native_class=False) |
| class Bar(Generic[_T]): |
| # Note the lack of __deletable__ |
| def __init__(self) -> None: |
| self.value: str = 'start' |
| def __get__(self, instance: _T, owner: Optional[type[_T]] = None) -> str: |
| global get_count |
| get_count += 1 |
| return self.value |
| def __set__(self, instance: _T, value: str) -> None: |
| global set_count |
| set_count += 1 |
| self.value = value |
| def __delete__(self, instance: _T) -> None: |
| global del_count |
| del_count += 1 |
| del self.value |
| |
| @mypyc_attr(native_class=False) |
| class Foo(object): |
| bar: Bar = Bar() |
| |
| [file driver.py] |
| import native |
| |
| f = native.Foo() |
| assert(hasattr(f, 'bar')) |
| assert(native.get_count == 1) |
| assert(f.bar == 'start') |
| assert(native.get_count == 2) |
| f.bar = 'test' |
| assert(f.bar == 'test') |
| assert(native.set_count == 1) |
| del f.bar |
| assert(not hasattr(f, 'bar')) |
| assert(native.del_count == 1) |
| |
| [case testMypycAttrNativeClassMeta] |
| from mypy_extensions import mypyc_attr |
| from typing import ClassVar, TypeVar |
| |
| _T = TypeVar("_T") |
| |
| @mypyc_attr(native_class=False) |
| class M(type): |
| count: ClassVar[int] = 0 |
| def make(cls: type[_T]) -> _T: |
| M.count += 1 |
| return cls() |
| |
| # implicit native_class=False |
| # see testMypycAttrNativeClassMetaError for when trying to set it True |
| class A(metaclass=M): |
| pass |
| |
| [file driver.py] |
| import native |
| |
| a: native.A = native.A.make() |
| assert(native.A.count == 1) |
| |
| class B(native.A): |
| pass |
| |
| b: B = B.make() |
| assert(B.count == 2) |
| |
| [case testTypeVarNarrowing] |
| from typing import TypeVar |
| |
| class B: |
| def __init__(self, x: int) -> None: |
| self.x = x |
| class C(B): |
| def __init__(self, x: int, y: str) -> None: |
| self.x = x |
| self.y = y |
| |
| T = TypeVar("T", bound=B) |
| def f(x: T) -> T: |
| if isinstance(x, C): |
| print("C", x.y) |
| return x |
| print("B", x.x) |
| return x |
| |
| [file driver.py] |
| from native import f, B, C |
| |
| f(B(1)) |
| f(C(1, "yes")) |
| [out] |
| B 1 |
| C yes |
| |
| [case testTypeObjectName] |
| from typing import Any |
| import re |
| |
| from dynamic import E, foo, Thing |
| |
| class C: pass |
| class D(C): pass |
| |
| def type_name(t: type[object]) -> str: |
| return t.__name__ |
| |
| def any_name(x: Any) -> str: |
| return x.__name__ |
| |
| def assert_type_name(x: Any) -> None: |
| assert type_name(x) == getattr(x, "__name__") |
| assert any_name(x) == getattr(x, "__name__") |
| |
| def assert_any_name(x: Any) -> None: |
| assert any_name(x) == getattr(x, "__name__") |
| |
| def test_type_name() -> None: |
| assert_type_name(C) |
| assert_type_name(D) |
| assert_type_name(int) |
| assert_type_name(E) |
| assert_type_name(re.Pattern) |
| |
| def test_module_name() -> None: |
| assert_any_name(re) |
| |
| def test_function_name() -> None: |
| assert_any_name(any_name) |
| assert_any_name(foo) |
| |
| def test_obj_name() -> None: |
| assert_any_name(Thing()) |
| |
| [file dynamic.py] |
| class E: pass |
| |
| def foo(): pass |
| |
| class Thing: |
| def __init__(self): |
| self.__name__ = "xyz" |
| |
| [case testTypeOfObject] |
| from typing import Any |
| |
| from dynamic import Dyn |
| |
| class Foo: pass |
| class Bar(Foo): pass |
| |
| def generic_type(x) -> type[object]: |
| return x.__class__ |
| |
| def test_built_in_type() -> None: |
| i: Any = int |
| l: Any = list |
| assert type(i()) is i().__class__ |
| assert type(i()) is int |
| assert type(l()) is list |
| n = 5 |
| assert n.__class__ is i |
| |
| def test_native_class() -> None: |
| f_any: Any = Foo() |
| b_any: Any = Bar() |
| f: Foo = f_any |
| b: Foo = b_any |
| if int("1"): # use int("1") to avoid constant folding |
| assert type(f) is Foo |
| assert type(b) is Bar |
| if int("2"): |
| assert f.__class__ is Foo |
| assert b.__class__ is Bar |
| if int("3"): |
| assert f_any.__class__ is Foo |
| assert b_any.__class__ is Bar |
| if int("4"): |
| assert type(f_any) is Foo |
| assert type(b_any) is Bar |
| |
| def test_python_class() -> None: |
| d = Dyn() |
| assert type(d) is Dyn |
| assert d.__class__ is Dyn |
| |
| [file dynamic.py] |
| class Dyn: pass |
| |
| [case testDunderNew] |
| from __future__ import annotations |
| from typing import Any, Union |
| |
| from testutil import assertRaises |
| |
| class Add: |
| l: IntLike |
| r: IntLike |
| |
| def __new__(cls, l: IntLike, r: IntLike) -> Any: |
| return ( |
| l if r == 0 else |
| r if l == 0 else |
| super().__new__(cls) |
| ) |
| |
| def __init__(self, l: IntLike, r: IntLike): |
| self.l = l |
| self.r = r |
| |
| IntLike = Union[int, Add] |
| |
| class RaisesException: |
| def __new__(cls, val: int) -> RaisesException: |
| if val == 0: |
| raise RuntimeError("Invalid value!") |
| return super().__new__(cls) |
| |
| def __init__(self, val: int) -> None: |
| self.val = val |
| |
| class ClsArgNotPassed: |
| def __new__(cls) -> Any: |
| return super().__new__(str) |
| |
| def test_dunder_new() -> None: |
| add_instance: Any = Add(1, 5) |
| assert type(add_instance) == Add |
| assert add_instance.l == 1 |
| assert add_instance.r == 5 |
| |
| # TODO: explicit types should not be needed but mypy does not use |
| # the return type of __new__ which makes mypyc add casts to Add. |
| right_int: Any = Add(0, 5) |
| assert type(right_int) == int |
| assert right_int == 5 |
| |
| left_int: Any = Add(1, 0) |
| assert type(left_int) == int |
| assert left_int == 1 |
| |
| with assertRaises(RuntimeError, "Invalid value!"): |
| raised = RaisesException(0) |
| |
| not_raised = RaisesException(1) |
| assert not_raised.val == 1 |
| |
| with assertRaises(TypeError, "object.__new__(str) is not safe, use str.__new__()"): |
| str_as_cls = ClsArgNotPassed() |
| |
| |
| [case testDunderNewInInterpreted] |
| from __future__ import annotations |
| from typing import Any, Union |
| |
| class Add: |
| l: IntLike |
| r: IntLike |
| |
| def __new__(cls, l: IntLike, r: IntLike) -> Any: |
| print(f'running __new__ with {l} and {r}') |
| |
| return ( |
| l if r == 0 else |
| r if l == 0 else |
| super().__new__(cls) |
| ) |
| |
| def __init__(self, l: IntLike, r: IntLike): |
| self.l = l |
| self.r = r |
| |
| def __repr__(self) -> str: |
| return f'({self.l} + {self.r})' |
| |
| IntLike = Union[int, Add] |
| |
| class RaisesException: |
| def __new__(cls, val: int) -> RaisesException: |
| if val == 0: |
| raise RuntimeError("Invalid value!") |
| return super().__new__(cls) |
| |
| def __init__(self, val: int) -> None: |
| self.val = val |
| |
| class ClsArgNotPassed: |
| def __new__(cls) -> Any: |
| return super().__new__(str) |
| |
| [file driver.py] |
| from native import Add, ClsArgNotPassed, RaisesException |
| |
| from testutil import assertRaises |
| |
| print(f'{Add(1, 5)=}') |
| print(f'{Add(0, 5)=}') |
| print(f'{Add(1, 0)=}') |
| |
| with assertRaises(RuntimeError, "Invalid value!"): |
| raised = RaisesException(0) |
| |
| not_raised = RaisesException(1) |
| assert not_raised.val == 1 |
| |
| with assertRaises(TypeError, "object.__new__(str) is not safe, use str.__new__()"): |
| str_as_cls = ClsArgNotPassed() |
| |
| [out] |
| running __new__ with 1 and 5 |
| Add(1, 5)=(1 + 5) |
| running __new__ with 0 and 5 |
| Add(0, 5)=5 |
| running __new__ with 1 and 0 |
| Add(1, 0)=1 |
| |
| [case testObjectDunderNew] |
| from __future__ import annotations |
| from typing import Any, Union |
| |
| from testutil import assertRaises |
| |
| class Add: |
| l: IntLike |
| r: IntLike |
| |
| def __new__(cls, l: IntLike, r: IntLike) -> Any: |
| return ( |
| l if r == 0 else |
| r if l == 0 else |
| object.__new__(cls) |
| ) |
| |
| def __init__(self, l: IntLike, r: IntLike): |
| self.l = l |
| self.r = r |
| |
| IntLike = Union[int, Add] |
| |
| class RaisesException: |
| def __new__(cls, val: int) -> RaisesException: |
| if val == 0: |
| raise RuntimeError("Invalid value!") |
| return object.__new__(cls) |
| |
| def __init__(self, val: int) -> None: |
| self.val = val |
| |
| class ClsArgNotPassed: |
| def __new__(cls) -> Any: |
| return object.__new__(str) |
| |
| class SkipsBase(Add): |
| def __new__(cls) -> Any: |
| obj = object.__new__(cls) |
| obj.l = 0 |
| obj.r = 0 |
| return obj |
| |
| def test_dunder_new() -> None: |
| add_instance: Any = Add(1, 5) |
| assert type(add_instance) == Add |
| assert add_instance.l == 1 |
| assert add_instance.r == 5 |
| |
| # TODO: explicit types should not be needed but mypy does not use |
| # the return type of __new__ which makes mypyc add casts to Add. |
| right_int: Any = Add(0, 5) |
| assert type(right_int) == int |
| assert right_int == 5 |
| |
| left_int: Any = Add(1, 0) |
| assert type(left_int) == int |
| assert left_int == 1 |
| |
| with assertRaises(RuntimeError, "Invalid value!"): |
| _ = RaisesException(0) |
| |
| not_raised = RaisesException(1) |
| assert not_raised.val == 1 |
| |
| with assertRaises(TypeError, "object.__new__(str) is not safe, use str.__new__()"): |
| _ = ClsArgNotPassed() |
| |
| skip = SkipsBase.__new__(SkipsBase) |
| assert type(skip) == SkipsBase |
| assert skip.l == 0 |
| assert skip.r == 0 |
| |
| [case testObjectDunderNewInInterpreted] |
| from __future__ import annotations |
| from typing import Any, Union |
| |
| class Add: |
| l: IntLike |
| r: IntLike |
| |
| def __new__(cls, l: IntLike, r: IntLike) -> Any: |
| print(f'running __new__ with {l} and {r}') |
| |
| return ( |
| l if r == 0 else |
| r if l == 0 else |
| object.__new__(cls) |
| ) |
| |
| def __init__(self, l: IntLike, r: IntLike): |
| self.l = l |
| self.r = r |
| |
| def __repr__(self) -> str: |
| return f'({self.l} + {self.r})' |
| |
| IntLike = Union[int, Add] |
| |
| class RaisesException: |
| def __new__(cls, val: int) -> RaisesException: |
| if val == 0: |
| raise RuntimeError("Invalid value!") |
| return object.__new__(cls) |
| |
| def __init__(self, val: int) -> None: |
| self.val = val |
| |
| class ClsArgNotPassed: |
| def __new__(cls) -> Any: |
| return object.__new__(str) |
| |
| class SkipsBase(Add): |
| def __new__(cls) -> Any: |
| obj = object.__new__(cls) |
| obj.l = 0 |
| obj.r = 0 |
| return obj |
| |
| [file driver.py] |
| from native import Add, ClsArgNotPassed, RaisesException, SkipsBase |
| |
| from testutil import assertRaises |
| |
| print(f'{Add(1, 5)=}') |
| print(f'{Add(0, 5)=}') |
| print(f'{Add(1, 0)=}') |
| |
| with assertRaises(RuntimeError, "Invalid value!"): |
| raised = RaisesException(0) |
| |
| not_raised = RaisesException(1) |
| assert not_raised.val == 1 |
| |
| with assertRaises(TypeError, "object.__new__(str) is not safe, use str.__new__()"): |
| str_as_cls = ClsArgNotPassed() |
| |
| skip = SkipsBase.__new__(SkipsBase) |
| assert type(skip) == SkipsBase |
| assert skip.l == 0 |
| assert skip.r == 0 |
| |
| [out] |
| running __new__ with 1 and 5 |
| Add(1, 5)=(1 + 5) |
| running __new__ with 0 and 5 |
| Add(0, 5)=5 |
| running __new__ with 1 and 0 |
| Add(1, 0)=1 |
| |
| [case testInheritedDunderNew] |
| from __future__ import annotations |
| from mypy_extensions import mypyc_attr |
| from typing_extensions import Self |
| |
| from m import interpreted_subclass |
| |
| @mypyc_attr(allow_interpreted_subclasses=True) |
| class Base: |
| val: int |
| |
| def __new__(cls, val: int) -> Self: |
| obj = super().__new__(cls) |
| obj.val = val + 1 |
| return obj |
| |
| def __init__(self, val: int) -> None: |
| self.init_val = val |
| |
| class Sub(Base): |
| def __new__(cls, val: int) -> Self: |
| return super().__new__(cls, val + 1) |
| |
| def __init__(self, val: int) -> None: |
| super().__init__(val) |
| self.init_val = self.init_val * 2 |
| |
| class SubWithoutNew(Base): |
| def __init__(self, val: int) -> None: |
| super().__init__(val) |
| self.init_val = self.init_val * 2 |
| |
| class BaseWithoutInterpretedSubclasses: |
| val: int |
| |
| def __new__(cls, val: int) -> Self: |
| obj = super().__new__(cls) |
| obj.val = val + 1 |
| return obj |
| |
| def __init__(self, val: int) -> None: |
| self.init_val = val |
| |
| class SubNoInterpreted(BaseWithoutInterpretedSubclasses): |
| def __new__(cls, val: int) -> Self: |
| return super().__new__(cls, val + 1) |
| |
| def __init__(self, val: int) -> None: |
| super().__init__(val) |
| self.init_val = self.init_val * 2 |
| |
| class SubNoInterpretedWithoutNew(BaseWithoutInterpretedSubclasses): |
| def __init__(self, val: int) -> None: |
| super().__init__(val) |
| self.init_val = self.init_val * 2 |
| |
| def test_inherited_dunder_new() -> None: |
| b = Base(42) |
| assert type(b) == Base |
| assert b.val == 43 |
| assert b.init_val == 42 |
| |
| s = Sub(42) |
| assert type(s) == Sub |
| assert s.val == 44 |
| assert s.init_val == 84 |
| |
| s2 = SubWithoutNew(42) |
| assert type(s2) == SubWithoutNew |
| assert s2.val == 43 |
| assert s2.init_val == 84 |
| |
| def test_inherited_dunder_new_without_interpreted_subclasses() -> None: |
| b = BaseWithoutInterpretedSubclasses(42) |
| assert type(b) == BaseWithoutInterpretedSubclasses |
| assert b.val == 43 |
| assert b.init_val == 42 |
| |
| s = SubNoInterpreted(42) |
| assert type(s) == SubNoInterpreted |
| assert s.val == 44 |
| assert s.init_val == 84 |
| |
| s2 = SubNoInterpretedWithoutNew(42) |
| assert type(s2) == SubNoInterpretedWithoutNew |
| assert s2.val == 43 |
| assert s2.init_val == 84 |
| |
| def test_interpreted_subclass() -> None: |
| interpreted_subclass(Base) |
| |
| [file m.py] |
| from __future__ import annotations |
| from typing_extensions import Self |
| |
| def interpreted_subclass(base) -> None: |
| b = base(42) |
| assert type(b) == base |
| assert b.val == 43 |
| assert b.init_val == 42 |
| |
| class InterpretedSub(base): |
| def __new__(cls, val: int) -> Self: |
| return super().__new__(cls, val + 1) |
| |
| def __init__(self, val: int) -> None: |
| super().__init__(val) |
| self.init_val : int = self.init_val * 2 |
| |
| s = InterpretedSub(42) |
| assert type(s) == InterpretedSub |
| assert s.val == 44 |
| assert s.init_val == 84 |
| |
| class InterpretedSubWithoutNew(base): |
| def __init__(self, val: int) -> None: |
| super().__init__(val) |
| self.init_val : int = self.init_val * 2 |
| |
| s2 = InterpretedSubWithoutNew(42) |
| assert type(s2) == InterpretedSubWithoutNew |
| assert s2.val == 43 |
| assert s2.init_val == 84 |
| |
| [typing fixtures/typing-full.pyi] |
| |
| [case testDunderNewInitArgMismatch] |
| from __future__ import annotations |
| from testutil import assertRaises |
| |
| class Test0: |
| @classmethod |
| def __new__(cls, val: int = 42) -> Test0: |
| obj = super().__new__(cls) |
| obj.val = val |
| return obj |
| |
| def __init__(self) -> None: |
| self.val = 0 |
| |
| class Test1: |
| def __new__(cls, val: int) -> Test1: |
| obj = super().__new__(cls) |
| obj.val = val |
| return obj |
| |
| def __init__(self) -> None: |
| self.val = 0 |
| |
| class Test2: |
| def __new__(cls) -> Test2: |
| obj = super().__new__(cls) |
| return obj |
| |
| def __init__(self, val: int) -> None: |
| self.val = val |
| |
| def test_arg_mismatch() -> None: |
| t0 = Test0() |
| assert t0.val == 0 |
| t0 = Test0.__new__(1) |
| assert t0.val == 1 |
| with assertRaises(TypeError, "__new__() missing required argument 'val'"): |
| t1 = Test1() |
| t1 = Test1.__new__(Test1, 2) |
| assert t1.val == 2 |
| with assertRaises(TypeError, "__new__() takes at most 0 arguments"): |
| t2 = Test2(42) |
| t2 = Test2.__new__(Test2) |
| with assertRaises(AttributeError, "attribute 'val' of 'Test2' undefined"): |
| print(t2.val) |
| |
| [case testDunderNewInitArgMismatchInInterpreted] |
| from __future__ import annotations |
| |
| class Test0: |
| # TODO: It should be possible to annotate '@classmethod' here |
| # but when it's added calling __new__ in interpreted code |
| # without the explicit type param results in a TypeError. |
| def __new__(cls, val: int = 42) -> Test0: |
| obj = super().__new__(cls) |
| obj.val = val |
| return obj |
| |
| def __init__(self) -> None: |
| self.val = 0 |
| |
| class Test1: |
| def __new__(cls, val: int) -> Test1: |
| obj = super().__new__(cls) |
| obj.val = val |
| return obj |
| |
| def __init__(self) -> None: |
| self.val = 0 |
| |
| class Test2: |
| def __new__(cls) -> Test2: |
| obj = super().__new__(cls) |
| return obj |
| |
| def __init__(self, val: int) -> None: |
| self.val = val |
| |
| [file driver.py] |
| from native import Test0, Test1, Test2 |
| from testutil import assertRaises |
| |
| t0 = Test0() |
| assert t0.val == 0 |
| t0 = Test0.__new__(Test0, 1) |
| assert t0.val == 1 |
| with assertRaises(TypeError, "__new__() missing required argument 'val'"): |
| t1 = Test1() |
| t1 = Test1.__new__(Test1, 2) |
| assert t1.val == 2 |
| with assertRaises(TypeError, "__new__() takes at most 0 arguments"): |
| t2 = Test2(42) |
| t2 = Test2.__new__(Test2) |
| with assertRaises(AttributeError, "attribute 'val' of 'Test2' undefined"): |
| print(t2.val) |
| |
| [case testDunderNewAttributeAccess] |
| from __future__ import annotations |
| |
| from mypy_extensions import u8 |
| from testutil import assertRaises |
| |
| class Test: |
| native: int |
| generic: object |
| bitfield: u8 |
| default: int = 5 |
| |
| def __new__(cls, native: int, generic: object, bitfield: u8) -> Test: |
| obj = super().__new__(cls) |
| |
| with assertRaises(AttributeError, "attribute 'native' of 'Test' undefined"): |
| print(obj.native) |
| with assertRaises(AttributeError, "attribute 'generic' of 'Test' undefined"): |
| print(obj.generic) |
| with assertRaises(AttributeError, "attribute 'bitfield' of 'Test' undefined"): |
| print(obj.bitfield) |
| |
| obj.native = native |
| obj.generic = generic |
| obj.bitfield = bitfield |
| |
| obj.native = obj.native + 1 |
| obj.generic = obj.generic.__str__() |
| obj.bitfield = obj.bitfield & 0x0F |
| obj.default = obj.default * 2 |
| return obj |
| |
| def test_attribute_access() -> None: |
| t = Test(42, {}, 0xCC) |
| assert t.native == 43 |
| assert t.generic == "{}" |
| assert t.bitfield == 0x0C |
| assert t.default == 10 |
| |
| [case testDunderNewAttributeAccessInInterpreted] |
| from __future__ import annotations |
| |
| from mypy_extensions import u8 |
| from testutil import assertRaises |
| |
| class Test: |
| native: int |
| generic: object |
| bitfield: u8 |
| default: int = 5 |
| |
| def __new__(cls, native: int, generic: object, bitfield: u8) -> Test: |
| obj = super().__new__(cls) |
| |
| with assertRaises(AttributeError, "attribute 'native' of 'Test' undefined"): |
| print(obj.native) |
| with assertRaises(AttributeError, "attribute 'generic' of 'Test' undefined"): |
| print(obj.generic) |
| with assertRaises(AttributeError, "attribute 'bitfield' of 'Test' undefined"): |
| print(obj.bitfield) |
| |
| obj.native = native |
| obj.generic = generic |
| obj.bitfield = bitfield |
| |
| obj.native = obj.native + 1 |
| obj.generic = obj.generic.__str__() |
| obj.bitfield = obj.bitfield & 0x0F |
| obj.default = obj.default * 2 |
| return obj |
| |
| [file driver.py] |
| from native import Test |
| |
| t = Test(42, {}, 0xCC) |
| assert t.native == 43 |
| assert t.generic == "{}" |
| assert t.bitfield == 0x0C |
| assert t.default == 10 |
| |
| [case testUntransformedDunderNewCalls] |
| from testutil import assertRaises |
| from typing import Any |
| |
| class TestStrCls: |
| def __new__(cls): |
| return str.__new__(cls) |
| |
| @classmethod |
| def factory(cls): |
| return str.__new__(cls) |
| |
| class TestStrStr: |
| def __new__(cls): |
| return str.__new__(str) |
| |
| @classmethod |
| def factory(cls): |
| return str.__new__(str) |
| |
| class TestStrInt: |
| def __new__(cls): |
| return str.__new__(int) |
| |
| @classmethod |
| def factory(cls): |
| return str.__new__(int) |
| |
| def test_untransformed_dunder_new() -> None: |
| with assertRaises(TypeError, "str.__new__(TestStrCls): TestStrCls is not a subtype of str"): |
| i = TestStrCls() |
| |
| j: Any = TestStrStr() |
| assert j == "" |
| |
| with assertRaises(TypeError, "str.__new__(int): int is not a subtype of str"): |
| k = TestStrInt() |
| |
| with assertRaises(TypeError, "str.__new__(TestStrCls): TestStrCls is not a subtype of str"): |
| i = TestStrCls.factory() |
| |
| j = TestStrStr.factory() |
| assert j == "" |
| |
| with assertRaises(TypeError, "str.__new__(int): int is not a subtype of str"): |
| k = TestStrInt.factory() |
| |
| [case testPerTypeFreeList] |
| from __future__ import annotations |
| |
| from mypy_extensions import mypyc_attr |
| |
| a = [] |
| |
| @mypyc_attr(free_list_len=1) |
| class Foo: |
| def __init__(self, x: int) -> None: |
| self.x = x |
| a.append(x) |
| |
| def test_alloc() -> None: |
| x: Foo | None |
| y: Foo | None |
| |
| x = Foo(1) |
| assert x.x == 1 |
| x = None |
| |
| x = Foo(2) |
| assert x.x == 2 |
| y = Foo(3) |
| assert x.x == 2 |
| assert y.x == 3 |
| x = None |
| y = None |
| assert a == [1, 2, 3] |
| |
| x = Foo(4) |
| assert x.x == 4 |
| y = Foo(5) |
| assert x.x == 4 |
| assert y.x == 5 |
| |
| @mypyc_attr(free_list_len=1) |
| class Base: |
| def __init__(self, x: str) -> None: |
| self.x = x |
| |
| class Deriv(Base): |
| def __init__(self, x: str, y: str) -> None: |
| super().__init__(x) |
| self.y = y |
| |
| @mypyc_attr(free_list_len=1) |
| class Deriv2(Base): |
| def __init__(self, x: str, y: str) -> None: |
| super().__init__(x) |
| self.y = y |
| |
| def test_inheritance() -> None: |
| x: Base | None |
| y: Base | None |
| x = Base('x' + str()) |
| y = Base('y' + str()) |
| y = None |
| d = Deriv('a' + str(), 'b' + str()) |
| assert type(d) is Deriv |
| assert d.x == 'a' |
| assert d.y == 'b' |
| assert x.x == 'x' |
| y = Base('z' + str()) |
| assert d.x == 'a' |
| assert d.y == 'b' |
| assert y.x == 'z' |
| x = None |
| y = None |
| |
| def test_inheritance_2() -> None: |
| x: Base | None |
| y: Base | None |
| d: Deriv2 | None |
| x = Base('x' + str()) |
| y = Base('y' + str()) |
| y = None |
| d = Deriv2('a' + str(), 'b' + str()) |
| assert type(d) is Deriv2 |
| assert d.x == 'a' |
| assert d.y == 'b' |
| assert x.x == 'x' |
| d = None |
| d = Deriv2('c' + str(), 'd' + str()) |
| assert type(d) is Deriv2 |
| assert d.x == 'c' |
| assert d.y == 'd' |
| assert x.x == 'x' |
| y = Base('z' + str()) |
| assert type(y) is Base |
| assert d.x == 'c' |
| assert d.y == 'd' |
| assert y.x == 'z' |
| x = None |
| y = None |
| d = None |
| |
| [case testDunderGetAttr] |
| from mypy_extensions import mypyc_attr |
| from typing import ClassVar |
| |
| class GetAttr: |
| class_var = "x" |
| |
| def __init__(self, extra_attrs: dict[str, object], regular_attr: int): |
| self.extra_attrs = extra_attrs |
| self.regular_attr = regular_attr |
| |
| def __getattr__(self, attr: str) -> object: |
| return self.extra_attrs.get(attr) |
| |
| class GetAttrDefault: |
| class_var: ClassVar[str] = "x" |
| |
| def __init__(self, extra_attrs: dict[str, object], regular_attr: int): |
| self.extra_attrs = extra_attrs |
| self.regular_attr = regular_attr |
| |
| def __getattr__(self, attr: str, default: int = 8, mult: int = 1) -> object: |
| return self.extra_attrs.get(attr, default * mult) |
| |
| class GetAttrInherited(GetAttr): |
| subclass_var = "y" |
| |
| def __init__(self, extra_attrs: dict[str, object], regular_attr: int, sub_attr: int): |
| super().__init__(extra_attrs, regular_attr) |
| self.sub_attr = sub_attr |
| |
| class GetAttrOverridden(GetAttr): |
| subclass_var: ClassVar[str] = "y" |
| |
| def __init__(self, extra_attrs: dict[str, object], regular_attr: int, sub_attr: int): |
| super().__init__(extra_attrs, regular_attr) |
| self.sub_attr = sub_attr |
| |
| def __getattr__(self, attr: str) -> str: |
| return attr |
| |
| @mypyc_attr(native_class=False) |
| class GetAttrNonNative: |
| class_var = "x" |
| |
| def __init__(self, extra_attrs: dict[str, object], regular_attr: int): |
| self.extra_attrs = extra_attrs |
| self.regular_attr = regular_attr |
| |
| def __getattr__(self, attr: str) -> object: |
| return self.extra_attrs.get(attr) |
| |
| def test_getattr() -> None: |
| i = GetAttr({"one": 1, "two": "two", "three": 3.14}, 42) |
| assert i.__getattr__("one") == 1 |
| assert i.__getattr__("regular_attr") == None |
| assert i.__getattr__("class_var") == None |
| assert i.__getattr__("four") == None |
| |
| assert getattr(i, "two") == "two" |
| assert getattr(i, "regular_attr") == 42 |
| assert getattr(i, "class_var") == "x" |
| assert getattr(i, "four") == None |
| |
| assert i.three == 3.14 |
| assert i.regular_attr == 42 |
| assert i.class_var == "x" |
| assert i.four == None |
| |
| assert i.__class__ == GetAttr |
| |
| i.extra_attrs["regular_attr"] = (4, 4, 4) |
| assert i.__getattr__("regular_attr") == (4, 4, 4) |
| assert getattr(i, "regular_attr") == 42 |
| assert i.regular_attr == 42 |
| |
| def test_getattr_default() -> None: |
| i = GetAttrDefault({"one": 1, "two": "two", "three": 3.14}, 42) |
| assert i.__getattr__("one") == 1 |
| assert i.__getattr__("regular_attr") == 8 |
| assert i.__getattr__("class_var") == 8 |
| assert i.__getattr__("four", 4, 3) == 12 |
| |
| assert getattr(i, "two") == "two" |
| assert getattr(i, "regular_attr") == 42 |
| assert getattr(i, "class_var") == "x" |
| assert getattr(i, "four") == 8 |
| |
| assert i.three == 3.14 |
| assert i.regular_attr == 42 |
| assert i.class_var == "x" |
| assert i.four == 8 |
| |
| assert i.__class__ == GetAttrDefault |
| |
| i.extra_attrs["class_var"] = (4, 4, 4) |
| assert i.__getattr__("class_var") == (4, 4, 4) |
| assert getattr(i, "class_var") == "x" |
| assert i.class_var == "x" |
| |
| def test_getattr_inherited() -> None: |
| i = GetAttrInherited({"one": 1, "two": "two", "three": 3.14}, 42, 24) |
| assert i.__getattr__("one") == 1 |
| assert i.__getattr__("regular_attr") == None |
| assert i.__getattr__("sub_attr") == None |
| assert i.__getattr__("class_var") == None |
| assert i.__getattr__("subclass_var") == None |
| assert i.__getattr__("four") == None |
| |
| assert getattr(i, "two") == "two" |
| assert getattr(i, "regular_attr") == 42 |
| assert getattr(i, "sub_attr") == 24 |
| assert getattr(i, "class_var") == "x" |
| assert getattr(i, "subclass_var") == "y" |
| assert getattr(i, "four") == None |
| |
| assert i.three == 3.14 |
| assert i.regular_attr == 42 |
| assert i.sub_attr == 24 |
| assert i.class_var == "x" |
| assert i.subclass_var == "y" |
| assert i.four == None |
| |
| assert i.__class__ == GetAttrInherited |
| |
| i.extra_attrs["sub_attr"] = (4, 4, 4) |
| assert i.__getattr__("sub_attr") == (4, 4, 4) |
| assert getattr(i, "sub_attr") == 24 |
| assert i.sub_attr == 24 |
| |
| base_ref: GetAttr = i |
| assert getattr(base_ref, "sub_attr") == 24 |
| assert base_ref.sub_attr == 24 |
| |
| assert getattr(base_ref, "subclass_var") == "y" |
| assert base_ref.subclass_var == "y" |
| |
| assert getattr(base_ref, "new") == None |
| assert base_ref.new == None |
| |
| assert base_ref.__class__ == GetAttrInherited |
| |
| |
| def test_getattr_overridden() -> None: |
| i = GetAttrOverridden({"one": 1, "two": "two", "three": 3.14}, 42, 24) |
| assert i.__getattr__("one") == "one" |
| assert i.__getattr__("regular_attr") == "regular_attr" |
| assert i.__getattr__("sub_attr") == "sub_attr" |
| assert i.__getattr__("class_var") == "class_var" |
| assert i.__getattr__("subclass_var") == "subclass_var" |
| assert i.__getattr__("four") == "four" |
| |
| assert getattr(i, "two") == "two" |
| assert getattr(i, "regular_attr") == 42 |
| assert getattr(i, "sub_attr") == 24 |
| assert getattr(i, "class_var") == "x" |
| assert getattr(i, "subclass_var") == "y" |
| assert getattr(i, "four") == "four" |
| |
| assert i.three == "three" |
| assert i.regular_attr == 42 |
| assert i.sub_attr == 24 |
| assert i.class_var == "x" |
| assert i.subclass_var == "y" |
| assert i.four == "four" |
| |
| assert i.__class__ == GetAttrOverridden |
| |
| i.extra_attrs["subclass_var"] = (4, 4, 4) |
| assert i.__getattr__("subclass_var") == "subclass_var" |
| assert getattr(i, "subclass_var") == "y" |
| assert i.subclass_var == "y" |
| |
| base_ref: GetAttr = i |
| assert getattr(base_ref, "sub_attr") == 24 |
| assert base_ref.sub_attr == 24 |
| |
| assert getattr(base_ref, "subclass_var") == "y" |
| assert base_ref.subclass_var == "y" |
| |
| assert getattr(base_ref, "new") == "new" |
| assert base_ref.new == "new" |
| |
| assert base_ref.__class__ == GetAttrOverridden |
| |
| def test_getattr_nonnative() -> None: |
| i = GetAttr({"one": 1, "two": "two", "three": 3.14}, 42) |
| assert i.__getattr__("one") == 1 |
| assert i.__getattr__("regular_attr") == None |
| assert i.__getattr__("class_var") == None |
| assert i.__getattr__("four") == None |
| |
| assert getattr(i, "two") == "two" |
| assert getattr(i, "regular_attr") == 42 |
| assert getattr(i, "class_var") == "x" |
| assert getattr(i, "four") == None |
| |
| assert i.three == 3.14 |
| assert i.regular_attr == 42 |
| assert i.class_var == "x" |
| assert i.four == None |
| |
| assert i.__class__ == GetAttr |
| |
| i.extra_attrs["regular_attr"] = (4, 4, 4) |
| assert i.__getattr__("regular_attr") == (4, 4, 4) |
| assert getattr(i, "regular_attr") == 42 |
| assert i.regular_attr == 42 |
| |
| [typing fixtures/typing-full.pyi] |
| |
| [case testDunderGetAttrInterpreted] |
| from mypy_extensions import mypyc_attr |
| from typing import ClassVar |
| |
| class GetAttr: |
| class_var = "x" |
| |
| def __init__(self, extra_attrs: dict[str, object], regular_attr: int): |
| self.extra_attrs = extra_attrs |
| self.regular_attr = regular_attr |
| |
| def __getattr__(self, attr: str) -> object: |
| return self.extra_attrs.get(attr) |
| |
| class GetAttrDefault: |
| class_var: ClassVar[str] = "x" |
| |
| def __init__(self, extra_attrs: dict[str, object], regular_attr: int): |
| self.extra_attrs = extra_attrs |
| self.regular_attr = regular_attr |
| |
| def __getattr__(self, attr: str, default: int = 8, mult: int = 1) -> object: |
| return self.extra_attrs.get(attr, default * mult) |
| |
| class GetAttrInherited(GetAttr): |
| subclass_var = "y" |
| |
| def __init__(self, extra_attrs: dict[str, object], regular_attr: int, sub_attr: int): |
| super().__init__(extra_attrs, regular_attr) |
| self.sub_attr = sub_attr |
| |
| class GetAttrOverridden(GetAttr): |
| subclass_var: ClassVar[str] = "y" |
| |
| def __init__(self, extra_attrs: dict[str, object], regular_attr: int, sub_attr: int): |
| super().__init__(extra_attrs, regular_attr) |
| self.sub_attr = sub_attr |
| |
| def __getattr__(self, attr: str) -> str: |
| return attr |
| |
| @mypyc_attr(native_class=False) |
| class GetAttrNonNative: |
| class_var = "x" |
| |
| def __init__(self, extra_attrs: dict[str, object], regular_attr: int): |
| self.extra_attrs = extra_attrs |
| self.regular_attr = regular_attr |
| |
| def __getattr__(self, attr: str) -> object: |
| return self.extra_attrs.get(attr) |
| |
| [file driver.py] |
| from native import GetAttr, GetAttrDefault, GetAttrInherited, GetAttrOverridden, GetAttrNonNative |
| |
| def test_getattr() -> None: |
| i = GetAttr({"one": 1, "two": "two", "three": 3.14}, 42) |
| assert i.__getattr__("one") == 1 |
| assert i.__getattr__("regular_attr") == None |
| assert i.__getattr__("class_var") == None |
| assert i.__getattr__("four") == None |
| |
| assert getattr(i, "two") == "two" |
| assert getattr(i, "regular_attr") == 42 |
| assert getattr(i, "class_var") == "x" |
| assert getattr(i, "four") == None |
| |
| assert i.three == 3.14 |
| assert i.regular_attr == 42 |
| assert i.class_var == "x" |
| assert i.four == None |
| |
| assert i.__class__ == GetAttr |
| |
| i.extra_attrs["regular_attr"] = (4, 4, 4) |
| assert i.__getattr__("regular_attr") == (4, 4, 4) |
| assert getattr(i, "regular_attr") == 42 |
| assert i.regular_attr == 42 |
| |
| def test_getattr_default() -> None: |
| i = GetAttrDefault({"one": 1, "two": "two", "three": 3.14}, 42) |
| assert i.__getattr__("one") == 1 |
| assert i.__getattr__("regular_attr") == 8 |
| assert i.__getattr__("class_var") == 8 |
| assert i.__getattr__("four", 4, 3) == 12 |
| |
| assert getattr(i, "two") == "two" |
| assert getattr(i, "regular_attr") == 42 |
| assert getattr(i, "class_var") == "x" |
| assert getattr(i, "four") == 8 |
| |
| assert i.three == 3.14 |
| assert i.regular_attr == 42 |
| assert i.class_var == "x" |
| assert i.four == 8 |
| |
| assert i.__class__ == GetAttrDefault |
| |
| i.extra_attrs["class_var"] = (4, 4, 4) |
| assert i.__getattr__("class_var") == (4, 4, 4) |
| assert getattr(i, "class_var") == "x" |
| assert i.class_var == "x" |
| |
| def test_getattr_inherited() -> None: |
| i = GetAttrInherited({"one": 1, "two": "two", "three": 3.14}, 42, 24) |
| assert i.__getattr__("one") == 1 |
| assert i.__getattr__("regular_attr") == None |
| assert i.__getattr__("sub_attr") == None |
| assert i.__getattr__("class_var") == None |
| assert i.__getattr__("subclass_var") == None |
| assert i.__getattr__("four") == None |
| |
| assert getattr(i, "two") == "two" |
| assert getattr(i, "regular_attr") == 42 |
| assert getattr(i, "sub_attr") == 24 |
| assert getattr(i, "class_var") == "x" |
| assert getattr(i, "subclass_var") == "y" |
| assert getattr(i, "four") == None |
| |
| assert i.three == 3.14 |
| assert i.regular_attr == 42 |
| assert i.sub_attr == 24 |
| assert i.class_var == "x" |
| assert i.subclass_var == "y" |
| assert i.four == None |
| |
| assert i.__class__ == GetAttrInherited |
| |
| i.extra_attrs["sub_attr"] = (4, 4, 4) |
| assert i.__getattr__("sub_attr") == (4, 4, 4) |
| assert getattr(i, "sub_attr") == 24 |
| assert i.sub_attr == 24 |
| |
| base_ref: GetAttr = i |
| assert getattr(base_ref, "sub_attr") == 24 |
| assert base_ref.sub_attr == 24 |
| |
| assert getattr(base_ref, "subclass_var") == "y" |
| assert base_ref.subclass_var == "y" |
| |
| assert getattr(base_ref, "new") == None |
| assert base_ref.new == None |
| |
| assert base_ref.__class__ == GetAttrInherited |
| |
| |
| def test_getattr_overridden() -> None: |
| i = GetAttrOverridden({"one": 1, "two": "two", "three": 3.14}, 42, 24) |
| assert i.__getattr__("one") == "one" |
| assert i.__getattr__("regular_attr") == "regular_attr" |
| assert i.__getattr__("sub_attr") == "sub_attr" |
| assert i.__getattr__("class_var") == "class_var" |
| assert i.__getattr__("subclass_var") == "subclass_var" |
| assert i.__getattr__("four") == "four" |
| |
| assert getattr(i, "two") == "two" |
| assert getattr(i, "regular_attr") == 42 |
| assert getattr(i, "sub_attr") == 24 |
| assert getattr(i, "class_var") == "x" |
| assert getattr(i, "subclass_var") == "y" |
| assert getattr(i, "four") == "four" |
| |
| assert i.three == "three" |
| assert i.regular_attr == 42 |
| assert i.sub_attr == 24 |
| assert i.class_var == "x" |
| assert i.subclass_var == "y" |
| assert i.four == "four" |
| |
| assert i.__class__ == GetAttrOverridden |
| |
| i.extra_attrs["subclass_var"] = (4, 4, 4) |
| assert i.__getattr__("subclass_var") == "subclass_var" |
| assert getattr(i, "subclass_var") == "y" |
| assert i.subclass_var == "y" |
| |
| base_ref: GetAttr = i |
| assert getattr(base_ref, "sub_attr") == 24 |
| assert base_ref.sub_attr == 24 |
| |
| assert getattr(base_ref, "subclass_var") == "y" |
| assert base_ref.subclass_var == "y" |
| |
| assert getattr(base_ref, "new") == "new" |
| assert base_ref.new == "new" |
| |
| assert base_ref.__class__ == GetAttrOverridden |
| |
| def test_getattr_nonnative() -> None: |
| i = GetAttr({"one": 1, "two": "two", "three": 3.14}, 42) |
| assert i.__getattr__("one") == 1 |
| assert i.__getattr__("regular_attr") == None |
| assert i.__getattr__("class_var") == None |
| assert i.__getattr__("four") == None |
| |
| assert getattr(i, "two") == "two" |
| assert getattr(i, "regular_attr") == 42 |
| assert getattr(i, "class_var") == "x" |
| assert getattr(i, "four") == None |
| |
| assert i.three == 3.14 |
| assert i.regular_attr == 42 |
| assert i.class_var == "x" |
| assert i.four == None |
| |
| assert i.__class__ == GetAttr |
| |
| i.extra_attrs["regular_attr"] = (4, 4, 4) |
| assert i.__getattr__("regular_attr") == (4, 4, 4) |
| assert getattr(i, "regular_attr") == 42 |
| assert i.regular_attr == 42 |
| |
| test_getattr() |
| test_getattr_default() |
| test_getattr_inherited() |
| test_getattr_overridden() |
| test_getattr_nonnative() |
| |
| [typing fixtures/typing-full.pyi] |
| |
| [case testDunderSetAttr] |
| from mypy_extensions import mypyc_attr |
| from testutil import assertRaises |
| from typing import ClassVar |
| |
| class SetAttr: |
| _attributes: dict[str, object] |
| regular_attr: int |
| class_var: ClassVar[str] = "x" |
| const: int = 42 |
| |
| def __init__(self, regular_attr: int, extra_attrs: dict[str, object]) -> None: |
| super().__setattr__("_attributes", extra_attrs) |
| super().__setattr__("regular_attr", regular_attr) |
| |
| def __setattr__(self, key: str, val: object) -> None: |
| if key == "regular_attr": |
| super().__setattr__("regular_attr", val) |
| elif key == "class_var" or key == "const": |
| raise AttributeError() |
| else: |
| self._attributes[key] = val |
| |
| def __getattr__(self, key: str) -> object: |
| return self._attributes.get(key) |
| |
| class SetAttrInherited(SetAttr): |
| def __init__(self, regular_attr: int, extra_attrs: dict[str, object]) -> None: |
| super().__init__(regular_attr, extra_attrs) |
| |
| class SetAttrOverridden(SetAttr): |
| sub_attr: int |
| subclass_var: ClassVar[str] = "y" |
| |
| def __init__(self, regular_attr: int, sub_attr: int, extra_attrs: dict[str, object]) -> None: |
| super().__init__(regular_attr, extra_attrs) |
| object.__setattr__(self, "sub_attr", sub_attr) |
| |
| def __setattr__(self, key: str, val: object) -> None: |
| if key == "sub_attr": |
| object.__setattr__(self, "sub_attr", val) |
| elif key == "subclass_var": |
| raise AttributeError() |
| else: |
| super().__setattr__(key, val) |
| |
| def __delattr__(self, key: str) -> None: |
| del self._attributes[key] |
| |
| @mypyc_attr(native_class=False) |
| class SetAttrNonNative: |
| _attributes: dict[str, object] |
| regular_attr: int |
| class_var: ClassVar[str] = "x" |
| const: int = 42 |
| |
| def __init__(self, regular_attr: int, extra_attrs: dict[str, object]) -> None: |
| super().__setattr__("_attributes", extra_attrs) |
| super().__setattr__("regular_attr", regular_attr) |
| |
| def __setattr__(self, key: str, val: object) -> None: |
| if key == "regular_attr": |
| super().__setattr__("regular_attr", val) |
| elif key == "class_var" or key == "const": |
| raise AttributeError() |
| else: |
| self._attributes[key] = val |
| |
| def __getattr__(self, key: str) -> object: |
| return self._attributes.get(key) |
| |
| class NoSetAttr: |
| def __init__(self, attr: int) -> None: |
| self.attr = attr |
| |
| def object_setattr(self, attr: str, val: object) -> None: |
| object.__setattr__(self, attr, val) |
| |
| def super_setattr(self, attr: str, val: object) -> None: |
| super().__setattr__(attr, val) |
| |
| @mypyc_attr(native_class=False) |
| class NoSetAttrNonNative: |
| def __init__(self, attr: int) -> None: |
| self.attr = attr |
| |
| def object_setattr(self, attr: str, val: object) -> None: |
| object.__setattr__(self, attr, val) |
| |
| def super_setattr(self, attr: str, val: object) -> None: |
| super().__setattr__(attr, val) |
| |
| def __getattr__(self, attr: str) -> object: |
| pass |
| |
| def test_setattr() -> None: |
| i = SetAttr(99, {"one": 1}) |
| assert i.class_var == "x" |
| assert i.regular_attr == 99 |
| assert i.one == 1 |
| assert i.two == None |
| assert i.const == 42 |
| |
| i.__setattr__("two", "2") |
| assert i.two == "2" |
| i.__setattr__("regular_attr", 101) |
| assert i.regular_attr == 101 |
| with assertRaises(AttributeError): |
| i.__setattr__("class_var", "y") |
| with assertRaises(AttributeError): |
| i.__setattr__("const", 43) |
| |
| setattr(i, "three", (3,3,3)) |
| assert i.three == (3,3,3) |
| setattr(i, "regular_attr", 102) |
| assert i.regular_attr == 102 |
| with assertRaises(AttributeError): |
| setattr(i, "class_var", "z") |
| with assertRaises(AttributeError): |
| setattr(i, "const", 44) |
| |
| i.four = [4,4] |
| assert i.four == [4,4] |
| i.regular_attr = 103 |
| assert i.regular_attr == 103 |
| with assertRaises(AttributeError): |
| i.const = 45 |
| |
| # Doesn't work because there's no __delattr__. |
| with assertRaises(AttributeError): |
| del i.four |
| |
| def test_setattr_inherited() -> None: |
| i = SetAttrInherited(99, {"one": 1}) |
| assert i.class_var == "x" |
| assert i.regular_attr == 99 |
| assert i.one == 1 |
| assert i.two == None |
| assert i.const == 42 |
| |
| i.__setattr__("two", "2") |
| assert i.two == "2" |
| i.__setattr__("regular_attr", 101) |
| assert i.regular_attr == 101 |
| with assertRaises(AttributeError): |
| i.__setattr__("class_var", "y") |
| with assertRaises(AttributeError): |
| i.__setattr__("const", 43) |
| |
| setattr(i, "three", (3,3,3)) |
| assert i.three == (3,3,3) |
| setattr(i, "regular_attr", 102) |
| assert i.regular_attr == 102 |
| with assertRaises(AttributeError): |
| setattr(i, "class_var", "z") |
| with assertRaises(AttributeError): |
| setattr(i, "const", 44) |
| |
| i.four = [4,4] |
| assert i.four == [4,4] |
| i.regular_attr = 103 |
| assert i.regular_attr == 103 |
| with assertRaises(AttributeError): |
| i.const = 45 |
| |
| # Doesn't work because there's no __delattr__. |
| with assertRaises(AttributeError): |
| del i.four |
| |
| def test_setattr_overridden() -> None: |
| i = SetAttrOverridden(99, 1, {"one": 1}) |
| assert i.class_var == "x" |
| assert i.subclass_var == "y" |
| assert i.regular_attr == 99 |
| assert i.sub_attr == 1 |
| assert i.one == 1 |
| assert i.two == None |
| assert i.const == 42 |
| |
| i.__setattr__("two", "2") |
| assert i.two == "2" |
| i.__setattr__("regular_attr", 101) |
| assert i.regular_attr == 101 |
| i.__setattr__("sub_attr", 2) |
| assert i.sub_attr == 2 |
| with assertRaises(AttributeError): |
| i.__setattr__("class_var", "y") |
| with assertRaises(AttributeError): |
| i.__setattr__("subclass_var", "a") |
| with assertRaises(AttributeError): |
| i.__setattr__("const", 43) |
| |
| setattr(i, "three", (3,3,3)) |
| assert i.three == (3,3,3) |
| setattr(i, "regular_attr", 102) |
| assert i.regular_attr == 102 |
| setattr(i, "sub_attr", 3) |
| assert i.sub_attr == 3 |
| with assertRaises(AttributeError): |
| setattr(i, "class_var", "z") |
| with assertRaises(AttributeError): |
| setattr(i, "subclass_var", "b") |
| with assertRaises(AttributeError): |
| setattr(i, "const", 44) |
| |
| i.four = [4,4] |
| assert i.four == [4,4] |
| i.regular_attr = 103 |
| assert i.regular_attr == 103 |
| i.sub_attr = 4 |
| assert i.sub_attr == 4 |
| with assertRaises(AttributeError): |
| i.const = 45 |
| |
| del i.four |
| assert "four" not in i._attributes |
| |
| delattr(i, "three") |
| assert "three" not in i._attributes |
| |
| i.__delattr__("two") |
| assert "two" not in i._attributes |
| |
| base_ref: SetAttr = i |
| setattr(base_ref, "sub_attr", 5) |
| assert base_ref.sub_attr == 5 |
| |
| base_ref.sub_attr = 6 |
| assert base_ref.sub_attr == 6 |
| |
| with assertRaises(AttributeError): |
| setattr(base_ref, "subclass_var", "c") |
| |
| base_ref.new_attr = "new_attr" |
| assert base_ref.new_attr == "new_attr" |
| |
| del base_ref.new_attr |
| assert "new_attr" not in base_ref._attributes |
| |
| def test_setattr_nonnative() -> None: |
| i = SetAttrNonNative(99, {"one": 1}) |
| assert i.class_var == "x" |
| assert i.regular_attr == 99 |
| assert i.one == 1 |
| assert i.two == None |
| assert i.const == 42 |
| |
| i.__setattr__("two", "2") |
| assert i.two == "2" |
| i.__setattr__("regular_attr", 101) |
| assert i.regular_attr == 101 |
| with assertRaises(AttributeError): |
| i.__setattr__("class_var", "y") |
| with assertRaises(AttributeError): |
| i.__setattr__("const", 43) |
| |
| setattr(i, "three", (3,3,3)) |
| assert i.three == (3,3,3) |
| setattr(i, "regular_attr", 102) |
| assert i.regular_attr == 102 |
| with assertRaises(AttributeError): |
| setattr(i, "class_var", "z") |
| with assertRaises(AttributeError): |
| setattr(i, "const", 44) |
| |
| i.four = [4,4] |
| assert i.four == [4,4] |
| i.regular_attr = 103 |
| assert i.regular_attr == 103 |
| with assertRaises(AttributeError): |
| i.const = 45 |
| |
| # Doesn't work because there's no __delattr__. |
| with assertRaises(AttributeError): |
| del i.four |
| |
| def test_no_setattr() -> None: |
| i = NoSetAttr(99) |
| i.super_setattr("attr", 100) |
| assert i.attr == 100 |
| |
| i.object_setattr("attr", 101) |
| assert i.attr == 101 |
| |
| object.__setattr__(i, "attr", 102) |
| assert i.attr == 102 |
| |
| with assertRaises(AttributeError): |
| i.super_setattr("not_attr", 100) |
| |
| with assertRaises(AttributeError): |
| i.object_setattr("not_attr", 101) |
| |
| with assertRaises(AttributeError): |
| object.__setattr__(i, "not_attr", 102) |
| |
| def test_no_setattr_nonnative() -> None: |
| i = NoSetAttrNonNative(99) |
| i.super_setattr("attr", 100) |
| assert i.attr == 100 |
| |
| i.object_setattr("attr", 101) |
| assert i.attr == 101 |
| |
| object.__setattr__(i, "attr", 102) |
| assert i.attr == 102 |
| |
| i.super_setattr("one", 100) |
| assert i.one == 100 |
| |
| i.object_setattr("two", 101) |
| assert i.two == 101 |
| |
| object.__setattr__(i, "three", 102) |
| assert i.three == 102 |
| |
| del i.three |
| assert i.three == None |
| |
| delattr(i, "two") |
| assert i.two == None |
| |
| object.__delattr__(i, "one") |
| assert i.one == None |
| |
| [typing fixtures/typing-full.pyi] |
| |
| [case testDunderSetAttrInterpreted] |
| from mypy_extensions import mypyc_attr |
| from typing import ClassVar |
| |
| class SetAttr: |
| _attributes: dict[str, object] |
| regular_attr: int |
| class_var: ClassVar[str] = "x" |
| const: int = 42 |
| |
| def __init__(self, regular_attr: int, extra_attrs: dict[str, object]) -> None: |
| super().__setattr__("_attributes", extra_attrs) |
| super().__setattr__("regular_attr", regular_attr) |
| |
| def __setattr__(self, key: str, val: object) -> None: |
| if key == "regular_attr": |
| super().__setattr__("regular_attr", val) |
| elif key == "class_var" or key == "const": |
| raise AttributeError() |
| else: |
| self._attributes[key] = val |
| |
| def __getattr__(self, key: str) -> object: |
| return self._attributes.get(key) |
| |
| class SetAttrInherited(SetAttr): |
| def __init__(self, regular_attr: int, extra_attrs: dict[str, object]) -> None: |
| super().__init__(regular_attr, extra_attrs) |
| |
| class SetAttrOverridden(SetAttr): |
| sub_attr: int |
| subclass_var: ClassVar[str] = "y" |
| |
| def __init__(self, regular_attr: int, sub_attr: int, extra_attrs: dict[str, object]) -> None: |
| super().__init__(regular_attr, extra_attrs) |
| object.__setattr__(self, "sub_attr", sub_attr) |
| |
| def __setattr__(self, key: str, val: object) -> None: |
| if key == "sub_attr": |
| object.__setattr__(self, "sub_attr", val) |
| elif key == "subclass_var": |
| raise AttributeError() |
| else: |
| super().__setattr__(key, val) |
| |
| def __delattr__(self, key: str) -> None: |
| del self._attributes[key] |
| |
| @mypyc_attr(native_class=False) |
| class SetAttrNonNative: |
| _attributes: dict[str, object] |
| regular_attr: int |
| class_var: ClassVar[str] = "x" |
| const: int = 42 |
| |
| def __init__(self, regular_attr: int, extra_attrs: dict[str, object]) -> None: |
| super().__setattr__("_attributes", extra_attrs) |
| super().__setattr__("regular_attr", regular_attr) |
| |
| def __setattr__(self, key: str, val: object) -> None: |
| if key == "regular_attr": |
| super().__setattr__("regular_attr", val) |
| elif key == "class_var" or key == "const": |
| raise AttributeError() |
| else: |
| self._attributes[key] = val |
| |
| def __getattr__(self, key: str) -> object: |
| return self._attributes.get(key) |
| |
| class NoSetAttr: |
| def __init__(self, attr: int) -> None: |
| self.attr = attr |
| |
| def object_setattr(self, attr: str, val: object) -> None: |
| object.__setattr__(self, attr, val) |
| |
| def super_setattr(self, attr: str, val: object) -> None: |
| super().__setattr__(attr, val) |
| |
| @mypyc_attr(native_class=False) |
| class NoSetAttrNonNative: |
| def __init__(self, attr: int) -> None: |
| self.attr = attr |
| |
| def object_setattr(self, attr: str, val: object) -> None: |
| object.__setattr__(self, attr, val) |
| |
| def super_setattr(self, attr: str, val: object) -> None: |
| super().__setattr__(attr, val) |
| |
| def __getattr__(self, attr: str) -> object: |
| pass |
| |
| [file driver.py] |
| from native import SetAttr, SetAttrInherited, SetAttrOverridden, SetAttrNonNative, NoSetAttr, NoSetAttrNonNative |
| from testutil import assertRaises |
| |
| def test_setattr() -> None: |
| i = SetAttr(99, {"one": 1}) |
| assert i.class_var == "x" |
| assert i.regular_attr == 99 |
| assert i.one == 1 |
| assert i.two == None |
| assert i.const == 42 |
| |
| i.__setattr__("two", "2") |
| assert i.two == "2" |
| i.__setattr__("regular_attr", 101) |
| assert i.regular_attr == 101 |
| with assertRaises(AttributeError): |
| i.__setattr__("class_var", "y") |
| with assertRaises(AttributeError): |
| i.__setattr__("const", 43) |
| |
| setattr(i, "three", (3,3,3)) |
| assert i.three == (3,3,3) |
| setattr(i, "regular_attr", 102) |
| assert i.regular_attr == 102 |
| with assertRaises(AttributeError): |
| setattr(i, "class_var", "z") |
| with assertRaises(AttributeError): |
| setattr(i, "const", 44) |
| |
| i.four = [4,4] |
| assert i.four == [4,4] |
| i.regular_attr = 103 |
| assert i.regular_attr == 103 |
| with assertRaises(AttributeError): |
| i.const = 45 |
| |
| # Doesn't work because there's no __delattr__. |
| with assertRaises(AttributeError): |
| del i.four |
| |
| def test_setattr_inherited() -> None: |
| i = SetAttrInherited(99, {"one": 1}) |
| assert i.class_var == "x" |
| assert i.regular_attr == 99 |
| assert i.one == 1 |
| assert i.two == None |
| assert i.const == 42 |
| |
| i.__setattr__("two", "2") |
| assert i.two == "2" |
| i.__setattr__("regular_attr", 101) |
| assert i.regular_attr == 101 |
| with assertRaises(AttributeError): |
| i.__setattr__("class_var", "y") |
| with assertRaises(AttributeError): |
| i.__setattr__("const", 43) |
| |
| setattr(i, "three", (3,3,3)) |
| assert i.three == (3,3,3) |
| setattr(i, "regular_attr", 102) |
| assert i.regular_attr == 102 |
| with assertRaises(AttributeError): |
| setattr(i, "class_var", "z") |
| with assertRaises(AttributeError): |
| setattr(i, "const", 44) |
| |
| i.four = [4,4] |
| assert i.four == [4,4] |
| i.regular_attr = 103 |
| assert i.regular_attr == 103 |
| with assertRaises(AttributeError): |
| i.const = 45 |
| |
| # Doesn't work because there's no __delattr__. |
| with assertRaises(AttributeError): |
| del i.four |
| |
| def test_setattr_overridden() -> None: |
| i = SetAttrOverridden(99, 1, {"one": 1}) |
| assert i.class_var == "x" |
| assert i.subclass_var == "y" |
| assert i.regular_attr == 99 |
| assert i.sub_attr == 1 |
| assert i.one == 1 |
| assert i.two == None |
| assert i.const == 42 |
| |
| i.__setattr__("two", "2") |
| assert i.two == "2" |
| i.__setattr__("regular_attr", 101) |
| assert i.regular_attr == 101 |
| i.__setattr__("sub_attr", 2) |
| assert i.sub_attr == 2 |
| with assertRaises(AttributeError): |
| i.__setattr__("class_var", "y") |
| with assertRaises(AttributeError): |
| i.__setattr__("subclass_var", "a") |
| with assertRaises(AttributeError): |
| i.__setattr__("const", 43) |
| |
| setattr(i, "three", (3,3,3)) |
| assert i.three == (3,3,3) |
| setattr(i, "regular_attr", 102) |
| assert i.regular_attr == 102 |
| setattr(i, "sub_attr", 3) |
| assert i.sub_attr == 3 |
| with assertRaises(AttributeError): |
| setattr(i, "class_var", "z") |
| with assertRaises(AttributeError): |
| setattr(i, "subclass_var", "b") |
| with assertRaises(AttributeError): |
| setattr(i, "const", 44) |
| |
| i.four = [4,4] |
| assert i.four == [4,4] |
| i.regular_attr = 103 |
| assert i.regular_attr == 103 |
| i.sub_attr = 4 |
| assert i.sub_attr == 4 |
| with assertRaises(AttributeError): |
| i.const = 45 |
| |
| del i.four |
| assert "four" not in i._attributes |
| |
| delattr(i, "three") |
| assert "three" not in i._attributes |
| |
| i.__delattr__("two") |
| assert "two" not in i._attributes |
| |
| base_ref: SetAttr = i |
| setattr(base_ref, "sub_attr", 5) |
| assert base_ref.sub_attr == 5 |
| |
| base_ref.sub_attr = 6 |
| assert base_ref.sub_attr == 6 |
| |
| with assertRaises(AttributeError): |
| setattr(base_ref, "subclass_var", "c") |
| |
| base_ref.new_attr = "new_attr" |
| assert base_ref.new_attr == "new_attr" |
| |
| del base_ref.new_attr |
| assert "new_attr" not in base_ref._attributes |
| |
| def test_setattr_nonnative() -> None: |
| i = SetAttrNonNative(99, {"one": 1}) |
| assert i.class_var == "x" |
| assert i.regular_attr == 99 |
| assert i.one == 1 |
| assert i.two == None |
| assert i.const == 42 |
| |
| i.__setattr__("two", "2") |
| assert i.two == "2" |
| i.__setattr__("regular_attr", 101) |
| assert i.regular_attr == 101 |
| with assertRaises(AttributeError): |
| i.__setattr__("class_var", "y") |
| with assertRaises(AttributeError): |
| i.__setattr__("const", 43) |
| |
| setattr(i, "three", (3,3,3)) |
| assert i.three == (3,3,3) |
| setattr(i, "regular_attr", 102) |
| assert i.regular_attr == 102 |
| with assertRaises(AttributeError): |
| setattr(i, "class_var", "z") |
| with assertRaises(AttributeError): |
| setattr(i, "const", 44) |
| |
| i.four = [4,4] |
| assert i.four == [4,4] |
| i.regular_attr = 103 |
| assert i.regular_attr == 103 |
| with assertRaises(AttributeError): |
| i.const = 45 |
| |
| # Doesn't work because there's no __delattr__. |
| with assertRaises(AttributeError): |
| del i.four |
| |
| def test_no_setattr() -> None: |
| i = NoSetAttr(99) |
| i.super_setattr("attr", 100) |
| assert i.attr == 100 |
| |
| i.object_setattr("attr", 101) |
| assert i.attr == 101 |
| |
| object.__setattr__(i, "attr", 102) |
| assert i.attr == 102 |
| |
| with assertRaises(AttributeError): |
| i.super_setattr("not_attr", 100) |
| |
| with assertRaises(AttributeError): |
| i.object_setattr("not_attr", 101) |
| |
| with assertRaises(AttributeError): |
| object.__setattr__(i, "not_attr", 102) |
| |
| def test_no_setattr_nonnative() -> None: |
| i = NoSetAttrNonNative(99) |
| i.super_setattr("attr", 100) |
| assert i.attr == 100 |
| |
| i.object_setattr("attr", 101) |
| assert i.attr == 101 |
| |
| object.__setattr__(i, "attr", 102) |
| assert i.attr == 102 |
| |
| i.super_setattr("one", 100) |
| assert i.one == 100 |
| |
| i.object_setattr("two", 101) |
| assert i.two == 101 |
| |
| object.__setattr__(i, "three", 102) |
| assert i.three == 102 |
| |
| del i.three |
| assert i.three == None |
| |
| delattr(i, "two") |
| assert i.two == None |
| |
| object.__delattr__(i, "one") |
| assert i.one == None |
| |
| test_setattr() |
| test_setattr_inherited() |
| test_setattr_overridden() |
| test_setattr_nonnative() |
| test_no_setattr() |
| test_no_setattr_nonnative() |
| |
| [typing fixtures/typing-full.pyi] |
| |
| [case testDelAttrWithDeletableAttr] |
| from testutil import assertRaises |
| |
| class DelAttr: |
| __deletable__ = ["del_counter"] |
| |
| _attributes: dict[str, object] |
| del_counter: int = 0 |
| |
| def __init__(self) -> None: |
| object.__setattr__(self, "_attributes", {}) |
| |
| def __setattr__(self, key: str, val: object) -> None: |
| if key == "del_counter": |
| object.__setattr__(self, "del_counter", val) |
| else: |
| self._attributes[key] = val |
| |
| def __delattr__(self, key: str) -> None: |
| if key == "del_counter": |
| self.del_counter += 1 |
| else: |
| del self._attributes[key] |
| |
| def test_deletable_attr() -> None: |
| i = DelAttr() |
| assert i.del_counter == 0 |
| del i.del_counter |
| assert i.del_counter == 1 |
| |
| [case testDelAttrWithDeletableAttrInterpreted] |
| class DelAttr: |
| __deletable__ = ["del_counter"] |
| |
| _attributes: dict[str, object] |
| del_counter: int = 0 |
| |
| def __init__(self) -> None: |
| object.__setattr__(self, "_attributes", {}) |
| |
| def __setattr__(self, key: str, val: object) -> None: |
| if key == "del_counter": |
| object.__setattr__(self, "del_counter", val) |
| else: |
| self._attributes[key] = val |
| |
| def __delattr__(self, key: str) -> None: |
| if key == "del_counter": |
| self.del_counter += 1 |
| else: |
| del self._attributes[key] |
| |
| [file driver.py] |
| from native import DelAttr |
| from testutil import assertRaises |
| |
| def test_deletable_attr() -> None: |
| i = DelAttr() |
| assert i.del_counter == 0 |
| del i.del_counter |
| assert i.del_counter == 1 |
| |
| test_deletable_attr() |