| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732 |
- -- Test cases for always defined attributes.
- --
- -- If class C has attributes x and y that are always defined, the output will
- -- have a line like this:
- --
- -- C: [x, y]
- [case testAlwaysDefinedSimple]
- class C:
- def __init__(self, x: int) -> None:
- self.x = x
- [out]
- C: [x]
- [case testAlwaysDefinedFail]
- class MethodCall:
- def __init__(self, x: int) -> None:
- self.f()
- self.x = x
- def f(self) -> None:
- pass
- class FuncCall:
- def __init__(self, x: int) -> None:
- f(x)
- self.x = x
- f(self)
- self.y = x
- class GetAttr:
- x: int
- def __init__(self, x: int) -> None:
- a = self.x
- self.x = x
- class _Base:
- def __init__(self) -> None:
- f(self)
- class CallSuper(_Base):
- def __init__(self, x: int) -> None:
- super().__init__()
- self.x = x
- class Lambda:
- def __init__(self, x: int) -> None:
- f = lambda x: x + 1
- self.x = x
- g = lambda x: self
- self.y = x
- class If:
- def __init__(self, x: int) -> None:
- self.a = 1
- if x:
- self.x = x
- else:
- self.y = 1
- class Deletable:
- __deletable__ = ('x', 'y')
- def __init__(self) -> None:
- self.x = 0
- self.y = 1
- self.z = 2
- class PrimitiveWithSelf:
- def __init__(self, s: str) -> None:
- self.x = getattr(self, s)
- def f(a) -> None: pass
- [out]
- MethodCall: []
- FuncCall: [x]
- GetAttr: []
- CallSuper: []
- Lambda: []
- If: [a]
- Deletable: [z]
- PrimitiveWithSelf: []
- [case testAlwaysDefinedConditional]
- class IfAlways:
- def __init__(self, x: int, y: int) -> None:
- if x:
- self.x = x
- self.y = y
- elif y:
- self.x = y
- self.y = x
- else:
- self.x = 0
- self.y = 0
- self.z = 0
- class IfSometimes1:
- def __init__(self, x: int, y: int) -> None:
- if x:
- self.x = x
- self.y = y
- elif y:
- self.z = y
- self.y = x
- else:
- self.y = 0
- self.a = 0
- class IfSometimes2:
- def __init__(self, x: int, y: int) -> None:
- if x:
- self.x = x
- self.y = y
- class IfStopAnalysis1:
- def __init__(self, x: int, y: int) -> None:
- if x:
- self.x = x
- f(self)
- else:
- self.x = x
- self.y = y
- class IfStopAnalysis2:
- def __init__(self, x: int, y: int) -> None:
- if x:
- self.x = x
- else:
- self.x = x
- f(self)
- self.y = y
- class IfStopAnalysis3:
- def __init__(self, x: int, y: int) -> None:
- if x:
- self.x = x
- else:
- f(self)
- self.x = x
- self.y = y
- class IfConditionalAndNonConditional1:
- def __init__(self, x: int) -> None:
- self.x = 0
- if x:
- self.x = x
- class IfConditionalAndNonConditional2:
- def __init__(self, x: int) -> None:
- # x is not considered always defined, since the second assignment may
- # either initialize or update.
- if x:
- self.x = x
- self.x = 0
- def f(a) -> None: pass
- [out]
- IfAlways: [x, y, z]
- IfSometimes1: [y]
- IfSometimes2: [y]
- IfStopAnalysis1: [x]
- IfStopAnalysis2: [x]
- IfStopAnalysis3: []
- IfConditionalAndNonConditional1: [x]
- IfConditionalAndNonConditional2: []
- [case testAlwaysDefinedExpressions]
- from typing import Dict, List, Set, Optional, cast
- from typing_extensions import Final
- import other
- class C: pass
- class Collections:
- def __init__(self, x: int) -> None:
- self.l = [x]
- self.d: Dict[str, str] = {}
- self.s: Set[int] = set()
- self.d2 = {'x': x}
- self.s2 = {x}
- self.l2 = [f(), None] * x
- self.t = tuple(self.l2)
- class Comparisons:
- def __init__(self, y: int, c: C, s: str, o: Optional[str]) -> None:
- self.n1 = y < 5
- self.n2 = y == 5
- self.c1 = y is c
- self.c2 = y is not c
- self.o1 = o is None
- self.o2 = o is not None
- self.s = s < 'x'
- class BinaryOps:
- def __init__(self, x: int, s: str) -> None:
- self.a = x + 2
- self.b = x & 2
- self.c = x * 2
- self.d = -x
- self.e = 'x' + s
- self.f = x << x
- g = 2
- class LocalsAndGlobals:
- def __init__(self, x: int) -> None:
- t = x + 1
- self.a = t - t
- self.g = g
- class Booleans:
- def __init__(self, x: int, b: bool) -> None:
- self.a = True
- self.b = False
- self.c = not b
- self.d = b or b
- self.e = b and b
- F: Final = 3
- class ModuleFinal:
- def __init__(self) -> None:
- self.a = F
- self.b = other.Y
- class ClassFinal:
- F: Final = 3
- def __init__(self) -> None:
- self.a = ClassFinal.F
- class Literals:
- def __init__(self) -> None:
- self.a = 'x'
- self.b = b'x'
- self.c = 2.2
- class ListComprehension:
- def __init__(self, x: List[int]) -> None:
- self.a = [i + 1 for i in x]
- class Helper:
- def __init__(self, arg) -> None:
- self.x = 0
- def foo(self, arg) -> int:
- return 1
- class AttrAccess:
- def __init__(self, o: Helper) -> None:
- self.x = o.x
- o.x = o.x + 1
- self.y = o.foo(self.x)
- o.foo(self)
- self.z = 1
- class Construct:
- def __init__(self) -> None:
- self.x = Helper(1)
- self.y = Helper(self)
- class IsInstance:
- def __init__(self, x: object) -> None:
- if isinstance(x, str):
- self.x = 0
- elif isinstance(x, Helper):
- self.x = 1
- elif isinstance(x, (list, tuple)):
- self.x = 2
- else:
- self.x = 3
- class Cast:
- def __init__(self, x: object) -> None:
- self.x = cast(int, x)
- self.s = cast(str, x)
- self.c = cast(Cast, x)
- class PropertyAccessGetter:
- def __init__(self, other: PropertyAccessGetter) -> None:
- self.x = other.p
- self.y = 1
- self.z = self.p
- @property
- def p(self) -> int:
- return 0
- class PropertyAccessSetter:
- def __init__(self, other: PropertyAccessSetter) -> None:
- other.p = 1
- self.y = 1
- self.z = self.p
- @property
- def p(self) -> int:
- return 0
- @p.setter
- def p(self, x: int) -> None:
- pass
- def f() -> int:
- return 0
- [file other.py]
- # Not compiled
- from typing_extensions import Final
- Y: Final = 3
- [out]
- C: []
- Collections: [d, d2, l, l2, s, s2, t]
- Comparisons: [c1, c2, n1, n2, o1, o2, s]
- BinaryOps: [a, b, c, d, e, f]
- LocalsAndGlobals: [a, g]
- Booleans: [a, b, c, d, e]
- ModuleFinal: [a, b]
- ClassFinal: [F, a]
- Literals: [a, b, c]
- ListComprehension: [a]
- Helper: [x]
- AttrAccess: [x, y]
- Construct: [x]
- IsInstance: [x]
- Cast: [c, s, x]
- PropertyAccessGetter: [x, y]
- PropertyAccessSetter: [y]
- [case testAlwaysDefinedExpressions2]
- from typing import List, Tuple
- class C:
- def __init__(self) -> None:
- self.x = 0
- class AttributeRef:
- def __init__(self, c: C) -> None:
- self.aa = c.x
- self.bb = self.aa
- if c is not None:
- self.z = 0
- self.cc = 0
- self.dd = self.z
- class ListOps:
- def __init__(self, x: List[int], n: int) -> None:
- self.a = len(x)
- self.b = x[n]
- self.c = [y + 1 for y in x]
- class TupleOps:
- def __init__(self, t: Tuple[int, str]) -> None:
- x, y = t
- self.x = x
- self.y = t[0]
- s = x, y
- self.z = s
- class IfExpr:
- def __init__(self, x: int) -> None:
- self.a = 1 if x < 5 else 2
- class Base:
- def __init__(self, x: int) -> None:
- self.x = x
- class Derived1(Base):
- def __init__(self, y: int) -> None:
- self.aa = y
- super().__init__(y)
- self.bb = y
- class Derived2(Base):
- pass
- class Conditionals:
- def __init__(self, b: bool, n: int) -> None:
- if not (n == 5 or n >= n + 1):
- self.a = b
- else:
- self.a = not b
- if b:
- self.b = 2
- else:
- self.b = 4
- [out]
- C: [x]
- AttributeRef: [aa, bb, cc, dd]
- ListOps: [a, b, c]
- TupleOps: [x, y, z]
- IfExpr: [a]
- Base: [x]
- Derived1: [aa, bb, x]
- Derived2: [x]
- Conditionals: [a, b]
- [case testAlwaysDefinedStatements]
- from typing import Any, List, Optional, Iterable
- class Return:
- def __init__(self, x: int) -> None:
- self.x = x
- if x > 5:
- self.y = 1
- return
- self.y = 2
- self.z = x
- class While:
- def __init__(self, x: int) -> None:
- n = 2
- while x > 0:
- n *=2
- x -= 1
- self.a = n
- while x < 5:
- self.b = 1
- self.b += 1
- class Try:
- def __init__(self, x: List[int]) -> None:
- self.a = 0
- try:
- self.b = x[0]
- except:
- self.c = x
- self.d = 0
- try:
- self.e = x[0]
- except:
- self.e = 1
- class TryFinally:
- def __init__(self, x: List[int]) -> None:
- self.a = 0
- try:
- self.b = x[0]
- finally:
- self.c = x
- self.d = 0
- try:
- self.e = x[0]
- finally:
- self.e = 1
- class Assert:
- def __init__(self, x: Optional[str], y: int) -> None:
- assert x is not None
- assert y < 5
- self.a = x
- class For:
- def __init__(self, it: Iterable[int]) -> None:
- self.x = 0
- for x in it:
- self.x += x
- for x in it:
- self.y = x
- class Assignment1:
- def __init__(self, other: Assignment1) -> None:
- self.x = 0
- self = other # Give up after assignment to self
- self.y = 1
- class Assignment2:
- def __init__(self) -> None:
- self.x = 0
- other = self # Give up after self is aliased
- self.y = other.x
- class With:
- def __init__(self, x: Any) -> None:
- self.a = 0
- with x:
- self.b = 1
- self.c = 2
- def f() -> None:
- pass
- [out]
- Return: [x, y]
- While: [a]
- -- We could infer 'e' as always defined, but this is tricky, since always defined attribute
- -- analysis must be performed earlier than exception handling transform. This would be
- -- easy to infer *after* exception handling transform.
- Try: [a, d]
- -- Again, 'e' could be always defined, but it would be a bit tricky to do it.
- TryFinally: [a, c, d]
- Assert: [a]
- For: [x]
- Assignment1: [x]
- Assignment2: [x]
- -- TODO: Why is not 'b' included?
- With: [a, c]
- [case testAlwaysDefinedAttributeDefaults]
- class Basic:
- x = 0
- class ClassBodyAndInit:
- x = 0
- s = 'x'
- def __init__(self, n: int) -> None:
- self.n = 0
- class AttrWithDefaultAndInit:
- x = 0
- def __init__(self, x: int) -> None:
- self.x = x
- class Base:
- x = 0
- y = 1
- class Derived(Base):
- y = 2
- z = 3
- [out]
- Basic: [x]
- ClassBodyAndInit: [n, s, x]
- AttrWithDefaultAndInit: [x]
- Base: [x, y]
- Derived: [x, y, z]
- [case testAlwaysDefinedWithInheritance]
- class Base:
- def __init__(self, x: int) -> None:
- self.x = x
- class Deriv1(Base):
- def __init__(self, x: int, y: str) -> None:
- super().__init__(x)
- self.y = y
- class Deriv2(Base):
- def __init__(self, x: int, y: str) -> None:
- self.y = y
- super().__init__(x)
- class Deriv22(Deriv2):
- def __init__(self, x: int, y: str, z: bool) -> None:
- super().__init__(x, y)
- self.z = False
- class Deriv3(Base):
- def __init__(self) -> None:
- super().__init__(1)
- class Deriv4(Base):
- def __init__(self) -> None:
- self.y = 1
- self.x = 2
- def f(a): pass
- class BaseUnsafe:
- def __init__(self, x: int, y: int) -> None:
- self.x = x
- f(self) # Unknown function
- self.y = y
- class DerivUnsafe(BaseUnsafe):
- def __init__(self, z: int, zz: int) -> None:
- self.z = z
- super().__init__(1, 2) # Calls unknown function
- self.zz = zz
- class BaseWithDefault:
- x = 1
- def __init__(self) -> None:
- self.y = 1
- class DerivedWithDefault(BaseWithDefault):
- def __init__(self) -> None:
- super().__init__()
- self.z = 1
- class AlwaysDefinedInBase:
- def __init__(self) -> None:
- self.x = 1
- self.y = 1
- class UndefinedInDerived(AlwaysDefinedInBase):
- def __init__(self, x: bool) -> None:
- self.x = 1
- if x:
- self.y = 2
- class UndefinedInDerived2(UndefinedInDerived):
- def __init__(self, x: bool):
- if x:
- self.y = 2
- [out]
- Base: [x]
- Deriv1: [x, y]
- Deriv2: [x, y]
- Deriv22: [x, y, z]
- Deriv3: [x]
- Deriv4: [x, y]
- BaseUnsafe: [x]
- DerivUnsafe: [x, z]
- BaseWithDefault: [x, y]
- DerivedWithDefault: [x, y, z]
- AlwaysDefinedInBase: []
- UndefinedInDerived: []
- UndefinedInDerived2: []
- [case testAlwaysDefinedWithInheritance2]
- from mypy_extensions import trait, mypyc_attr
- from interpreted import PythonBase
- class BasePartiallyDefined:
- def __init__(self, x: int) -> None:
- self.a = 0
- if x:
- self.x = x
- class Derived1(BasePartiallyDefined):
- def __init__(self, x: int) -> None:
- super().__init__(x)
- self.y = x
- class BaseUndefined:
- x: int
- class DerivedAlwaysDefined(BaseUndefined):
- def __init__(self) -> None:
- super().__init__()
- self.z = 0
- self.x = 2
- @trait
- class MyTrait:
- def f(self) -> None: pass
- class SimpleTraitImpl(MyTrait):
- def __init__(self) -> None:
- super().__init__()
- self.x = 0
- @trait
- class TraitWithAttr:
- x: int
- y: str
- class TraitWithAttrImpl(TraitWithAttr):
- def __init__(self) -> None:
- self.y = 'x'
- @trait
- class TraitWithAttr2:
- z: int
- class TraitWithAttrImpl2(TraitWithAttr, TraitWithAttr2):
- def __init__(self) -> None:
- self.y = 'x'
- self.z = 2
- @mypyc_attr(allow_interpreted_subclasses=True)
- class BaseWithGeneralSubclassing:
- x = 0
- y: int
- def __init__(self, s: str) -> None:
- self.s = s
- class Derived2(BaseWithGeneralSubclassing):
- def __init__(self) -> None:
- super().__init__('x')
- self.z = 0
- class SubclassPythonclass(PythonBase):
- def __init__(self) -> None:
- self.y = 1
- class BaseWithSometimesDefined:
- def __init__(self, b: bool) -> None:
- if b:
- self.x = 0
- class Derived3(BaseWithSometimesDefined):
- def __init__(self, b: bool) -> None:
- super().__init__(b)
- self.x = 1
- [file interpreted.py]
- class PythonBase:
- def __init__(self) -> None:
- self.x = 0
- [out]
- BasePartiallyDefined: [a]
- Derived1: [a, y]
- BaseUndefined: []
- DerivedAlwaysDefined: [x, z]
- MyTrait: []
- SimpleTraitImpl: [x]
- TraitWithAttr: []
- TraitWithAttrImpl: [y]
- TraitWithAttr2: []
- TraitWithAttrImpl2: [y, z]
- BaseWithGeneralSubclassing: []
- -- TODO: 's' could also be always defined
- Derived2: [x, z]
- -- Always defined attribute analysis is turned off when inheriting a non-native class.
- SubclassPythonclass: []
- BaseWithSometimesDefined: []
- -- TODO: 'x' could also be always defined, but it is a bit tricky to support
- Derived3: []
- [case testAlwaysDefinedWithNesting]
- class NestedFunc:
- def __init__(self) -> None:
- self.x = 0
- def f() -> None:
- self.y = 0
- f()
- self.z = 1
- [out]
- -- TODO: Support nested functions.
- NestedFunc: []
- f___init___NestedFunc_obj: []
|