| -- Test cases for generating fine-grained dependencies for classes. |
| -- |
| -- The dependencies are used for fined-grained incremental checking. |
| -- |
| -- See the comment at the top of deps.test for more documentation. |
| |
| -- TODO: Move class related test cases from deps.test to here |
| |
| [case testNamedTuple] |
| from typing import NamedTuple, Any |
| from a import A |
| N = NamedTuple('N', [('a', 'A')]) |
| |
| def f(a: Any) -> None: |
| n = N(a) |
| n.a |
| [file a.py] |
| class A: pass |
| [builtins fixtures/tuple.pyi] |
| [out] |
| <m.N.__init__> -> m.f |
| <m.N.__new__> -> m.f |
| <m.N.a> -> m.f |
| <m.N> -> m.f |
| <a.A> -> <m.N.a>, <m.N>, m |
| <a> -> m |
| |
| [case testNamedTuple2] |
| from typing import NamedTuple, Any, Tuple |
| from a import A, B |
| N = NamedTuple('N', [('a', 'Tuple[A, B]')]) |
| |
| def f(a: Any) -> None: |
| n = N(a) |
| n.a |
| [file a.py] |
| class A: pass |
| class B: pass |
| [builtins fixtures/tuple.pyi] |
| [out] |
| <m.N.__init__> -> m.f |
| <m.N.__new__> -> m.f |
| <m.N.a> -> m.f |
| <m.N> -> m.f |
| <a.A> -> <m.N.a>, <m.N>, m |
| <a.B> -> <m.N.a>, <m.N>, m |
| <a> -> m |
| |
| [case testNamedTuple3] |
| from typing import NamedTuple |
| N = NamedTuple('N', [('x', int)]) |
| x = N(1) |
| M = NamedTuple('M', [('z', 'N')]) |
| y = M(x) |
| [builtins fixtures/tuple.pyi] |
| [out] |
| <m.M.__init__> -> m |
| <m.M.__new__> -> m |
| <m.M> -> <m.y>, m |
| <m.N.__init__> -> m |
| <m.N.__new__> -> m |
| <m.N> -> <m.M.z>, <m.M>, <m.x>, <m.y>, m |
| <m.x> -> m |
| <m.y> -> m |
| |
| [case testNamedTuple4] |
| from typing import NamedTuple, Any |
| from a import A |
| class N(NamedTuple): |
| a: A |
| |
| def f(a: Any) -> None: |
| n = N(a) |
| n.a |
| [file a.py] |
| class A: pass |
| [builtins fixtures/tuple.pyi] |
| [out] |
| <m.N.__init__> -> m.f |
| <m.N.__new__> -> m.f |
| <m.N.a> -> m.f |
| <m.N> -> m.N, m.f |
| <a.A> -> <m.N.a>, <m.N>, m, m.N |
| <a> -> m |
| |
| [case testIfFalseInClassBody] |
| class A: |
| if False: |
| x = None # type: str |
| x.foo() |
| [builtins fixtures/bool.pyi] |
| [out] |
| <m.A> -> m.A |
| |
| [case testAlwaysFalseIsinstanceInClassBody] |
| class A: |
| x: int |
| if isinstance(x, str): |
| y: str = None |
| y.foo() |
| [builtins fixtures/isinstance.pyi] |
| [out] |
| <m.A> -> m.A |
| |
| [case testDoubleAttributeInitializationToNone] |
| class C: |
| def __init__(self) -> None: |
| self.x = None |
| self.x = None |
| [out] |
| <m.C.x> -> m.C.__init__ |
| <m.C> -> m.C |
| |
| [case testClassNestedWithinFunction] |
| class C: pass |
| |
| def f() -> None: |
| class S1(C): pass |
| |
| class D: |
| def g(self) -> None: |
| class S2(C): pass |
| [out] |
| -- TODO: Is it okay to have targets like m.S1@4.__init__? |
| <m.C.(abstract)> -> <m.S1@4.__init__>, <m.S2@8.__init__>, m.D.g, m.f |
| <m.C.__init__> -> <m.S1@4.__init__>, <m.S2@8.__init__> |
| <m.C.__new__> -> <m.S1@4.__new__>, <m.S2@8.__new__> |
| <m.C> -> m.C, m.D.g, m.f |
| <m.D.g> -> m.D.g |
| <m.D> -> m.D |
| <m.f> -> m.f |
| |
| [case testClassSuper] |
| class C: |
| def __init__(self, x: int) -> None: pass |
| def foo(self) -> None: pass |
| |
| class D(C): |
| def __init__(self, x: int) -> None: |
| super().__init__(x) |
| super().foo() |
| [out] |
| <m.C.(abstract)> -> <m.D.__init__>, m |
| <m.C.__init__> -> <m.D.__init__>, m.D.__init__ |
| <m.C.__new__> -> <m.D.__new__> |
| <m.C.foo> -> <m.D.foo>, m.D.__init__ |
| <m.C> -> m, m.C, m.D |
| <m.D> -> m.D |
| |
| [case testClassMissingInit] |
| class C: |
| def __init__(self, x: int) -> None: pass |
| |
| class D(C): |
| pass |
| |
| def foo() -> None: |
| D(6) |
| [out] |
| <m.C.(abstract)> -> <m.D.__init__>, m |
| <m.C.__init__> -> <m.D.__init__> |
| <m.C.__new__> -> <m.D.__new__> |
| <m.C> -> m, m.C, m.D |
| <m.D.__init__> -> m.foo |
| <m.D.__new__> -> m.foo |
| <m.D> -> m.D, m.foo |
| |
| [case testClassBasedEnum] |
| from enum import Enum |
| from m import B |
| |
| class A(Enum): |
| X = B() |
| |
| def f(a: A) -> None: |
| pass |
| def g() -> None: |
| A.X |
| [file m.py] |
| class B: pass |
| [out] |
| <m.A.X> -> m.g |
| <m.A> -> <m.f>, m.A, m.f, m.g |
| <m.B.__init__> -> m |
| <m.B.__new__> -> m |
| -- The <m.A.X> dependency target is superfluous but benign |
| <m.B> -> <m.A.X>, m |
| <m> -> m |
| |
| [case testClassAttribute] |
| class C: |
| x = 0 |
| |
| def f() -> None: |
| C.x |
| |
| def g() -> None: |
| C.x = 1 |
| [out] |
| <m.C.x> -> m.f, m.g |
| <m.C> -> m.C, m.f, m.g |
| |
| [case testStaticAndClassMethods] |
| class C: |
| @staticmethod |
| def foo() -> None: |
| h() |
| |
| @classmethod |
| def bar(cls) -> None: |
| h() |
| |
| def fstatic() -> None: |
| C.foo() |
| |
| def fclass() -> None: |
| C.bar() |
| |
| cc = C() |
| |
| def gstatic() -> None: |
| cc.foo() |
| |
| def gclass() -> None: |
| cc.bar() |
| |
| def h() -> None: pass |
| [builtins fixtures/classmethod.pyi] |
| [out] |
| <m.C.__init__> -> m |
| <m.C.__new__> -> m |
| <m.C.bar> -> m, m.fclass, m.gclass |
| <m.C.foo> -> m, m.fstatic, m.gstatic |
| <m.C> -> <m.cc>, m, m.C, m.fclass, m.fstatic |
| <m.cc> -> m, m.gclass, m.gstatic |
| <m.h> -> m.C.bar, m.C.foo |
| |
| [case testClassAttributeWithMetaclass] |
| class M(type): |
| x = 1 |
| class C(metaclass=M): |
| pass |
| def f() -> None: |
| C.x |
| [out] |
| <m.C.x> -> m.f |
| <m.C> -> m.C, m.f |
| <m.M.x> -> m.f |
| <m.M> -> <m.C>, m, m.M |