| [case testForcedAssignment] |
| x = 1 # type: object |
| y = 1 |
| def f(): x, y # Prevent independent redefinition |
| y = x # E: Incompatible types in assignment (expression has type "object", variable has type "int") |
| x = 2 |
| y = x |
| [builtins fixtures/tuple.pyi] |
| |
| [case testJoinAny] |
| from typing import List, Any |
| |
| x: List[Any] |
| |
| def foo() -> List[int]: pass |
| def bar() -> List[str]: pass |
| |
| if bool(): |
| x = foo() |
| else: |
| x = bar() |
| |
| x * 2 |
| [builtins fixtures/list.pyi] |
| |
| [case testGeneratorExpressionTypes] |
| class A: y = 1 |
| x = [A()] |
| y = [x] |
| |
| z = [1,2] |
| z = [a.y for b in y for a in b] |
| [builtins fixtures/list.pyi] |
| |
| [case testIsinstanceNestedTuple] |
| from typing import Union, List, Tuple, Dict |
| |
| def f(x: Union[int, str, List]) -> None: |
| if isinstance(x, (str, (int,))): |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| x[1] # E: Value of type "Union[int, str]" is not indexable |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.list[Any]" |
| x[1] |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str, builtins.list[Any]]" |
| if isinstance(x, (str, (list,))): |
| reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.list[Any]]" |
| x[1] |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str, builtins.list[Any]]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testClassAttributeInitialization] |
| class A: |
| x: int |
| def __init__(self) -> None: |
| self.y: int |
| z = self.x |
| w = self.y |
| |
| [case testAssignmentSubtypes] |
| from typing import Union |
| |
| def foo(x: Union[str, int]): |
| if isinstance(x, int): |
| x = 'a' |
| x + 'a' |
| z = x |
| y = [x] |
| y[0] + 'a' |
| # TODO: should we allow these two lines? |
| y + [1] # E: List item 0 has incompatible type "int"; expected "str" |
| z = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "str") |
| |
| x: int |
| y = [x] |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testFunctionDefaultArgs] |
| class A: pass |
| class B(A): y = 1 |
| |
| x = A() |
| |
| def foo(x: A = B()): |
| x.y # E: "A" has no attribute "y" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceFancyConditionals] |
| class A: pass |
| |
| class B(A): |
| y = 1 |
| |
| x = A() |
| if isinstance(x, B): |
| x.y |
| while isinstance(x, B): |
| x.y |
| while isinstance(x, B): |
| x.y |
| x = B() |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testSubtypingWithAny] |
| class A: |
| y = 1 |
| |
| class B(A): |
| z = 1 |
| |
| def foo(): pass |
| |
| x = A() |
| if int(): |
| x = B() |
| x.z |
| x = foo() |
| x.z # E: "A" has no attribute "z" |
| x.y |
| |
| [case testSingleMultiAssignment] |
| x = 'a' |
| (x,) = ('a',) |
| |
| [case testUnionMultiAssignment] |
| from typing import Union |
| x: Union[int, str] |
| if int(): |
| x = 1 |
| x = 'a' |
| x + 1 # E: Unsupported operand types for + ("str" and "int") |
| x = 1 |
| (x, y) = ('a', 1) |
| x + 1 # E: Unsupported operand types for + ("str" and "int") |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testUnionIfZigzag] |
| from typing import Union |
| |
| def f(x: Union[int, str]) -> None: |
| if 1: # Without this, the assignment below could create a new variable "x" of type "int" |
| x = 1 |
| if x: |
| x = 'a' |
| x = 1 |
| x + 1 |
| x + 1 |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testTwoLoopsUnion] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| def bar() -> None: |
| x = foo() |
| if isinstance(x, int): |
| return |
| while bool(): |
| x + 'a' |
| while bool(): |
| x = foo() |
| if bool(): |
| return |
| x = 'a' |
| x + 'a' |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testComplicatedBlocks] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| def bar() -> None: |
| x = foo() |
| if isinstance(x, int): |
| return |
| while bool(): |
| x + 'a' |
| while bool(): |
| x = foo() |
| if bool(): |
| return |
| x = 'a' |
| x + 'a' |
| |
| x = foo() |
| if isinstance(x, int): |
| return |
| while bool(): |
| x + 'a' |
| while bool(): |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ |
| # N: Left operand is of type "Union[int, str]" |
| x = foo() |
| if bool(): |
| continue |
| x = 'a' |
| x = 'a' |
| x + 'a' |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testUnionTryExcept] |
| class A: |
| y = A() |
| |
| class B(A): |
| z = 1 |
| |
| x = A() |
| def f(): x # Prevent redefinition of x |
| x = B() |
| x.z |
| try: |
| x.z |
| x = A() |
| x = B() |
| x.z |
| except: |
| pass |
| x.z # E: "A" has no attribute "z" |
| |
| [case testUnionTryExcept2] |
| class A: |
| y = A() |
| |
| class B(A): |
| z = 1 |
| |
| x = A() |
| try: |
| x.z # E: "A" has no attribute "z" |
| x = A() |
| x = B() |
| x.z |
| except: |
| x.z # E: "A" has no attribute "z" |
| x = B() |
| x.z |
| else: |
| x = B() |
| x.z |
| |
| [case testUnionTryExcept3] |
| class A: |
| y = A() |
| |
| class B(A): |
| z = 1 |
| |
| x = A() |
| def f(): x # Prevent redefinition of x |
| x = B() |
| try: |
| raise BaseException() |
| x = A() |
| except: |
| pass |
| x.z |
| x = B() |
| try: |
| x = A() |
| raise BaseException() |
| except: |
| pass |
| x.z # E: "A" has no attribute "z" |
| x = B() |
| try: |
| pass |
| except: |
| x = A() |
| raise BaseException() |
| x.z |
| try: |
| x = A() |
| except: |
| pass |
| x.z # E: "A" has no attribute "z" |
| x = B() |
| try: |
| pass |
| except: |
| x = A() |
| x.z # E: "A" has no attribute "z" |
| [builtins fixtures/exception.pyi] |
| |
| [case testUnionTryExcept4] |
| class A: pass |
| |
| class B(A): |
| z = 1 |
| |
| x = A() |
| while bool(): |
| try: |
| x.z # E: "A" has no attribute "z" |
| x = A() |
| except: |
| x = B() |
| else: |
| x = B() |
| x.z |
| [builtins fixtures/exception.pyi] |
| |
| [case testUnionTryFinally] |
| class A: pass |
| |
| class B(A): |
| b = 1 |
| |
| x = A() |
| def f(): x # Prevent redefinition |
| x = B() |
| try: |
| x = A() |
| x.b # E: "A" has no attribute "b" |
| x = B() |
| finally: |
| x.b # E: "A" has no attribute "b" |
| x.b |
| |
| [case testUnionTryFinally2] |
| class A: pass |
| |
| class B(A): |
| b = 1 |
| |
| x = A() |
| def f(): x # Prevent redefinition |
| x = B() |
| try: |
| x = A() |
| x = B() |
| except: |
| pass |
| finally: |
| pass |
| x.b # E: "A" has no attribute "b" |
| |
| [case testUnionTryFinally3] |
| class A: pass |
| |
| class B(A): |
| b = 1 |
| |
| x = A() |
| def f(): x # Prevent redefinition |
| x = B() |
| try: |
| x = A() |
| x = B() |
| except: |
| pass |
| finally: |
| x = B() |
| x.b |
| |
| [case testUnionTryFinally4] |
| class A: pass |
| |
| class B(A): |
| b = 1 |
| |
| while 2: |
| x = A() |
| def f(): x # Prevents redefinition |
| x = B() |
| try: |
| x = A() |
| x = B() |
| except: |
| pass |
| finally: |
| x.b # E: "A" has no attribute "b" |
| if not isinstance(x, B): |
| break |
| x.b |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testUnionTryFinally5] |
| class A: pass |
| |
| class B(A): |
| b = 1 |
| |
| while 2: |
| x = A() |
| try: |
| x = A() |
| x = B() |
| finally: |
| x.b # E: "A" has no attribute "b" |
| break |
| x.b |
| x.b |
| |
| [case testUnionTryFinally6] |
| class A: pass |
| |
| class B(A): |
| b = 1 |
| |
| def f() -> int: |
| x = B() # type: A |
| try: |
| x = B() |
| except: |
| x = A() |
| # An exception could occur here |
| x = B() |
| finally: |
| return x.b # E: "A" has no attribute "b" |
| |
| [case testUnionListIsinstance] |
| from typing import Union, List |
| |
| def f(x: Union[List[int], List[str], int]) -> None: |
| if isinstance(x, list): |
| a = x[0] |
| if isinstance(a, int): |
| a + 1 |
| a + 'x' # E: Unsupported operand types for + ("int" and "str") |
| |
| # type of a? |
| reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.int], builtins.list[builtins.str]]" |
| x + 1 # E: Unsupported operand types for + ("List[int]" and "int") \ |
| # E: Unsupported operand types for + ("List[str]" and "int") \ |
| # N: Left operand is of type "Union[List[int], List[str]]" |
| else: |
| x[0] # E: Value of type "int" is not indexable |
| x + 1 |
| x[0] # E: Value of type "Union[List[int], List[str], int]" is not indexable |
| x + 1 # E: Unsupported operand types for + ("List[int]" and "int") \ |
| # E: Unsupported operand types for + ("List[str]" and "int") \ |
| # N: Left operand is of type "Union[List[int], List[str], int]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testUnionListIsinstance2] |
| from typing import Union, List |
| |
| class A: |
| a = 1 |
| |
| class B: pass |
| class C: pass |
| |
| def g(x: Union[A, B]) -> A: pass |
| def h(x: C) -> A: pass |
| def f(x: Union[A, B, C]) -> None: |
| if isinstance(x, C): |
| x = h(x) |
| else: |
| x = g(x) |
| x.a |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testUnionStrictDefnBasic] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| x = foo() |
| if int(): |
| x = 1 |
| x = x + 1 |
| x = foo() |
| x = x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| if isinstance(x, str): |
| x = x + 1 # E: Unsupported operand types for + ("str" and "int") |
| x = 1 |
| x = x + 1 |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testSubtypeRedefinitionBasic] |
| from typing import Union |
| |
| class A: pass |
| |
| class B(A): |
| y = 1 |
| |
| x = A() |
| x.y # E: "A" has no attribute "y" |
| x = B() |
| x.y # OK: x is known to be a B |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceBasic] |
| from typing import Union |
| x: Union[int, str] |
| if isinstance(x, str): |
| x = x + 1 # E: Unsupported operand types for + ("str" and "int") |
| x = x + 'a' |
| else: |
| x = x + 'a' # E: Unsupported operand types for + ("int" and "str") |
| x = x + 1 |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceIndexing] |
| from typing import Union |
| x: Union[int, str] |
| j = [x] |
| if isinstance(j[0], str): |
| j[0] = j[0] + 'a' |
| j[0] = j[0] + 1 # E: Unsupported operand types for + ("str" and "int") |
| else: |
| j[0] = j[0] + 'a' # E: Unsupported operand types for + ("int" and "str") |
| j[0] = j[0] + 1 |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceSubClassMember] |
| from typing import Union |
| |
| class Animal: pass |
| |
| class Dog(Animal): |
| paws = 4 # type: Union[int, str] |
| |
| def bark(self): pass |
| |
| class House: |
| pet = None # type: Animal |
| |
| h = House() |
| h.pet = Dog() |
| |
| while bool(): |
| if isinstance(h.pet, Dog): |
| if isinstance(h.pet.paws, str): |
| x = h.pet.paws + 'a' |
| y = h.pet.paws + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| z = h.pet.paws + 'a' # E: Unsupported operand types for + ("int" and "str") \ |
| # N: Left operand is of type "Union[int, str]" |
| if isinstance(h.pet.paws, str): |
| x = h.pet.paws + 'a' |
| break |
| y = h.pet.paws + 1 |
| z = h.pet.paws + 'a' # E: Unsupported operand types for + ("int" and "str") |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceSubClassReset] |
| class A: |
| pass |
| |
| class B(A): |
| b = 1 |
| |
| class C: |
| a = A() |
| |
| x = C() |
| x.a.b # E: "A" has no attribute "b" |
| if isinstance(x.a, B): |
| x.a.b |
| x = C() |
| x.a.b # E: "A" has no attribute "b" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceTuple] |
| from typing import Union |
| |
| class A: pass |
| |
| class B: |
| def method2(self, arg: int): |
| return 123 |
| |
| class C: |
| def method2(self, arg: int): |
| return 456 |
| |
| def method3(self, arg: str): |
| return 'abc' |
| |
| v = A() # type: Union[A, B, C] |
| |
| if isinstance(v, (B, C)): |
| v.method2(123) |
| v.method3('xyz') # E: Item "B" of "Union[B, C]" has no attribute "method3" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceNeverWidens] |
| from typing import Union |
| |
| class A: pass |
| class B: pass |
| class C: pass |
| |
| a = A() # type: A |
| assert isinstance(a, (A, B)) |
| reveal_type(a) # N: Revealed type is "__main__.A" |
| |
| b = A() # type: Union[A, B] |
| assert isinstance(b, (A, B, C)) |
| reveal_type(b) # N: Revealed type is "Union[__main__.A, __main__.B]" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testMemberAssignmentChanges] |
| from typing import Union |
| |
| class Dog: |
| paws = 1 # type: Union[int, str] |
| |
| pet = Dog() |
| |
| pet.paws + 'a' # E: Unsupported operand types for + ("int" and "str") \ |
| # N: Left operand is of type "Union[int, str]" |
| pet.paws = 'a' |
| pet.paws + 'a' |
| pet.paws = 1 |
| pet.paws + 1 |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceSubClassMemberHard] |
| from typing import Union |
| |
| class Animal: |
| pass |
| |
| class Dog(Animal): |
| paws = 4 # type: Union[int, str] |
| |
| def bark(self): pass |
| |
| class House: |
| pet = None # type: Animal |
| |
| h = House() |
| h.pet = Dog() |
| |
| if isinstance(h.pet, Dog): |
| if isinstance(h.pet.paws, str): |
| for i in [1]: |
| # TODO: should we allow this if iterable is of length one or zero? |
| h.pet.paws + 'a' # E: Unsupported operand types for + ("int" and "str") \ |
| # N: Left operand is of type "Union[int, str]" |
| if bool(): |
| break |
| h.pet.paws = 1 |
| h.pet.paws + 1 |
| |
| if isinstance(h.pet.paws, str): |
| h.pet.paws + 'a' |
| else: |
| h.pet.paws + 1 |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceReturn] |
| from typing import Union |
| |
| def foo() -> None: |
| x = 1 # type: Union[int, str] |
| if isinstance(x, int): |
| return |
| y = x + 'asdad' |
| |
| def bar() -> None: |
| x = 1 # type: Union[int, str] |
| if isinstance(x, int): |
| return |
| else: |
| pass |
| y = x + 'asdad' |
| |
| foo() |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceBadBreak] |
| from typing import Union |
| |
| def foo() -> None: |
| x: Union[int, str] |
| if isinstance(x, int): |
| for z in [1,2]: |
| break |
| else: |
| pass |
| y = x + 'asdad' # E: Unsupported operand types for + ("int" and "str") \ |
| # N: Left operand is of type "Union[int, str]" |
| |
| foo() |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceThreeUnion] |
| from typing import Union, List |
| |
| x: Union[int, str, List[int]] |
| |
| while bool(): |
| if isinstance(x, int): |
| x + 1 |
| elif isinstance(x, str): |
| x + 'a' |
| else: |
| x + [1] |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ |
| # E: Unsupported operand types for + ("List[int]" and "str") \ |
| # N: Left operand is of type "Union[int, str, List[int]]" |
| |
| x + [1] # E: Unsupported operand types for + ("int" and "List[int]") \ |
| # E: Unsupported operand types for + ("str" and "List[int]") \ |
| # N: Left operand is of type "Union[int, str, List[int]]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceThreeUnion2] |
| from typing import Union, List |
| x: Union[int, str, List[int]] |
| while bool(): |
| if isinstance(x, int): |
| x + 1 |
| break |
| elif isinstance(x, str): |
| x + 'a' |
| break |
| x + [1] |
| x + 'a' # E: Unsupported operand types for + ("List[int]" and "str") |
| x + [1] # E: Unsupported operand types for + ("int" and "List[int]") \ |
| # E: Unsupported operand types for + ("str" and "List[int]") \ |
| # N: Left operand is of type "Union[int, str, List[int]]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceThreeUnion3] |
| from typing import Union, List |
| |
| while bool(): |
| x: Union[int, str, List[int]] |
| def f(): x # Prevent redefinition |
| x = 1 |
| if isinstance(x, int): |
| x + 1 |
| break |
| elif isinstance(x, str): |
| x + 'a' |
| break |
| x + [1] # These lines aren't reached because x was an int |
| x + 'a' |
| x + [1] # E: Unsupported operand types for + ("int" and "List[int]") \ |
| # E: Unsupported operand types for + ("str" and "List[int]") \ |
| # N: Left operand is of type "Union[int, str, List[int]]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testRemovingTypeRepeatedly] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| for i in [1, 2]: |
| x = foo() |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ |
| # N: Left operand is of type "Union[int, str]" |
| if isinstance(x, int): |
| break |
| x + 'a' |
| |
| x = foo() |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ |
| # N: Left operand is of type "Union[int, str]" |
| if isinstance(x, int): |
| break |
| x + 'a' |
| |
| x = foo() |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ |
| # N: Left operand is of type "Union[int, str]" |
| if isinstance(x, int): |
| break |
| x + 'a' |
| |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ |
| # N: Left operand is of type "Union[int, str]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testModifyRepeatedly] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| x = foo() |
| def f(): x # Prevent redefinition |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ |
| # N: Left operand is of type "Union[int, str]" |
| |
| x = 1 |
| x + 1 |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") |
| |
| x = 'a' |
| x + 1 # E: Unsupported operand types for + ("str" and "int") |
| x + 'a' |
| |
| x = foo() |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ |
| # N: Left operand is of type "Union[int, str]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testModifyLoop] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| x = foo() |
| def f(): x # Prevent redefinition |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| x = 'a' |
| x + 1 # E: Unsupported operand types for + ("str" and "int") |
| x = 1 |
| x + 1 |
| |
| while bool(): |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| x = 'a' |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testModifyLoop2] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| x = foo() |
| def f(): x # Prevent redefinition |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| x = 'a' |
| x + 1 # E: Unsupported operand types for + ("str" and "int") |
| x = 1 |
| x + 1 |
| |
| for i in [1]: |
| x = 'a' |
| |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testModifyLoop3] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| x = foo() |
| def f(): x # Prevent redefinition |
| x = 1 |
| |
| while bool(): |
| x + 1 |
| x = 'a' |
| break |
| else: |
| x + 1 |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| x = 1 |
| for y in [1]: |
| x + 1 |
| x = 'a' |
| break |
| else: |
| x + 1 |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testModifyLoopWhile4] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| x = foo() |
| def f(): x # Prevent redefinition |
| x = 1 |
| |
| while bool(): |
| x + 1 |
| if bool(): |
| x = 'a' |
| break |
| else: |
| x + 1 |
| x = 'a' |
| x + 'a' |
| x = 1 |
| while bool(): |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| if bool(): |
| x = 'a' |
| continue |
| else: |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| x = 'a' |
| x + 'a' |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testModifyLoopFor4] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| x = foo() |
| def f(): x # Prevent redefinition |
| x = 1 |
| |
| for y in [1]: |
| x + 1 |
| if bool(): |
| x = 'a' |
| break |
| else: |
| x + 1 |
| x = 'a' |
| x + 'a' |
| x = 1 |
| for y in [1]: |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| if bool(): |
| x = 'a' |
| continue |
| else: |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| x = 'a' |
| x + 'a' |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testModifyNestedLoop] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| x = foo() |
| def f(): x # Prevent redefinition |
| x = 1 |
| |
| for y in [1]: |
| for z in [1]: |
| break |
| else: |
| x = 'a' |
| break |
| else: |
| x + 1 |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| x = 1 |
| while bool(): |
| while bool(): |
| break |
| else: |
| x = 'a' |
| break |
| else: |
| x + 1 |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testModifyLoopLong] |
| from typing import Union |
| |
| class A: a = 1 |
| |
| def foo() -> Union[int, str, A]: pass |
| |
| def bar() -> None: |
| x = foo() |
| x + 1 # E: Unsupported left operand type for + ("A") \ |
| # N: Left operand is of type "Union[int, str, A]" \ |
| # E: Unsupported operand types for + ("str" and "int") |
| if isinstance(x, A): |
| x.a |
| else: |
| if isinstance(x, int): |
| x + 1 |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") |
| else: |
| x + 'a' |
| x.a # E: "str" has no attribute "a" |
| x = A() |
| |
| if isinstance(x, str): |
| x + 'a' |
| else: |
| while bool(): |
| if isinstance(x, int): |
| x + 1 |
| else: |
| x.a |
| break |
| while bool(): |
| if isinstance(x, int): |
| x + 1 |
| else: |
| x.a |
| continue |
| |
| while bool(): |
| if isinstance(x, int): |
| x + 1 |
| else: |
| x.a # E: Item "str" of "Union[str, A]" has no attribute "a" |
| x = 'a' |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testWhileExitCondition1] |
| from typing import Union |
| x = 1 # type: Union[int, str] |
| while isinstance(x, int): |
| if bool(): |
| continue |
| x = 'a' |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.str" |
| reveal_type(x) # N: Revealed type is "builtins.str" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testWhileExitCondition2] |
| from typing import Union |
| x = 1 # type: Union[int, str] |
| while isinstance(x, int): |
| if bool(): |
| break |
| x = 'a' |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.str" |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testWhileLinkedList] |
| from typing import Union |
| LinkedList = Union['Cons', 'Nil'] |
| class Nil: pass |
| class Cons: |
| tail = None # type: LinkedList |
| def last(x: LinkedList) -> Nil: |
| while isinstance(x, Cons): |
| x = x.tail |
| return x |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testReturnAndFlow] |
| def foo() -> int: |
| return 1 and 2 |
| return 'a' |
| [case testCastIsinstance] |
| from typing import Union |
| |
| def foo() -> Union[int, str]: pass |
| |
| x = foo() |
| y = 1 # type: int |
| |
| if isinstance(x, str): |
| x = y |
| x + 1 |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testUnreachableCode] |
| x = 1 # type: int |
| |
| while bool(): |
| x = 'a' # E: Incompatible types in assignment (expression has type "str", variable has type "int") |
| break |
| x = 'a' # Note: no error because unreachable code |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testUnreachableCode2] |
| x = 1 |
| while bool(): |
| try: |
| pass |
| except: |
| continue |
| else: |
| continue |
| x + 'a' |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testUnreachableWhileTrue] |
| def f(x: int) -> None: |
| while True: |
| if x: |
| return |
| 1() |
| [builtins fixtures/bool.pyi] |
| |
| [case testUnreachableAssertFalse] |
| def f() -> None: |
| assert False |
| 1() |
| [builtins fixtures/bool.pyi] |
| |
| [case testUnreachableAssertFalse2] |
| def f() -> None: |
| # The old parser doesn't understand the syntax below |
| assert False, "hi" |
| 1() |
| [builtins fixtures/bool.pyi] |
| |
| [case testUnreachableReturnOrAssertFalse] |
| def f(x: int) -> int: |
| if x: |
| return x |
| else: |
| assert False |
| 1() |
| [builtins fixtures/bool.pyi] |
| |
| [case testUnreachableTryExcept] |
| def f() -> None: |
| try: |
| f() |
| return |
| except BaseException: |
| return |
| 1() |
| [builtins fixtures/exception.pyi] |
| |
| [case testUnreachableTryExceptElse] |
| def f() -> None: |
| try: |
| f() |
| except BaseException: |
| return |
| else: |
| return |
| 1() |
| [builtins fixtures/exception.pyi] |
| |
| [case testUnreachableTryReturnFinally1] |
| def f() -> None: |
| try: |
| return |
| finally: |
| pass |
| 1() |
| |
| [case testUnreachableTryReturnFinally2] |
| def f() -> None: |
| try: |
| pass |
| finally: |
| return |
| 1() |
| |
| [case testUnreachableTryReturnExceptRaise] |
| def f() -> None: |
| try: |
| return |
| except: |
| raise |
| 1() |
| |
| [case testUnreachableReturnLambda] |
| from typing import Callable |
| def g(t: Callable[[int], int]) -> int: pass |
| def f() -> int: |
| return g(lambda x: x) |
| 1() |
| |
| [case testIsinstanceAnd] |
| class A: pass |
| |
| class B(A): |
| flag = 1 |
| |
| x = B() # type: A |
| |
| if isinstance(x, B) and 1: |
| x.flag |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsinstanceShortcircuit] |
| class A: |
| pass |
| |
| class B(A): |
| flag = 1 |
| |
| x = B() # type: A |
| |
| if isinstance(x, B) and x.flag: |
| pass |
| if isinstance(x, B) or x.flag: # E: "A" has no attribute "flag" |
| pass |
| if not isinstance(x, B) or x.flag: |
| pass |
| if not isinstance(x, B) and x.flag: # E: "A" has no attribute "flag" |
| pass |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsinstanceExpression] |
| class A: |
| pass |
| |
| class B(A): |
| flag = 1 |
| |
| x = B() # type: A |
| |
| x.flag if isinstance(x, B) else 0 |
| 0 if not isinstance(x, B) else x.flag |
| 0 if isinstance(x, B) else x.flag # E: "A" has no attribute "flag" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsinstanceMultiAnd] |
| class A: pass |
| |
| class B(A): |
| flag = 1 |
| |
| class C(A): |
| glaf = 1 |
| |
| x = B() # type: A |
| y = C() # type: A |
| |
| if isinstance(x, B) and isinstance(y, C): |
| x.flag += 1 |
| y.glaf += 1 |
| x() # E: "B" not callable |
| y() # E: "C" not callable |
| else: |
| x() # E: "A" not callable |
| y() # E: "A" not callable |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsinstanceMultiAndSpecialCase] |
| class A: |
| # Ensure A.__add__ and int.__add__ are different to |
| # force 'isinstance(y, int)' checks below to never succeed. |
| def __add__(self, other: A) -> A: pass |
| |
| class B(A): |
| flag = 1 |
| |
| class C(A): |
| glaf = 1 |
| |
| x = B() # type: A |
| y = C() # type: A |
| |
| if isinstance(x, B) and isinstance(y, int): |
| 1() # type checking skipped |
| if isinstance(y, int) and isinstance(x, B): |
| 1() # type checking skipped |
| if isinstance(y, int) and y > 42: |
| 1() # type checking skipped |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testReturnWithCallExprAndIsinstance] |
| from typing import Union |
| |
| def f(x: Union[int, str]) -> None: |
| if not isinstance(x, int): |
| return foo() |
| x() # E: "int" not callable |
| |
| def foo(): pass |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsinstanceOr1] |
| from typing import Optional |
| |
| def f(a: bool, x: object) -> Optional[int]: |
| if a or not isinstance(x, int): |
| return None |
| reveal_type(x) # N: Revealed type is "builtins.int" |
| return x |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceOr2] |
| from typing import Optional |
| |
| def g(a: bool, x: object) -> Optional[int]: |
| if not isinstance(x, int) or a: |
| return None |
| reveal_type(x) # N: Revealed type is "builtins.int" |
| return x |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceOr3] |
| from typing import Optional |
| |
| def h(a: bool, x: object) -> Optional[int]: |
| if a or isinstance(x, int): |
| return None |
| return x # E: Incompatible return value type (got "object", expected "Optional[int]") |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceWithOverlappingUnionType] |
| from typing import Union |
| |
| def f(x: Union[float, int]) -> None: |
| if isinstance(x, float): |
| pass |
| if not isinstance(x, int): |
| f(x) |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceWithOverlappingUnionType2] |
| from typing import Union |
| |
| class A: pass |
| class B(A): pass |
| |
| def f(x: Union[A, B]) -> None: |
| if isinstance(x, A): |
| pass |
| if not isinstance(x, B): |
| f(x) |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceWithOverlappingPromotionTypes] |
| from typing import Union |
| |
| class FloatLike: pass |
| class IntLike(FloatLike): pass |
| |
| def f1(x: Union[float, int]) -> None: |
| # We ignore promotions in isinstance checks |
| if isinstance(x, float): |
| reveal_type(x) # N: Revealed type is "builtins.float" |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.int" |
| |
| def f2(x: Union[FloatLike, IntLike]) -> None: |
| # ...but not regular subtyping relationships |
| if isinstance(x, FloatLike): |
| reveal_type(x) # N: Revealed type is "Union[__main__.FloatLike, __main__.IntLike]" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceOfSuperclass] |
| class A: pass |
| class B(A): pass |
| |
| x = B() |
| if isinstance(x, A): |
| reveal_type(x) # N: Revealed type is "__main__.B" |
| if not isinstance(x, A): |
| reveal_type(x) # unreachable |
| x = A() |
| reveal_type(x) # N: Revealed type is "__main__.B" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceOfNonoverlapping] |
| class A: pass |
| class B: pass |
| |
| x = B() |
| if isinstance(x, A): |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "B" and "A">" |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.B" |
| reveal_type(x) # N: Revealed type is "__main__.B" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testAssertIsinstance] |
| def f(x: object): |
| assert isinstance(x, int) |
| y = 0 # type: int |
| y = x |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testUnionAssertIsinstance] |
| from typing import Union |
| |
| def f(x: Union[str, int]): |
| assert isinstance(x, int) |
| y = 0 # type: int |
| y = x |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testAnyAssertIsinstance] |
| from typing import Any |
| |
| def f(x: Any): |
| assert isinstance(x, int) # this should narrow x to type int |
| x + "foo" # E: Unsupported operand types for + ("int" and "str") |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceOfGenericClassRetainsParameters] |
| from typing import List, Union |
| |
| def f(x: Union[List[int], str]) -> None: |
| if isinstance(x, list): |
| x[0]() # E: "int" not callable |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.str" |
| reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.int], builtins.str]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsinstanceOrIsinstance] |
| class A: pass |
| |
| class B(A): |
| flag = 1 |
| |
| class C(A): |
| flag = 2 |
| |
| x1 = A() |
| if isinstance(x1, B) or isinstance(x1, C): |
| reveal_type(x1) # N: Revealed type is "Union[__main__.B, __main__.C]" |
| f = x1.flag # type: int |
| else: |
| reveal_type(x1) # N: Revealed type is "__main__.A" |
| f = 0 |
| reveal_type(x1) # N: Revealed type is "__main__.A" |
| x2 = A() |
| if isinstance(x2, A) or isinstance(x2, C): |
| reveal_type(x2) # N: Revealed type is "__main__.A" |
| f = x2.flag # E: "A" has no attribute "flag" |
| else: |
| # unreachable |
| 1() |
| reveal_type(x2) # N: Revealed type is "__main__.A" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testComprehensionIsInstance] |
| from typing import List, Union |
| a = [] # type: List[Union[int, str]] |
| l = [x for x in a if isinstance(x, int)] |
| g = (x for x in a if isinstance(x, int)) |
| d = {0: x for x in a if isinstance(x, int)} |
| reveal_type(l) # N: Revealed type is "builtins.list[builtins.int]" |
| reveal_type(g) # N: Revealed type is "typing.Generator[builtins.int, None, None]" |
| reveal_type(d) # N: Revealed type is "builtins.dict[builtins.int, builtins.int]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsinstanceInWrongOrderInBooleanOp] |
| class A: |
| m = 1 |
| |
| def f(x: object) -> None: |
| if x.m and isinstance(x, A) or False: # E: "object" has no attribute "m" |
| pass |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceAndOr] |
| class A: |
| a = None # type: A |
| |
| def f(x: object) -> None: |
| b = isinstance(x, A) and x.a or A() |
| reveal_type(b) # N: Revealed type is "__main__.A" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceWithUnknownType] |
| from typing import Union |
| |
| def f(x: Union[int, str], typ: type) -> None: |
| if isinstance(x, (typ, int)): |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ |
| # N: Left operand is of type "Union[int, str]" |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.str" |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceWithBoundedType] |
| from typing import Union, Type |
| |
| class A: pass |
| |
| def f(x: Union[int, A], a: Type[A]) -> None: |
| if isinstance(x, (a, int)): |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, __main__.A]" |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.A" |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, __main__.A]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceWithEmtpy2ndArg] |
| from typing import Union |
| |
| def f(x: Union[int, str]) -> None: |
| if isinstance(x, ()): |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| else: |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceWithTypeObject] |
| from typing import Union, Type |
| |
| class A: pass |
| |
| def f(x: Union[int, A], a: Type[A]) -> None: |
| if isinstance(x, a): |
| reveal_type(x) # N: Revealed type is "__main__.A" |
| elif isinstance(x, int): |
| reveal_type(x) # N: Revealed type is "builtins.int" |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.A" |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, __main__.A]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIssubclassUnreachable] |
| from typing import Type, Sequence, Union |
| |
| x: Type[str] |
| if issubclass(x, int): |
| reveal_type(x) # unreachable block |
| |
| class X: pass |
| class Y(X): pass |
| class Z(X): pass |
| |
| a: Union[Type[Y], Type[Z]] |
| if issubclass(a, X): |
| reveal_type(a) # N: Revealed type is "Union[Type[__main__.Y], Type[__main__.Z]]" |
| else: |
| reveal_type(a) # unreachable block |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIssubclasDestructuringUnions1] |
| from typing import Union, List, Tuple, Dict, Type |
| def f(x: Union[Type[int], Type[str], Type[List]]) -> None: |
| if issubclass(x, (str, (int,))): |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.int], Type[builtins.str]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| x()[1] # E: Value of type "Union[int, str]" is not indexable |
| else: |
| reveal_type(x) # N: Revealed type is "Type[builtins.list[Any]]" |
| reveal_type(x()) # N: Revealed type is "builtins.list[Any]" |
| x()[1] |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.int], Type[builtins.str], Type[builtins.list[Any]]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.int, builtins.str, builtins.list[Any]]" |
| if issubclass(x, (str, (list,))): |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.str], Type[builtins.list[Any]]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.str, builtins.list[Any]]" |
| x()[1] |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.int], Type[builtins.str], Type[builtins.list[Any]]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.int, builtins.str, builtins.list[Any]]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIssubclasDestructuringUnions2] |
| from typing import Union, List, Tuple, Dict, Type |
| |
| def f(x: Type[Union[int, str, List]]) -> None: |
| if issubclass(x, (str, (int,))): |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.int], Type[builtins.str]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| x()[1] # E: Value of type "Union[int, str]" is not indexable |
| else: |
| reveal_type(x) # N: Revealed type is "Type[builtins.list[Any]]" |
| reveal_type(x()) # N: Revealed type is "builtins.list[Any]" |
| x()[1] |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.int], Type[builtins.str], Type[builtins.list[Any]]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.int, builtins.str, builtins.list[Any]]" |
| if issubclass(x, (str, (list,))): |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.str], Type[builtins.list[Any]]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.str, builtins.list[Any]]" |
| x()[1] |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.int], Type[builtins.str], Type[builtins.list[Any]]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.int, builtins.str, builtins.list[Any]]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIssubclasDestructuringUnions3] |
| from typing import Union, List, Tuple, Dict, Type |
| |
| def f(x: Type[Union[int, str, List]]) -> None: |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.int], Type[builtins.str], Type[builtins.list[Any]]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.int, builtins.str, builtins.list[Any]]" |
| if issubclass(x, (str, (int,))): |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.int], Type[builtins.str]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| x()[1] # E: Value of type "Union[int, str]" is not indexable |
| else: |
| reveal_type(x) # N: Revealed type is "Type[builtins.list[Any]]" |
| reveal_type(x()) # N: Revealed type is "builtins.list[Any]" |
| x()[1] |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.int], Type[builtins.str], Type[builtins.list[Any]]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.int, builtins.str, builtins.list[Any]]" |
| if issubclass(x, (str, (list,))): |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.str], Type[builtins.list[Any]]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.str, builtins.list[Any]]" |
| x()[1] |
| reveal_type(x) # N: Revealed type is "Union[Type[builtins.int], Type[builtins.str], Type[builtins.list[Any]]]" |
| reveal_type(x()) # N: Revealed type is "Union[builtins.int, builtins.str, builtins.list[Any]]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIssubclass] |
| from typing import Type, ClassVar |
| |
| class Goblin: |
| level: int |
| |
| class GoblinAmbusher(Goblin): |
| job: ClassVar[str] = 'Ranger' |
| |
| def test_issubclass(cls: Type[Goblin]) -> None: |
| if issubclass(cls, GoblinAmbusher): |
| reveal_type(cls) # N: Revealed type is "Type[__main__.GoblinAmbusher]" |
| cls.level |
| cls.job |
| ga = cls() |
| ga.level = 15 |
| ga.job |
| ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance |
| else: |
| reveal_type(cls) # N: Revealed type is "Type[__main__.Goblin]" |
| cls.level |
| cls.job # E: "Type[Goblin]" has no attribute "job" |
| g = cls() |
| g.level = 15 |
| g.job # E: "Goblin" has no attribute "job" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIssubclassDeepHierarchy] |
| from typing import Type, ClassVar |
| |
| class Mob: pass |
| |
| class Goblin(Mob): |
| level: int |
| |
| class GoblinAmbusher(Goblin): |
| job: ClassVar[str] = 'Ranger' |
| |
| def test_issubclass(cls: Type[Mob]) -> None: |
| if issubclass(cls, Goblin): |
| reveal_type(cls) # N: Revealed type is "Type[__main__.Goblin]" |
| cls.level |
| cls.job # E: "Type[Goblin]" has no attribute "job" |
| g = cls() |
| g.level = 15 |
| g.job # E: "Goblin" has no attribute "job" |
| if issubclass(cls, GoblinAmbusher): |
| reveal_type(cls) # N: Revealed type is "Type[__main__.GoblinAmbusher]" |
| cls.level |
| cls.job |
| g = cls() |
| g.level = 15 |
| g.job |
| g.job = 'Warrior' # E: Cannot assign to class variable "job" via instance |
| else: |
| reveal_type(cls) # N: Revealed type is "Type[__main__.Mob]" |
| cls.job # E: "Type[Mob]" has no attribute "job" |
| cls.level # E: "Type[Mob]" has no attribute "level" |
| m = cls() |
| m.level = 15 # E: "Mob" has no attribute "level" |
| m.job # E: "Mob" has no attribute "job" |
| if issubclass(cls, GoblinAmbusher): |
| reveal_type(cls) # N: Revealed type is "Type[__main__.GoblinAmbusher]" |
| cls.job |
| cls.level |
| ga = cls() |
| ga.level = 15 |
| ga.job |
| ga.job = 'Warrior' # E: Cannot assign to class variable "job" via instance |
| |
| if issubclass(cls, GoblinAmbusher): |
| reveal_type(cls) # N: Revealed type is "Type[__main__.GoblinAmbusher]" |
| cls.level |
| cls.job |
| ga = cls() |
| ga.level = 15 |
| ga.job |
| ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIssubclassTuple] |
| from typing import Type, ClassVar |
| |
| class Mob: pass |
| |
| class Goblin(Mob): |
| level: int |
| |
| class GoblinAmbusher(Goblin): |
| job: ClassVar[str] = 'Ranger' |
| |
| class GoblinDigger(Goblin): |
| job: ClassVar[str] = 'Thief' |
| |
| def test_issubclass(cls: Type[Mob]) -> None: |
| if issubclass(cls, (Goblin, GoblinAmbusher)): |
| reveal_type(cls) # N: Revealed type is "Type[__main__.Goblin]" |
| cls.level |
| cls.job # E: "Type[Goblin]" has no attribute "job" |
| g = cls() |
| g.level = 15 |
| g.job # E: "Goblin" has no attribute "job" |
| if issubclass(cls, GoblinAmbusher): |
| cls.level |
| reveal_type(cls) # N: Revealed type is "Type[__main__.GoblinAmbusher]" |
| cls.job |
| ga = cls() |
| ga.level = 15 |
| ga.job |
| ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance |
| else: |
| reveal_type(cls) # N: Revealed type is "Type[__main__.Mob]" |
| cls.job # E: "Type[Mob]" has no attribute "job" |
| cls.level # E: "Type[Mob]" has no attribute "level" |
| m = cls() |
| m.level = 15 # E: "Mob" has no attribute "level" |
| m.job # E: "Mob" has no attribute "job" |
| if issubclass(cls, GoblinAmbusher): |
| reveal_type(cls) # N: Revealed type is "Type[__main__.GoblinAmbusher]" |
| cls.job |
| cls.level |
| ga = cls() |
| ga.level = 15 |
| ga.job |
| ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance |
| |
| if issubclass(cls, (GoblinDigger, GoblinAmbusher)): |
| reveal_type(cls) # N: Revealed type is "Union[Type[__main__.GoblinDigger], Type[__main__.GoblinAmbusher]]" |
| cls.level |
| cls.job |
| g = cls() |
| g.level = 15 |
| g.job |
| g.job = "Warrior" # E: Cannot assign to class variable "job" via instance |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIssubclassBuiltins] |
| from typing import List, Type |
| |
| class MyList(List): pass |
| class MyIntList(List[int]): pass |
| |
| def f(cls: Type[object]) -> None: |
| if issubclass(cls, MyList): |
| reveal_type(cls) # N: Revealed type is "Type[__main__.MyList]" |
| cls()[0] |
| else: |
| reveal_type(cls) # N: Revealed type is "Type[builtins.object]" |
| cls()[0] # E: Value of type "object" is not indexable |
| |
| if issubclass(cls, MyIntList): |
| reveal_type(cls) # N: Revealed type is "Type[__main__.MyIntList]" |
| cls()[0] + 1 |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsinstanceTypeArgs] |
| from typing import Iterable, TypeVar |
| x = 1 |
| isinstance(x, Iterable) |
| isinstance(x, Iterable[int]) # E: Parameterized generics cannot be used with class or instance checks |
| isinstance(x, (int, Iterable[int])) # E: Parameterized generics cannot be used with class or instance checks |
| isinstance(x, (int, (str, Iterable[int]))) # E: Parameterized generics cannot be used with class or instance checks |
| [builtins fixtures/isinstancelist.pyi] |
| [typing fixtures/typing-full.pyi] |
| |
| [case testIsinstanceAnyAlias] |
| from typing import Any |
| A = Any |
| isinstance(object(), A) # E: Cannot use isinstance() with Any type |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceTypeArgsAliases] |
| from typing import Iterable, TypeVar |
| x = 1 |
| T = TypeVar('T') |
| It = Iterable |
| It2 = Iterable[T] |
| |
| isinstance(x, It[int]) # E: Parameterized generics cannot be used with class or instance checks |
| isinstance(x, It) |
| isinstance(x, It2[int]) # E: Parameterized generics cannot be used with class or instance checks |
| isinstance(x, It2) # E: Parameterized generics cannot be used with class or instance checks |
| [builtins fixtures/isinstance.pyi] |
| [typing fixtures/typing-full.pyi] |
| |
| [case testIssubclassTypeArgs] |
| from typing import Iterable, TypeVar |
| x = int |
| issubclass(x, Iterable) |
| issubclass(x, Iterable[int]) # E: Parameterized generics cannot be used with class or instance checks |
| issubclass(x, (int, Iterable[int])) # E: Parameterized generics cannot be used with class or instance checks |
| [builtins fixtures/isinstance.pyi] |
| [typing fixtures/typing-full.pyi] |
| |
| [case testIssubclassWithMetaclasses] |
| # flags: --no-strict-optional |
| class FooMetaclass(type): ... |
| class Foo(metaclass=FooMetaclass): ... |
| class Bar: ... |
| |
| fm: FooMetaclass |
| reveal_type(fm) # N: Revealed type is "__main__.FooMetaclass" |
| if issubclass(fm, Foo): |
| reveal_type(fm) # N: Revealed type is "Type[__main__.Foo]" |
| if issubclass(fm, Bar): |
| reveal_type(fm) # N: Revealed type is "None" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIssubclassWithMetaclassesStrictOptional] |
| class FooMetaclass(type): ... |
| class BarMetaclass(type): ... |
| class Foo(metaclass=FooMetaclass): ... |
| class Bar(metaclass=BarMetaclass): ... |
| class Baz: ... |
| |
| fm: FooMetaclass |
| reveal_type(fm) # N: Revealed type is "__main__.FooMetaclass" |
| if issubclass(fm, Foo): |
| reveal_type(fm) # N: Revealed type is "Type[__main__.Foo]" |
| if issubclass(fm, Bar): |
| reveal_type(fm) # N: Revealed type is "<nothing>" |
| if issubclass(fm, Baz): |
| reveal_type(fm) # N: Revealed type is "<nothing>" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceAndNarrowTypeVariable] |
| from typing import TypeVar |
| |
| class A: pass |
| class B(A): pass |
| |
| T = TypeVar('T', bound=A) |
| |
| def f(x: T) -> None: |
| if isinstance(x, B): |
| reveal_type(x) # N: Revealed type is "__main__.B" |
| else: |
| reveal_type(x) # N: Revealed type is "T`-1" |
| reveal_type(x) # N: Revealed type is "T`-1" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceAndTypeType] |
| from typing import Type |
| def f(x: Type[int]) -> None: |
| if isinstance(x, type): |
| reveal_type(x) # N: Revealed type is "Type[builtins.int]" |
| else: |
| reveal_type(x) # Unreachable |
| reveal_type(x) # N: Revealed type is "Type[builtins.int]" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceVariableSubstitution] |
| T = (int, str) |
| U = (list, T) |
| x: object = None |
| |
| if isinstance(x, T): |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| |
| if isinstance(x, U): |
| reveal_type(x) # N: Revealed type is "Union[builtins.list[Any], builtins.int, builtins.str]" |
| |
| if isinstance(x, (set, (list, T))): |
| reveal_type(x) # N: Revealed type is "Union[builtins.set[Any], builtins.list[Any], builtins.int, builtins.str]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceTooFewArgs] |
| isinstance() # E: Missing positional arguments "x", "t" in call to "isinstance" |
| x: object |
| if isinstance(): # E: Missing positional arguments "x", "t" in call to "isinstance" |
| x = 1 |
| reveal_type(x) # N: Revealed type is "builtins.int" |
| if isinstance(x): # E: Missing positional argument "t" in call to "isinstance" |
| x = 1 |
| reveal_type(x) # N: Revealed type is "builtins.int" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsSubclassTooFewArgs] |
| from typing import Type |
| |
| issubclass() # E: Missing positional arguments "x", "t" in call to "issubclass" |
| y: Type[object] |
| if issubclass(): # E: Missing positional arguments "x", "t" in call to "issubclass" |
| reveal_type(y) # N: Revealed type is "Type[builtins.object]" |
| if issubclass(y): # E: Missing positional argument "t" in call to "issubclass" |
| reveal_type(y) # N: Revealed type is "Type[builtins.object]" |
| |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceTooManyArgs] |
| isinstance(1, 1, 1) # E: Too many arguments for "isinstance" \ |
| # E: Argument 2 to "isinstance" has incompatible type "int"; expected "Union[type, Tuple[Any, ...]]" |
| x: object |
| if isinstance(x, str, 1): # E: Too many arguments for "isinstance" |
| reveal_type(x) # N: Revealed type is "builtins.object" |
| x = 1 |
| reveal_type(x) # N: Revealed type is "builtins.int" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsinstanceNarrowAny] |
| from typing import Any |
| |
| def narrow_any_to_str_then_reassign_to_int() -> None: |
| v = 1 # type: Any |
| |
| if isinstance(v, str): |
| reveal_type(v) # N: Revealed type is "builtins.str" |
| v = 2 |
| reveal_type(v) # N: Revealed type is "Any" |
| |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testNarrowTypeAfterInList] |
| from typing import List, Optional |
| |
| x: List[int] |
| y: Optional[int] |
| |
| if y in x: |
| reveal_type(y) # N: Revealed type is "builtins.int" |
| else: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| if y not in x: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| else: |
| reveal_type(y) # N: Revealed type is "builtins.int" |
| [builtins fixtures/list.pyi] |
| [out] |
| |
| [case testNarrowTypeAfterInListOfOptional] |
| from typing import List, Optional |
| |
| x: List[Optional[int]] |
| y: Optional[int] |
| |
| if y not in x: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| else: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| [builtins fixtures/list.pyi] |
| [out] |
| |
| [case testNarrowTypeAfterInListNonOverlapping] |
| from typing import List, Optional |
| |
| x: List[str] |
| y: Optional[int] |
| |
| if y in x: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| else: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| [builtins fixtures/list.pyi] |
| [out] |
| |
| [case testNarrowTypeAfterInListNested] |
| from typing import List, Optional, Any |
| |
| x: Optional[int] |
| lst: Optional[List[int]] |
| nested_any: List[List[Any]] |
| |
| if lst in nested_any: |
| reveal_type(lst) # N: Revealed type is "builtins.list[builtins.int]" |
| if x in nested_any: |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, None]" |
| [builtins fixtures/list.pyi] |
| [out] |
| |
| [case testNarrowTypeAfterInTuple] |
| from typing import Optional |
| class A: pass |
| class B(A): pass |
| class C(A): pass |
| |
| y: Optional[B] |
| if y in (B(), C()): |
| reveal_type(y) # N: Revealed type is "__main__.B" |
| else: |
| reveal_type(y) # N: Revealed type is "Union[__main__.B, None]" |
| [builtins fixtures/tuple.pyi] |
| [out] |
| |
| [case testNarrowTypeAfterInNamedTuple] |
| from typing import NamedTuple, Optional |
| class NT(NamedTuple): |
| x: int |
| y: int |
| nt: NT |
| |
| y: Optional[int] |
| if y not in nt: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| else: |
| reveal_type(y) # N: Revealed type is "builtins.int" |
| [builtins fixtures/tuple.pyi] |
| [out] |
| |
| [case testNarrowTypeAfterInDict] |
| from typing import Dict, Optional |
| x: Dict[str, int] |
| y: Optional[str] |
| |
| if y in x: |
| reveal_type(y) # N: Revealed type is "builtins.str" |
| else: |
| reveal_type(y) # N: Revealed type is "Union[builtins.str, None]" |
| if y not in x: |
| reveal_type(y) # N: Revealed type is "Union[builtins.str, None]" |
| else: |
| reveal_type(y) # N: Revealed type is "builtins.str" |
| [builtins fixtures/dict.pyi] |
| [out] |
| |
| [case testNarrowTypeAfterInNoAnyOrObject] |
| from typing import Any, List, Optional |
| x: List[Any] |
| z: List[object] |
| |
| y: Optional[int] |
| if y in x: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| else: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| |
| if y not in z: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| else: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| [typing fixtures/typing-medium.pyi] |
| [builtins fixtures/list.pyi] |
| [out] |
| |
| [case testNarrowTypeAfterInUserDefined] |
| from typing import Container, Optional |
| |
| class C(Container[int]): |
| def __contains__(self, item: object) -> bool: |
| return item is 'surprise' |
| |
| y: Optional[int] |
| # We never trust user defined types |
| if y in C(): |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| else: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| if y not in C(): |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| else: |
| reveal_type(y) # N: Revealed type is "Union[builtins.int, None]" |
| [typing fixtures/typing-full.pyi] |
| [builtins fixtures/list.pyi] |
| [out] |
| |
| [case testNarrowTypeAfterInSet] |
| from typing import Optional, Set |
| s: Set[str] |
| |
| y: Optional[str] |
| if y in {'a', 'b', 'c'}: |
| reveal_type(y) # N: Revealed type is "builtins.str" |
| else: |
| reveal_type(y) # N: Revealed type is "Union[builtins.str, None]" |
| if y not in s: |
| reveal_type(y) # N: Revealed type is "Union[builtins.str, None]" |
| else: |
| reveal_type(y) # N: Revealed type is "builtins.str" |
| [builtins fixtures/set.pyi] |
| [out] |
| |
| [case testNarrowTypeAfterInTypedDict] |
| from typing import Optional |
| from mypy_extensions import TypedDict |
| class TD(TypedDict): |
| a: int |
| b: str |
| td: TD |
| |
| def f() -> None: |
| x: Optional[str] |
| if x not in td: |
| return |
| reveal_type(x) # N: Revealed type is "builtins.str" |
| [typing fixtures/typing-typeddict.pyi] |
| [builtins fixtures/dict.pyi] |
| [out] |
| |
| [case testIsinstanceWidensWithAnyArg] |
| from typing import Any |
| class A: ... |
| B: Any |
| x: A |
| x.foo() # E: "A" has no attribute "foo" |
| assert isinstance(x, B) |
| x.foo() |
| reveal_type(x) # N: Revealed type is "Any" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceWidensUnionWithAnyArg] |
| from typing import Any, Union |
| class A: ... |
| B: Any |
| x: Union[A, B] |
| reveal_type(x) # N: Revealed type is "Union[__main__.A, Any]" |
| assert isinstance(x, B) |
| reveal_type(x) # N: Revealed type is "Any" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceIgnoredImport] |
| from typing import Union |
| from foo import A # type: ignore |
| def f(x: Union[A, str]) -> None: |
| x.method_only_in_a() # E: Item "str" of "Union[Any, str]" has no attribute "method_only_in_a" |
| if isinstance(x, A): |
| x.method_only_in_a() |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsinstanceIgnoredImportDualAny] |
| from typing import Any |
| from foo import Bad, OtherBad # type: ignore |
| x: Any |
| if isinstance(x, Bad): |
| reveal_type(x) # N: Revealed type is "Any" |
| else: |
| reveal_type(x) # N: Revealed type is "Any" |
| |
| if isinstance(x, (Bad, OtherBad)): |
| reveal_type(x) # N: Revealed type is "Any" |
| else: |
| reveal_type(x) # N: Revealed type is "Any" |
| |
| y: object |
| if isinstance(y, Bad): |
| reveal_type(y) # N: Revealed type is "Any" |
| else: |
| reveal_type(y) # N: Revealed type is "builtins.object" |
| |
| class Ok: pass |
| z: Any |
| if isinstance(z, Ok): |
| reveal_type(z) # N: Revealed type is "__main__.Ok" |
| else: |
| reveal_type(z) # N: Revealed type is "Any" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceInitialNoneCheckSkipsImpossibleCasesNoStrictOptional] |
| from typing import Optional, Union |
| |
| class A: pass |
| |
| def foo1(x: Union[A, str, None]) -> None: |
| if x is None: |
| reveal_type(x) # N: Revealed type is "None" |
| elif isinstance(x, A): |
| reveal_type(x) # N: Revealed type is "__main__.A" |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.str" |
| |
| def foo2(x: Optional[str]) -> None: |
| if x is None: |
| reveal_type(x) # N: Revealed type is "None" |
| elif isinstance(x, A): |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "str" and "A">" |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.str" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceInitialNoneCheckSkipsImpossibleCasesInNoStrictOptional] |
| # flags: --no-strict-optional |
| from typing import Optional, Union |
| |
| class A: pass |
| |
| def foo1(x: Union[A, str, None]) -> None: |
| if x is None: |
| reveal_type(x) # N: Revealed type is "None" |
| elif isinstance(x, A): |
| # Note that Union[None, A] == A in no-strict-optional |
| reveal_type(x) # N: Revealed type is "__main__.A" |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.str" |
| |
| def foo2(x: Optional[str]) -> None: |
| if x is None: |
| reveal_type(x) # N: Revealed type is "None" |
| elif isinstance(x, A): |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "str" and "A">" |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.str" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testNoneCheckDoesNotNarrowWhenUsingTypeVars] |
| |
| # Note: this test (and the following one) are testing checker.conditional_type_map: |
| # if you set the 'prohibit_none_typevar_overlap' keyword argument to False when calling |
| # 'is_overlapping_types', the binder will incorrectly infer that 'out' has a type of |
| # Union[T, None] after the if statement. |
| |
| from typing import TypeVar |
| |
| T = TypeVar('T') |
| |
| def foo(x: T) -> T: |
| out = None |
| out = x |
| if out is None: |
| pass |
| return out |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testNoneCheckDoesNotNarrowWhenUsingTypeVarsNoStrictOptional] |
| # flags: --no-strict-optional |
| from typing import TypeVar |
| |
| T = TypeVar('T') |
| |
| def foo(x: T) -> T: |
| out = None |
| out = x |
| if out is None: |
| pass |
| return out |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testNoneAndGenericTypesOverlapNoStrictOptional] |
| # flags: --no-strict-optional |
| from typing import Union, Optional, List |
| |
| # Note: this test is indirectly making sure meet.is_overlapping_types |
| # correctly ignores 'None' in unions. |
| |
| def foo(x: Optional[List[str]]) -> None: |
| reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.str], None]" |
| assert isinstance(x, list) |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" |
| |
| def bar(x: Union[List[str], List[int], None]) -> None: |
| reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.str], builtins.list[builtins.int], None]" |
| assert isinstance(x, list) |
| reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.str], builtins.list[builtins.int]]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testNoneAndGenericTypesOverlapStrictOptional] |
| from typing import Union, Optional, List |
| |
| # This test is the same as the one above, except for strict-optional. |
| # It isn't testing anything explicitly and mostly exists for the sake |
| # of completeness. |
| |
| def foo(x: Optional[List[str]]) -> None: |
| reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.str], None]" |
| assert isinstance(x, list) |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" |
| |
| def bar(x: Union[List[str], List[int], None]) -> None: |
| reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.str], builtins.list[builtins.int], None]" |
| assert isinstance(x, list) |
| reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.str], builtins.list[builtins.int]]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceWithStarExpression] |
| from typing import Union, List, Tuple |
| |
| def f(var: Union[List[str], Tuple[str, str], str]) -> None: |
| reveal_type(var) # N: Revealed type is "Union[builtins.list[builtins.str], Tuple[builtins.str, builtins.str], builtins.str]" |
| if isinstance(var, (list, *(str, int))): |
| reveal_type(var) # N: Revealed type is "Union[builtins.list[builtins.str], builtins.str]" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceWithStarExpressionAndVariable] |
| from typing import Union |
| |
| def f(var: Union[int, str]) -> None: |
| reveal_type(var) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| some_types = (str, tuple) |
| another_type = list |
| if isinstance(var, (*some_types, another_type)): |
| reveal_type(var) # N: Revealed type is "builtins.str" |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceWithWrongStarExpression] |
| var = 'some string' |
| if isinstance(var, *(str, int)): # E: Too many arguments for "isinstance" |
| pass |
| [builtins fixtures/isinstancelist.pyi] |
| |
| [case testIsInstanceAdHocIntersectionBasic] |
| class A: |
| def f1(self) -> int: ... |
| class B: |
| def f2(self) -> int: ... |
| class C: |
| def f3(self) -> int: ... |
| |
| x: A |
| if isinstance(x, B): |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "A" and "B">" |
| if isinstance(x, C): |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "A", "B", and "C">" |
| reveal_type(x.f1()) # N: Revealed type is "builtins.int" |
| reveal_type(x.f2()) # N: Revealed type is "builtins.int" |
| reveal_type(x.f3()) # N: Revealed type is "builtins.int" |
| x.bad() # E: "<subclass of "A", "B", and "C">" has no attribute "bad" |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "A" and "B">" |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.A" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionRepeatedChecks] |
| # flags: --warn-unreachable |
| |
| class A: pass |
| class B: pass |
| |
| x: A |
| if isinstance(x, B): |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "A" and "B">" |
| if isinstance(x, A): |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "A" and "B">" |
| if isinstance(x, B): |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "A" and "B">" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionIncompatibleClasses] |
| # flags: --warn-unreachable |
| class A: |
| def f(self) -> int: ... |
| class B: |
| def f(self) -> str: ... |
| class C: |
| def f(self) -> str: ... |
| |
| class Example(A, B): pass # E: Definition of "f" in base class "A" is incompatible with definition in base class "B" |
| x: A |
| if isinstance(x, B): # E: Subclass of "A" and "B" cannot exist: would have incompatible method signatures |
| reveal_type(x) # E: Statement is unreachable |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.A" |
| |
| y: C |
| if isinstance(y, B): |
| reveal_type(y) # N: Revealed type is "__main__.<subclass of "C" and "B">" |
| if isinstance(y, A): # E: Subclass of "C", "B", and "A" cannot exist: would have incompatible method signatures |
| reveal_type(y) # E: Statement is unreachable |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionReversed] |
| # flags: --warn-unreachable |
| |
| from abc import abstractmethod |
| from typing_extensions import Literal |
| |
| class A0: |
| def f(self) -> Literal[0]: |
| ... |
| |
| class A1: |
| def f(self) -> Literal[1]: |
| ... |
| |
| class A2: |
| def f(self) -> Literal[2]: |
| ... |
| |
| class B: |
| @abstractmethod |
| def f(self) -> Literal[1, 2]: |
| ... |
| |
| def t0(self) -> None: |
| if isinstance(self, A0): # E: Subclass of "B" and "A0" cannot exist: would have incompatible method signatures |
| x0: Literal[0] = self.f() # E: Statement is unreachable |
| |
| def t1(self) -> None: |
| if isinstance(self, A1): |
| reveal_type(self) # N: Revealed type is "__main__.<subclass of "A1" and "B">" |
| x0: Literal[0] = self.f() # E: Incompatible types in assignment (expression has type "Literal[1]", variable has type "Literal[0]") |
| x1: Literal[1] = self.f() |
| |
| def t2(self) -> None: |
| if isinstance(self, (A0, A1)): |
| reveal_type(self) # N: Revealed type is "__main__.<subclass of "A1" and "B">1" |
| x0: Literal[0] = self.f() # E: Incompatible types in assignment (expression has type "Literal[1]", variable has type "Literal[0]") |
| x1: Literal[1] = self.f() |
| |
| def t3(self) -> None: |
| if isinstance(self, (A1, A2)): |
| reveal_type(self) # N: Revealed type is "Union[__main__.<subclass of "A1" and "B">2, __main__.<subclass of "A2" and "B">]" |
| x0: Literal[0] = self.f() # E: Incompatible types in assignment (expression has type "Literal[1, 2]", variable has type "Literal[0]") |
| x1: Literal[1] = self.f() # E: Incompatible types in assignment (expression has type "Literal[1, 2]", variable has type "Literal[1]") |
| |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionGenerics] |
| # flags: --warn-unreachable |
| from typing import Generic, TypeVar |
| |
| class Parent: pass |
| class Child(Parent): pass |
| |
| T = TypeVar('T') |
| class A(Generic[T]): |
| def f(self) -> T: ... |
| class B: |
| def f(self) -> Parent: ... |
| |
| x: A[int] |
| if isinstance(x, B): # E: Subclass of "A[int]" and "B" cannot exist: would have incompatible method signatures |
| reveal_type(x) # E: Statement is unreachable |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.A[builtins.int]" |
| |
| y: A[Parent] |
| if isinstance(y, B): |
| reveal_type(y) # N: Revealed type is "__main__.<subclass of "A" and "B">" |
| reveal_type(y.f()) # N: Revealed type is "__main__.Parent" |
| else: |
| reveal_type(y) # N: Revealed type is "__main__.A[__main__.Parent]" |
| |
| z: A[Child] |
| if isinstance(z, B): |
| reveal_type(z) # N: Revealed type is "__main__.<subclass of "A" and "B">1" |
| reveal_type(z.f()) # N: Revealed type is "__main__.Child" |
| else: |
| reveal_type(z) # N: Revealed type is "__main__.A[__main__.Child]" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionGenericsWithValues] |
| # flags: --warn-unreachable |
| from typing import TypeVar |
| |
| class A: |
| attr: int |
| class B: |
| attr: int |
| class C: |
| attr: str |
| |
| T1 = TypeVar('T1', A, B) |
| def f1(x: T1) -> T1: |
| if isinstance(x, A): |
| reveal_type(x) # N: Revealed type is "__main__.A" \ |
| # N: Revealed type is "__main__.<subclass of "B" and "A">" |
| if isinstance(x, B): |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "A" and "B">" \ |
| # N: Revealed type is "__main__.<subclass of "B" and "A">" |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.A" |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.B" |
| return x |
| |
| T2 = TypeVar('T2', B, C) |
| def f2(x: T2) -> T2: |
| if isinstance(x, B): |
| reveal_type(x) # N: Revealed type is "__main__.B" |
| # Note: even though --warn-unreachable is set, we don't report |
| # errors for the below: we don't yet have a way of filtering out |
| # reachability errors that occur for only one variation of the |
| # TypeVar yet. |
| if isinstance(x, C): |
| reveal_type(x) |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.B" |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.C" |
| return x |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionGenericsWithValuesDirectReturn] |
| # flags: --warn-unreachable |
| from typing import TypeVar |
| |
| class A: |
| attr: int |
| class B: |
| attr: int |
| class C: |
| attr: str |
| |
| T1 = TypeVar('T1', A, B) |
| def f1(x: T1) -> T1: |
| if isinstance(x, A): |
| # The error message is confusing, but we indeed do run into problems if |
| # 'x' is a subclass of A and B |
| return A() # E: Incompatible return value type (got "A", expected "B") |
| else: |
| return B() |
| |
| T2 = TypeVar('T2', B, C) |
| def f2(x: T2) -> T2: |
| if isinstance(x, B): |
| # In contrast, it's impossible for a subclass of "B" and "C" to |
| # exist, so this is fine |
| return B() |
| else: |
| return C() |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionUsage] |
| # flags: --warn-unreachable |
| class A: pass |
| class B: pass |
| class Concrete(A, B): pass |
| |
| def accept_a(a: A) -> None: pass |
| def accept_b(a: B) -> None: pass |
| def accept_concrete(c: Concrete) -> None: pass |
| |
| x: A |
| if isinstance(x, B): |
| var = x |
| reveal_type(var) # N: Revealed type is "__main__.<subclass of "A" and "B">" |
| accept_a(var) |
| accept_b(var) |
| accept_concrete(var) # E: Argument 1 to "accept_concrete" has incompatible type "<subclass of "A" and "B">"; expected "Concrete" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionReinfer] |
| # flags: --warn-unreachable |
| class A: pass |
| class B: pass |
| |
| x: A |
| assert isinstance(x, B) |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "A" and "B">" |
| |
| y: A |
| assert isinstance(y, B) |
| reveal_type(y) # N: Revealed type is "__main__.<subclass of "A" and "B">1" |
| |
| x = y |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "A" and "B">1" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionWithUnions] |
| # flags: --warn-unreachable |
| from typing import Type, Union |
| class A: pass |
| class B: pass |
| class C: pass |
| class D: pass |
| |
| v1: A |
| if isinstance(v1, (B, C)): |
| reveal_type(v1) # N: Revealed type is "Union[__main__.<subclass of "A" and "B">, __main__.<subclass of "A" and "C">]" |
| |
| v2: Union[A, B] |
| if isinstance(v2, C): |
| reveal_type(v2) # N: Revealed type is "Union[__main__.<subclass of "A" and "C">1, __main__.<subclass of "B" and "C">]" |
| |
| v3: Union[A, B] |
| if isinstance(v3, (C, D)): |
| reveal_type(v3) # N: Revealed type is "Union[__main__.<subclass of "A" and "C">2, __main__.<subclass of "A" and "D">, __main__.<subclass of "B" and "C">1, __main__.<subclass of "B" and "D">]" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionSameNames] |
| # flags: --warn-unreachable |
| from foo import A as A2 |
| class A: pass |
| |
| x: A |
| if isinstance(x, A2): |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "A" and "A">" |
| |
| [file foo.py] |
| class A: pass |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionBadMro] |
| # flags: --warn-unreachable |
| class X: pass |
| class Y: pass |
| class A(X, Y): pass |
| class B(Y, X): pass |
| |
| foo: A |
| if isinstance(foo, B): # E: Subclass of "A" and "B" cannot exist: would have inconsistent method resolution order |
| reveal_type(foo) # E: Statement is unreachable |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsInstanceAdHocIntersectionAmbiguousClass] |
| # flags: --warn-unreachable |
| from typing import Any |
| |
| class Concrete: |
| x: int |
| class Ambiguous: |
| x: Any |
| |
| # We bias towards assuming these two classes could be overlapping |
| foo: Concrete |
| if isinstance(foo, Ambiguous): |
| reveal_type(foo) # N: Revealed type is "__main__.<subclass of "Concrete" and "Ambiguous">" |
| reveal_type(foo.x) # N: Revealed type is "builtins.int" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIsSubclassAdHocIntersection] |
| # flags: --warn-unreachable |
| from typing import Type |
| |
| class A: |
| x: int |
| class B: |
| x: int |
| class C: |
| x: str |
| |
| x: Type[A] |
| if issubclass(x, B): |
| reveal_type(x) # N: Revealed type is "Type[__main__.<subclass of "A" and "B">]" |
| if issubclass(x, C): # E: Subclass of "A", "B", and "C" cannot exist: would have incompatible method signatures |
| reveal_type(x) # E: Statement is unreachable |
| else: |
| reveal_type(x) # N: Revealed type is "Type[__main__.<subclass of "A" and "B">]" |
| else: |
| reveal_type(x) # N: Revealed type is "Type[__main__.A]" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testTypeEqualsCheck] |
| from typing import Any |
| |
| y: Any |
| if type(y) == int: |
| reveal_type(y) # N: Revealed type is "builtins.int" |
| |
| |
| [case testMultipleTypeEqualsCheck] |
| from typing import Any |
| |
| x: Any |
| y: Any |
| if type(x) == type(y) == int: |
| reveal_type(y) # N: Revealed type is "builtins.int" |
| reveal_type(x) # N: Revealed type is "builtins.int" |
| |
| [case testTypeEqualsCheckUsingIs] |
| from typing import Any |
| |
| y: Any |
| if type(y) is int: |
| reveal_type(y) # N: Revealed type is "builtins.int" |
| |
| [case testTypeEqualsNarrowingUnionWithElse] |
| from typing import Union |
| |
| x: Union[int, str] |
| if type(x) is int: |
| reveal_type(x) # N: Revealed type is "builtins.int" |
| else: |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| |
| [case testTypeEqualsMultipleTypesShouldntNarrow] |
| # make sure we don't do any narrowing if there are multiple types being compared |
| |
| from typing import Union |
| |
| x: Union[int, str] |
| if type(x) == int == str: |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| else: |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| |
| # mypy thinks int isn't defined unless we include this |
| [builtins fixtures/primitives.pyi] |
| |
| [case testTypeNotEqualsCheck] |
| from typing import Union |
| |
| x: Union[int, str] |
| if type(x) != int: |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.int" |
| |
| # mypy thinks int isn't defined unless we include this |
| [builtins fixtures/primitives.pyi] |
| |
| [case testTypeNotEqualsCheckUsingIsNot] |
| from typing import Union |
| |
| x: Union[int, str] |
| if type(x) is not int: |
| reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" |
| else: |
| reveal_type(x) # N: Revealed type is "builtins.int" |
| |
| [case testNarrowInElseCaseIfFinal] |
| from typing import final, Union |
| @final |
| class C: |
| pass |
| class D: |
| pass |
| |
| x: Union[C, D] |
| if type(x) is C: |
| reveal_type(x) # N: Revealed type is "__main__.C" |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.D" |
| [case testNarrowInIfCaseIfFinalUsingIsNot] |
| from typing import final, Union |
| @final |
| class C: |
| pass |
| class D: |
| pass |
| |
| x: Union[C, D] |
| if type(x) is not C: |
| reveal_type(x) # N: Revealed type is "__main__.D" |
| else: |
| reveal_type(x) # N: Revealed type is "__main__.C" |
| |
| [case testHasAttrExistingAttribute] |
| class C: |
| x: int |
| c: C |
| if hasattr(c, "x"): |
| reveal_type(c.x) # N: Revealed type is "builtins.int" |
| else: |
| # We don't mark this unreachable since people may check for deleted attributes |
| reveal_type(c.x) # N: Revealed type is "builtins.int" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrMissingAttributeInstance] |
| class B: ... |
| b: B |
| if hasattr(b, "x"): |
| reveal_type(b.x) # N: Revealed type is "Any" |
| else: |
| b.x # E: "B" has no attribute "x" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrMissingAttributeFunction] |
| def foo(x: int) -> None: ... |
| if hasattr(foo, "x"): |
| reveal_type(foo.x) # N: Revealed type is "Any" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrMissingAttributeClassObject] |
| class C: ... |
| if hasattr(C, "x"): |
| reveal_type(C.x) # N: Revealed type is "Any" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrMissingAttributeTypeType] |
| from typing import Type |
| class C: ... |
| c: Type[C] |
| if hasattr(c, "x"): |
| reveal_type(c.x) # N: Revealed type is "Any" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrMissingAttributeTypeVar] |
| from typing import TypeVar |
| |
| T = TypeVar("T") |
| def foo(x: T) -> T: |
| if hasattr(x, "x"): |
| reveal_type(x.x) # N: Revealed type is "Any" |
| return x |
| else: |
| return x |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrMissingAttributeChained] |
| class B: ... |
| b: B |
| if hasattr(b, "x"): |
| reveal_type(b.x) # N: Revealed type is "Any" |
| elif hasattr(b, "y"): |
| reveal_type(b.y) # N: Revealed type is "Any" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrMissingAttributeNested] |
| class A: ... |
| class B: ... |
| |
| x: A |
| if hasattr(x, "x"): |
| if isinstance(x, B): |
| reveal_type(x.x) # N: Revealed type is "Any" |
| |
| if hasattr(x, "x") and hasattr(x, "y"): |
| reveal_type(x.x) # N: Revealed type is "Any" |
| reveal_type(x.y) # N: Revealed type is "Any" |
| |
| if hasattr(x, "x"): |
| if hasattr(x, "y"): |
| reveal_type(x.x) # N: Revealed type is "Any" |
| reveal_type(x.y) # N: Revealed type is "Any" |
| |
| if hasattr(x, "x") or hasattr(x, "y"): |
| x.x # E: "A" has no attribute "x" |
| x.y # E: "A" has no attribute "y" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrPreciseType] |
| class A: ... |
| |
| x: A |
| if hasattr(x, "a") and isinstance(x.a, int): |
| reveal_type(x.a) # N: Revealed type is "builtins.int" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrMissingAttributeUnion] |
| from typing import Union |
| |
| class A: ... |
| class B: |
| x: int |
| |
| xu: Union[A, B] |
| if hasattr(xu, "x"): |
| reveal_type(xu) # N: Revealed type is "Union[__main__.A, __main__.B]" |
| reveal_type(xu.x) # N: Revealed type is "Union[Any, builtins.int]" |
| else: |
| reveal_type(xu) # N: Revealed type is "__main__.A" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrMissingAttributeOuterUnion] |
| from typing import Union |
| |
| class A: ... |
| class B: ... |
| xu: Union[A, B] |
| if isinstance(xu, B): |
| if hasattr(xu, "x"): |
| reveal_type(xu.x) # N: Revealed type is "Any" |
| |
| if isinstance(xu, B) and hasattr(xu, "x"): |
| reveal_type(xu.x) # N: Revealed type is "Any" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrDoesntInterfereGetAttr] |
| class C: |
| def __getattr__(self, attr: str) -> str: ... |
| |
| c: C |
| if hasattr(c, "foo"): |
| reveal_type(c.foo) # N: Revealed type is "builtins.str" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrMissingAttributeLiteral] |
| from typing import Final |
| class B: ... |
| b: B |
| ATTR: Final = "x" |
| if hasattr(b, ATTR): |
| reveal_type(b.x) # N: Revealed type is "Any" |
| else: |
| b.x # E: "B" has no attribute "x" |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrDeferred] |
| def foo() -> str: ... |
| |
| class Test: |
| def stream(self) -> None: |
| if hasattr(self, "_body"): |
| reveal_type(self._body) # N: Revealed type is "builtins.str" |
| |
| def body(self) -> str: |
| if not hasattr(self, "_body"): |
| self._body = foo() |
| return self._body |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testHasAttrModule] |
| import mod |
| |
| if hasattr(mod, "y"): |
| reveal_type(mod.y) # N: Revealed type is "Any" |
| reveal_type(mod.x) # N: Revealed type is "builtins.int" |
| else: |
| mod.y # E: Module has no attribute "y" |
| reveal_type(mod.x) # N: Revealed type is "builtins.int" |
| |
| if hasattr(mod, "x"): |
| mod.y # E: Module has no attribute "y" |
| reveal_type(mod.x) # N: Revealed type is "builtins.int" |
| else: |
| mod.y # E: Module has no attribute "y" |
| reveal_type(mod.x) # N: Revealed type is "builtins.int" |
| |
| [file mod.py] |
| x: int |
| [builtins fixtures/module.pyi] |
| |
| [case testHasAttrDoesntInterfereModuleGetAttr] |
| import mod |
| |
| if hasattr(mod, "y"): |
| reveal_type(mod.y) # N: Revealed type is "builtins.str" |
| |
| [file mod.py] |
| def __getattr__(attr: str) -> str: ... |
| [builtins fixtures/module.pyi] |