-- Type checker test cases for conditional checks that result in some -- blocks classified as unreachable (they are not type checked or semantically -- analyzed). -- -- For example, we skip blocks that will not be executed on the active -- Python version. [case testConditionalTypeAliasPY3] import typing def f(): pass PY3 = f() if PY3: t = int x = object() + 'x' # E: Unsupported left operand type for + ("object") else: t = str y = 'x' / 1 x z = 1 # type: t [case testConditionalAssignmentPY2] import typing def f(): pass PY2 = f() if PY2: x = object() + 'x' else: y = 'x' / 1 # E: Unsupported left operand type for / ("str") y [case testConditionalImport] import typing def f(): pass PY2 = f() if PY2: import fuzzybar from barbar import * from pawwaw import a, bc else: import m [file m.py] import typing x = 1 if int(): x = 'a' [out] tmp/m.py:4: error: Incompatible types in assignment (expression has type "str", variable has type "int") [case testNegatedMypyConditional] import typing MYPY = 0 if not MYPY: import xyz753 else: import pow123 # E [builtins fixtures/bool.pyi] [out] main:6: error: Cannot find implementation or library stub for module named "pow123" main:6: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports [case testMypyConditional] import typing MYPY = 0 if MYPY: None + 1 # E: Unsupported left operand type for + ("None") else: None + '' [builtins fixtures/bool.pyi] [case testTypeCheckingConditional] import typing if typing.TYPE_CHECKING: import pow123 # E else: import xyz753 [typing fixtures/typing-medium.pyi] [out] main:3: error: Cannot find implementation or library stub for module named "pow123" main:3: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports [case testTypeCheckingConditionalFromImport] from typing import TYPE_CHECKING if TYPE_CHECKING: import pow123 # E else: import xyz753 [typing fixtures/typing-medium.pyi] [out] main:3: error: Cannot find implementation or library stub for module named "pow123" main:3: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports [case testNegatedTypeCheckingConditional] import typing if not typing.TYPE_CHECKING: import pow123 # E else: import xyz753 [builtins fixtures/bool.pyi] [typing fixtures/typing-medium.pyi] [out] main:5: error: Cannot find implementation or library stub for module named "xyz753" main:5: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports [case testUndefinedTypeCheckingConditional] if not TYPE_CHECKING: # E import pow123 else: import xyz753 [builtins fixtures/bool.pyi] [out] main:1: error: Name "TYPE_CHECKING" is not defined main:4: error: Cannot find implementation or library stub for module named "xyz753" main:4: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports [case testConditionalClassDefPY3] def f(): pass PY3 = f() if PY3: pass else: class X(object): pass [case testUnreachabilityAndElifPY3] def f(): pass PY3 = f() if PY3: pass elif bool(): import nonexistent 1 + '' else: import bad_name 1 + '' [builtins fixtures/bool.pyi] [out] [case testSysVersionInfo] import sys if sys.version_info[0] >= 3: def foo() -> int: return 0 else: def foo() -> str: return '' reveal_type(foo()) # N: Revealed type is "builtins.int" [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoReversedOperandsOrder] import sys if (3,) <= sys.version_info: def foo() -> int: return 0 else: def foo() -> str: return '' reveal_type(foo()) # N: Revealed type is "builtins.int" [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoNegated] import sys if not (sys.version_info[0] < 3): def foo() -> int: return 0 else: def foo() -> str: return '' reveal_type(foo()) # N: Revealed type is "builtins.int" [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoSliced1] import sys if sys.version_info[:1] >= (3,): def foo() -> int: return 0 else: def foo() -> str: return '' foo() + 0 [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoSliced2] import sys if sys.version_info[:2] >= (3, 0): def foo() -> int: return 0 else: def foo() -> str: return '' foo() + 0 [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoSliced3] import sys if sys.version_info[:] >= (3, 0): def foo() -> int: return 0 else: def foo() -> str: return '' foo() + 0 [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoSliced4] import sys if sys.version_info[0:2] >= (3, 0): def foo() -> int: return 0 else: def foo() -> str: return '' foo() + 0 [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoSliced5] import sys if sys.version_info[0:] >= (3,): def foo() -> int: return 0 else: def foo() -> str: return '' foo() + 0 [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoSliced6] import sys if sys.version_info[1:] >= (5,): def foo() -> int: return 0 else: def foo() -> str: return '' foo() + 0 [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoSliced7] import sys if sys.version_info >= (3, 5): def foo() -> int: return 0 else: def foo() -> str: return '' foo() + 0 [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoSliced8] # Our pyversion only has (major, minor), # so testing for (major, minor, bugfix) is unsupported. import sys if sys.version_info >= (3, 5, 0): def foo() -> int: return 0 else: def foo() -> str: return '' # E: All conditional function variants must have identical signatures \ # N: Original: \ # N: def foo() -> int \ # N: Redefinition: \ # N: def foo() -> str [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoSliced9] # Our pyversion only has (major, minor), # so testing for (minor, bugfix) is unsupported (also it's silly :-). import sys if sys.version_info[1:] >= (5, 0): def foo() -> int: return 0 else: def foo() -> str: return '' # E: All conditional function variants must have identical signatures \ # N: Original: \ # N: def foo() -> int \ # N: Redefinition: \ # N: def foo() -> str [builtins fixtures/ops.pyi] [out] [case testSysPlatform1] import sys if sys.platform == 'fictional': def foo() -> int: return 0 else: def foo() -> str: return '' foo() + '' [builtins fixtures/ops.pyi] [out] [case testSysPlatform2] import sys if sys.platform != 'fictional': def foo() -> int: return 0 else: def foo() -> str: return '' foo() + 0 [builtins fixtures/ops.pyi] [out] [case testSysPlatformNegated] import sys if not (sys.platform == 'fictional'): def foo() -> int: return 0 else: def foo() -> str: return '' foo() + 0 [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoClass] import sys if sys.version_info < (3, 5): class C: pass else: class C: def foo(self) -> int: return 0 C().foo() + 0 [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoImport] import sys if sys.version_info >= (3, 5): import collections else: collections = None Pt = collections.namedtuple('Pt', 'x y z') [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoVariable] import sys if sys.version_info >= (3, 5): x = '' else: x = 0 x + '' [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoInClass] import sys class C: if sys.version_info >= (3, 5): def foo(self) -> int: return 0 else: def foo(self) -> str: return '' reveal_type(C().foo()) # N: Revealed type is "builtins.int" [builtins fixtures/ops.pyi] [out] [case testSysVersionInfoInFunction] import sys def foo() -> None: if sys.version_info >= (3, 5): x = '' else: x = 0 reveal_type(x) # N: Revealed type is "builtins.str" [builtins fixtures/ops.pyi] [out] [case testSysPlatformInMethod] import sys class C: def foo(self) -> None: if sys.platform != 'fictional': x = '' else: x = 0 reveal_type(x) # N: Revealed type is "builtins.str" [builtins fixtures/ops.pyi] [out] [case testSysPlatformInFunctionImport1] import sys def foo() -> None: if sys.platform != 'fictional': import a else: import b as a a.x [file a.py] x = 1 [builtins fixtures/ops.pyi] [out] [case testSysPlatformInFunctionImport2] import sys def foo() -> None: if sys.platform == 'fictional': import b as a else: import a a.x [file a.py] x = 1 [builtins fixtures/ops.pyi] [out] [case testSysPlatformInFunctionImport3] from typing import Callable import sys def idf(x: Callable[[], None]) -> Callable[[], None]: return x @idf def foo() -> None: if sys.platform == 'fictional': import b as a else: import a a.x [file a.py] x = 1 [builtins fixtures/ops.pyi] [out] [case testSysPlatformInMethodImport2] import sys class A: def foo(self) -> None: if sys.platform == 'fictional': import b as a else: import a a.x [file a.py] x = 1 [builtins fixtures/ops.pyi] [out] [case testCustomSysVersionInfo] # flags: --python-version 3.11 import sys if sys.version_info >= (3, 11): x = "foo" else: x = 3 reveal_type(x) # N: Revealed type is "builtins.str" [builtins fixtures/ops.pyi] [case testCustomSysVersionInfo2] # flags: --python-version 3.11 import sys if sys.version_info >= (3, 12): x = "foo" else: x = 3 reveal_type(x) # N: Revealed type is "builtins.int" [builtins fixtures/ops.pyi] [case testCustomSysPlatform] # flags: --platform linux import sys if sys.platform == 'linux': x = "foo" else: x = 3 reveal_type(x) # N: Revealed type is "builtins.str" [builtins fixtures/ops.pyi] [out] [case testCustomSysPlatform2_no_native_parse] # flags: --platform win32 import sys if sys.platform == 'linux': x = "foo" else: x = 3 reveal_type(x) # N: Revealed type is "builtins.int" [builtins fixtures/ops.pyi] [out] [case testCustomSysPlatformStartsWith_no_native_parse] # flags: --platform win32 import sys if sys.platform.startswith('win'): x = "foo" else: x = 3 reveal_type(x) # N: Revealed type is "builtins.str" [builtins fixtures/ops.pyi] [out] [case testShortCircuitInExpression] import typing def make() -> bool: pass PY2 = PY3 = make() a = PY2 and str() b = PY3 and str() c = PY2 or str() d = PY3 or str() e = (PY2 or PY3) and str() f = (PY3 or PY2) and str() g = (PY2 or PY3) or str() h = (PY3 or PY2) or str() reveal_type(a) # N: Revealed type is "builtins.bool" reveal_type(b) # N: Revealed type is "builtins.str" reveal_type(c) # N: Revealed type is "builtins.str" reveal_type(d) # N: Revealed type is "builtins.bool" reveal_type(e) # N: Revealed type is "builtins.str" reveal_type(f) # N: Revealed type is "builtins.str" reveal_type(g) # N: Revealed type is "builtins.bool" reveal_type(h) # N: Revealed type is "builtins.bool" [builtins fixtures/ops.pyi] [out] [case testConditionalValuesBinaryOps] # flags: --platform linux import sys t_and_t = (sys.platform == 'linux' and sys.platform == 'linux') and str() t_or_t = (sys.platform == 'linux' or sys.platform == 'linux') and str() t_and_f = (sys.platform == 'linux' and sys.platform == 'windows') and str() t_or_f = (sys.platform == 'linux' or sys.platform == 'windows') and str() f_and_t = (sys.platform == 'windows' and sys.platform == 'linux') and str() f_or_t = (sys.platform == 'windows' or sys.platform == 'linux') and str() f_and_f = (sys.platform == 'windows' and sys.platform == 'windows') and str() f_or_f = (sys.platform == 'windows' or sys.platform == 'windows') and str() reveal_type(t_and_t) # N: Revealed type is "builtins.str" reveal_type(t_or_t) # N: Revealed type is "builtins.str" reveal_type(f_and_t) # N: Revealed type is "builtins.bool" reveal_type(f_or_t) # N: Revealed type is "builtins.str" reveal_type(t_and_f) # N: Revealed type is "builtins.bool" reveal_type(t_or_f) # N: Revealed type is "builtins.str" reveal_type(f_and_f) # N: Revealed type is "builtins.bool" reveal_type(f_or_f) # N: Revealed type is "builtins.bool" [builtins fixtures/ops.pyi] [case testConditionalValuesNegation] # flags: --platform linux import sys not_t = not sys.platform == 'linux' and str() not_f = not sys.platform == 'windows' and str() not_and_t = not (sys.platform == 'linux' and sys.platform == 'linux') and str() not_and_f = not (sys.platform == 'linux' and sys.platform == 'windows') and str() not_or_t = not (sys.platform == 'linux' or sys.platform == 'linux') and str() not_or_f = not (sys.platform == 'windows' or sys.platform == 'windows') and str() reveal_type(not_t) # N: Revealed type is "builtins.bool" reveal_type(not_f) # N: Revealed type is "builtins.str" reveal_type(not_and_t) # N: Revealed type is "builtins.bool" reveal_type(not_and_f) # N: Revealed type is "builtins.str" reveal_type(not_or_t) # N: Revealed type is "builtins.bool" reveal_type(not_or_f) # N: Revealed type is "builtins.str" [builtins fixtures/ops.pyi] [case testConditionalValuesUnsupportedOps] # flags: --platform linux import sys unary_minus = -(sys.platform == 'linux') and str() binary_minus = ((sys.platform == 'linux') - (sys.platform == 'linux')) and str() reveal_type(unary_minus) # N: Revealed type is "Literal[0] | builtins.str" reveal_type(binary_minus) # N: Revealed type is "Literal[0] | builtins.str" [builtins fixtures/ops.pyi] [case testMypyFalseValuesInBinaryOps_no_empty] # flags: --platform linux import sys from typing import TYPE_CHECKING MYPY = 0 if TYPE_CHECKING and sys.platform == 'linux': def foo1() -> int: ... if sys.platform == 'linux' and TYPE_CHECKING: def foo2() -> int: ... if MYPY and sys.platform == 'linux': def foo3() -> int: ... if sys.platform == 'linux' and MYPY: def foo4() -> int: ... if TYPE_CHECKING or sys.platform == 'linux': def bar1() -> int: ... # E: Missing return statement if sys.platform == 'linux' or TYPE_CHECKING: def bar2() -> int: ... # E: Missing return statement if MYPY or sys.platform == 'linux': def bar3() -> int: ... # E: Missing return statement if sys.platform == 'linux' or MYPY: def bar4() -> int: ... # E: Missing return statement [builtins fixtures/ops.pyi] [case testShortCircuitAndWithConditionalAssignment] # flags: --platform linux import sys def f(): pass PY2 = f() if PY2 and sys.platform == 'linux': x = 'foo' else: x = 3 reveal_type(x) # N: Revealed type is "builtins.int" if sys.platform == 'linux' and PY2: y = 'foo' else: y = 3 reveal_type(y) # N: Revealed type is "builtins.int" [builtins fixtures/ops.pyi] [case testShortCircuitOrWithConditionalAssignment] # flags: --platform linux import sys def f(): pass PY2 = f() if PY2 or sys.platform == 'linux': x = 'foo' else: x = 3 reveal_type(x) # N: Revealed type is "builtins.str" if sys.platform == 'linux' or PY2: y = 'foo' else: y = 3 reveal_type(y) # N: Revealed type is "builtins.str" [builtins fixtures/ops.pyi] [case testShortCircuitNoEvaluation] # flags: --platform linux --always-false COMPILE_TIME_FALSE import sys if sys.platform == 'darwin': mac_only = 'junk' # `mac_only` should not be evaluated if sys.platform == 'darwin' and mac_only: pass if sys.platform == 'linux' or mac_only: pass COMPILE_TIME_FALSE = 'junk' if COMPILE_TIME_FALSE: compile_time_false_only = 'junk' # `compile_time_false_only` should not be evaluated if COMPILE_TIME_FALSE and compile_time_false_only: pass if not COMPILE_TIME_FALSE or compile_time_false_only: pass MYPY = False if not MYPY: mypy_only = 'junk' # `mypy_only` should not be evaluated if not MYPY and mypy_only: pass if MYPY or mypy_only: pass [builtins fixtures/ops.pyi] [case testSemanticAnalysisFalseButTypeNarrowingTrue] # flags: --always-false COMPILE_TIME_FALSE from typing import Literal indeterminate: str COMPILE_TIME_FALSE: Literal[True] # type-narrowing: mapped in 'if' only a = COMPILE_TIME_FALSE or indeterminate reveal_type(a) # N: Revealed type is "builtins.str" b = indeterminate or COMPILE_TIME_FALSE reveal_type(b) # N: Revealed type is "builtins.str | Literal[True]" [typing fixtures/typing-medium.pyi] [case testSemanticAnalysisTrueButTypeNarrowingFalse] # flags: --always-true COMPILE_TIME_TRUE from typing import Literal indeterminate: str COMPILE_TIME_TRUE: Literal[False] # type narrowed to `else` only a = COMPILE_TIME_TRUE or indeterminate reveal_type(a) # N: Revealed type is "Literal[False]" b = indeterminate or COMPILE_TIME_TRUE reveal_type(b) # N: Revealed type is "builtins.str | Literal[False]" [typing fixtures/typing-medium.pyi] [case testConditionalAssertWithoutElse] import typing class A: pass class B(A): pass x = A() reveal_type(x) # N: Revealed type is "__main__.A" if typing.TYPE_CHECKING: assert isinstance(x, B) reveal_type(x) # N: Revealed type is "__main__.B" reveal_type(x) # N: Revealed type is "__main__.B" [builtins fixtures/isinstancelist.pyi] [typing fixtures/typing-medium.pyi] [case testUnreachableWhenSuperclassIsAny] from typing import Any # This can happen if we're importing a class from a missing module Parent: Any class Child(Parent): def foo(self) -> int: reveal_type(self) # N: Revealed type is "__main__.Child" if self is None: reveal_type(self) return None reveal_type(self) # N: Revealed type is "__main__.Child" return 3 def bar(self) -> int: if 1: self = super(Child, self).something() reveal_type(self) # N: Revealed type is "__main__.Child" if self is None: reveal_type(self) return None reveal_type(self) # N: Revealed type is "__main__.Child" return 3 [builtins fixtures/isinstance.pyi] [case testUnreachableWhenSuperclassIsAnyNoStrictOptional] # flags: --no-strict-optional from typing import Any Parent: Any class Child(Parent): def foo(self) -> int: reveal_type(self) # N: Revealed type is "__main__.Child" if self is None: reveal_type(self) # N: Revealed type is "None" return None reveal_type(self) # N: Revealed type is "__main__.Child" return 3 [builtins fixtures/isinstance.pyi] [case testUnreachableAfterToplevelAssert] import sys reveal_type(0) # N: Revealed type is "Literal[0]?" assert sys.platform == 'lol' reveal_type('') # No error here :-) [builtins fixtures/ops.pyi] [case testUnreachableAfterToplevelAssert2] import sys reveal_type(0) # N: Revealed type is "Literal[0]?" assert sys.version_info[0] == 1 reveal_type('') # No error here :-) [builtins fixtures/ops.pyi] [case testUnreachableAfterToplevelAssert3] reveal_type(0) # N: Revealed type is "Literal[0]?" MYPY = False assert not MYPY reveal_type('') # No error here :-) [builtins fixtures/ops.pyi] [case testUnreachableAfterToplevelAssert4] # flags: --always-false NOPE reveal_type(0) # N: Revealed type is "Literal[0]?" NOPE = False assert NOPE reveal_type('') # No error here :-) [builtins fixtures/ops.pyi] [case testUnreachableAfterToplevelAssertImport] import foo foo.bar() # E: "object" has no attribute "bar" [file foo.py] import sys assert sys.platform == 'lol' def bar() -> None: pass [builtins fixtures/ops.pyi] [case testUnreachableAfterToplevelAssertImport2] # flags: --platform lol import foo foo.bar() # No error :-) [file foo.py] import sys assert sys.platform == 'lol' def bar() -> None: pass [builtins fixtures/ops.pyi] [case testUnreachableAfterToplevelAssertImportThirdParty] # flags: --platform unknown import sys assert sys.platform == 'linux' import does_not_exist [builtins fixtures/ops.pyi] [case testUnreachableAfterToplevelAssertImportThirdParty2] # flags: --platform unknown import sys import bad; assert sys.platform == 'linux'; import does_not_exist [builtins fixtures/ops.pyi] [out] main:3: error: Cannot find implementation or library stub for module named "bad" main:3: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports [case testUnreachableAfterToplevelAssertNotInsideIf] import sys if sys.version_info[0] >= 2: assert sys.platform == 'lol' reveal_type('') # N: Revealed type is "Literal['']?" reveal_type('') # N: Revealed type is "Literal['']?" [builtins fixtures/ops.pyi] [case testUnreachableFlagWithBadControlFlow1] # flags: --warn-unreachable a: int if isinstance(a, int): reveal_type(a) # N: Revealed type is "builtins.int" else: reveal_type(a) # E: Statement is unreachable [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagWithBadControlFlow2] # flags: --warn-unreachable b: int while isinstance(b, int): reveal_type(b) # N: Revealed type is "builtins.int" else: reveal_type(b) # E: Statement is unreachable [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagWithBadControlFlow3] # flags: --warn-unreachable def foo(c: int) -> None: reveal_type(c) # N: Revealed type is "builtins.int" assert not isinstance(c, int) reveal_type(c) # E: Statement is unreachable [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagWithBadControlFlow4] # flags: --warn-unreachable d: int if False: reveal_type(d) # E: Statement is unreachable [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagWithBadControlFlow5] # flags: --warn-unreachable e: int if True: reveal_type(e) # N: Revealed type is "builtins.int" else: reveal_type(e) # E: Statement is unreachable [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagStatementAfterReturn] # flags: --warn-unreachable def foo(x: int) -> None: reveal_type(x) # N: Revealed type is "builtins.int" return reveal_type(x) # E: Statement is unreachable [case testUnreachableFlagTryBlocks] # flags: --warn-unreachable def foo(x: int) -> int: try: reveal_type(x) # N: Revealed type is "builtins.int" return x reveal_type(x) # E: Statement is unreachable finally: reveal_type(x) # N: Revealed type is "builtins.int" if True: reveal_type(x) # N: Revealed type is "builtins.int" else: reveal_type(x) # E: Statement is unreachable def bar(x: int) -> int: try: if True: raise Exception() reveal_type(x) # E: Statement is unreachable except: reveal_type(x) # N: Revealed type is "builtins.int" return x else: reveal_type(x) # E: Statement is unreachable def baz(x: int) -> int: try: reveal_type(x) # N: Revealed type is "builtins.int" except: # Mypy assumes all lines could throw an exception reveal_type(x) # N: Revealed type is "builtins.int" return x else: reveal_type(x) # N: Revealed type is "builtins.int" return x [builtins fixtures/exception.pyi] [case testUnreachableFlagIgnoresSemanticAnalysisUnreachable_no_native_parse] # flags: --warn-unreachable --python-version 3.10 --platform win32 --always-false FOOBAR import sys from typing import TYPE_CHECKING def f1(x: int) -> None: if TYPE_CHECKING: reveal_type(x) # N: Revealed type is "builtins.int" else: reveal_type(x) def f2(x: int) -> None: if not TYPE_CHECKING: reveal_type(x) else: reveal_type(x) # N: Revealed type is "builtins.int" def f3(x: int) -> None: if sys.platform == 'darwin': reveal_type(x) else: reveal_type(x) # N: Revealed type is "builtins.int" def f4(x: int) -> None: if sys.platform == 'win32': reveal_type(x) # N: Revealed type is "builtins.int" else: reveal_type(x) def f5(x: int) -> None: if sys.version_info == (2, 7): reveal_type(x) else: reveal_type(x) # N: Revealed type is "builtins.int" def f6(x: int) -> None: if sys.version_info >= (3, 10): reveal_type(x) # N: Revealed type is "builtins.int" else: reveal_type(x) if sys.version_info >= (3, 11): reveal_type(x) else: reveal_type(x) # N: Revealed type is "builtins.int" def f7(x: int) -> None: FOOBAR = "" if FOOBAR: reveal_type(x) else: reveal_type(x) # N: Revealed type is "builtins.int" [builtins fixtures/ops.pyi] [typing fixtures/typing-medium.pyi] [case testUnreachableFlagIgnoresSemanticAnalysisExprUnreachable] # flags: --warn-unreachable --always-false FOOBAR import sys from typing import TYPE_CHECKING FOOBAR = "" def foo() -> bool: ... lst = [1, 2, 3] a = FOOBAR and foo() b = (not FOOBAR) or foo() c = 1 if FOOBAR else 2 d = [x for x in lst if FOOBAR] [builtins fixtures/list.pyi] [typing fixtures/typing-medium.pyi] [case testUnreachableFlagOkWithDeadStatements] # flags: --warn-unreachable from typing import NoReturn def assert_never(x: NoReturn) -> NoReturn: assert False def nonthrowing_assert_never(x: NoReturn) -> None: ... def expect_str(x: str) -> str: pass x: int if False: assert False reveal_type(x) # E: Statement is unreachable if False: raise Exception() reveal_type(x) # E: Statement is unreachable if False: assert_never(x) reveal_type(x) # E: Statement is unreachable if False: nonthrowing_assert_never(x) # E: Statement is unreachable reveal_type(x) if False: # Ignore obvious type errors assert_never(expect_str(x)) reveal_type(x) # E: Statement is unreachable [builtins fixtures/exception.pyi] [case testNeverVariants] from typing import Never from typing_extensions import Never as TENever from typing import NoReturn from typing_extensions import NoReturn as TENoReturn from mypy_extensions import NoReturn as MENoReturn bottom1: Never reveal_type(bottom1) # N: Revealed type is "Never" bottom2: TENever reveal_type(bottom2) # N: Revealed type is "Never" bottom3: NoReturn reveal_type(bottom3) # N: Revealed type is "Never" bottom4: TENoReturn reveal_type(bottom4) # N: Revealed type is "Never" bottom5: MENoReturn reveal_type(bottom5) # N: Revealed type is "Never" [builtins fixtures/tuple.pyi] [case testUnreachableFlagExpressions] # flags: --warn-unreachable def foo() -> bool: ... lst = [1, 2, 3, 4] a = True or foo() # E: Right operand of "or" is never evaluated b = 42 or False # E: Right operand of "or" is never evaluated d = False and foo() # E: Right operand of "and" is never evaluated e = True or (True or (True or foo())) # E: Right operand of "or" is never evaluated f = (True or foo()) or (True or foo()) # E: Right operand of "or" is never evaluated k = [x for x in lst if isinstance(x, int) or foo()] # E: Right operand of "or" is never evaluated [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagMiscTestCaseMissingMethod] # flags: --warn-unreachable class Case1: def test1(self) -> bool: return False and self.missing() # E: Right operand of "and" is never evaluated def test2(self) -> bool: return not self.property_decorator_missing and self.missing() # E: Function "property_decorator_missing" could always be true in boolean context \ # E: Right operand of "and" is never evaluated def property_decorator_missing(self) -> bool: return True [builtins fixtures/bool.pyi] [case testUnreachableFlagWithGenerics] # flags: --warn-unreachable from typing import TypeVar, Generic T1 = TypeVar('T1', bound=int) T2 = TypeVar('T2', int, str) T3 = TypeVar('T3', None, str) def test1(x: T1) -> T1: if isinstance(x, int): reveal_type(x) # N: Revealed type is "T1`-1" else: reveal_type(x) # E: Statement is unreachable return x def test2(x: T2) -> T2: if isinstance(x, int): reveal_type(x) # N: Revealed type is "builtins.int" else: reveal_type(x) # N: Revealed type is "builtins.str" if False: # This is unreachable, but we don't report an error, unfortunately. # The presence of the TypeVar with values unfortunately currently shuts # down type-checking for this entire function. # TODO: Find a way of removing this limitation reveal_type(x) return x class Test3(Generic[T2]): x: T2 def func(self) -> None: if isinstance(self.x, int): reveal_type(self.x) # N: Revealed type is "builtins.int" else: reveal_type(self.x) # N: Revealed type is "builtins.str" if False: # Same issue as above reveal_type(self.x) class Test4(Generic[T3]): def __init__(self, x: T3): # https://github.com/python/mypy/issues/9456 # On TypeVars with value restrictions, we currently have no way # of checking a statement for all the type expansions. # Thus unreachable warnings are disabled if x and False: pass # This test should fail after this limitation is removed. if False and x: pass [builtins fixtures/isinstancelist.pyi] [case testUnreachableBlockStaysUnreachableWithTypeVarConstraints] # flags: --always-false COMPILE_TIME_FALSE from typing import TypeVar COMPILE_TIME_FALSE = False T = TypeVar("T", int, str) def foo(x: T) -> T: if COMPILE_TIME_FALSE: return "bad" return x [case testUnreachableFlagContextManagersNoSuppress] # flags: --warn-unreachable from contextlib import contextmanager from typing import Literal, Optional, Iterator, Any class DoesNotSuppress1: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Optional[bool]: ... class DoesNotSuppress2: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Literal[False]: ... class DoesNotSuppress3: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Any: ... class DoesNotSuppress4: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> None: ... @contextmanager def simple() -> Iterator[int]: yield 3 def cond() -> bool: ... def noop() -> None: ... def f_no_suppress_1a() -> int: with DoesNotSuppress1(): return 3 noop() # E: Statement is unreachable def f_no_suppress_1b() -> int: with DoesNotSuppress1(): if cond(): return 3 else: return 3 noop() # E: Statement is unreachable def f_no_suppress_2() -> int: with DoesNotSuppress2(): return 3 noop() # E: Statement is unreachable def f_no_suppress_3() -> int: with DoesNotSuppress3(): return 3 noop() # E: Statement is unreachable def f_no_suppress_4() -> int: with DoesNotSuppress4(): return 3 noop() # E: Statement is unreachable def f_no_suppress_5() -> int: with simple(): return 3 noop() # E: Statement is unreachable [typing fixtures/typing-medium.pyi] [builtins fixtures/tuple.pyi] [case testUnreachableFlagContextManagersSuppressed] # flags: --warn-unreachable from contextlib import contextmanager from typing import Optional, Iterator, Literal, Any class DoesNotSuppress: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Optional[bool]: ... class Suppresses1: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> bool: ... class Suppresses2: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Literal[True]: ... def cond() -> bool: ... def noop() -> None: ... def f_suppress_1a() -> int: # E: Missing return statement with Suppresses1(): return 3 noop() def f_suppress_1b() -> int: # E: Missing return statement with Suppresses1(): if cond(): return 3 else: return 3 noop() def f_suppress_2() -> int: # E: Missing return statement with Suppresses2(): return 3 noop() def f_mix() -> int: # E: Missing return statement with DoesNotSuppress(), Suppresses1(), DoesNotSuppress(): return 3 noop() [typing fixtures/typing-medium.pyi] [builtins fixtures/tuple.pyi] [case testUnreachableFlagContextManagersSuppressedNoStrictOptional] # flags: --warn-unreachable --no-strict-optional from contextlib import contextmanager from typing import Optional, Iterator, Literal, Any class DoesNotSuppress1: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Optional[bool]: ... # Normally, this should suppress. But when strict-optional mode is disabled, we can't # necessarily distinguish between bool and Optional[bool]. So we default to assuming # no suppression, since that's what most context managers will do. class DoesNotSuppress2: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> bool: ... # But if we see Literal[True], it's pretty unlikely the return type is actually meant to # be 'Optional[Literal[True]]'. So, we optimistically assume this is meant to be suppressing. class Suppresses: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Literal[True]: ... def noop() -> None: ... def f_no_suppress_1() -> int: with DoesNotSuppress1(): return 3 noop() # E: Statement is unreachable def f_no_suppress_2() -> int: with DoesNotSuppress1(): return 3 noop() # E: Statement is unreachable def f_suppress() -> int: # E: Missing return statement with Suppresses(): return 3 noop() [typing fixtures/typing-medium.pyi] [builtins fixtures/tuple.pyi] [case testUnreachableFlagContextAsyncManagersNoSuppress] # flags: --warn-unreachable from contextlib import asynccontextmanager from typing import Optional, AsyncIterator, Literal, Any class DoesNotSuppress1: async def __aenter__(self) -> int: ... async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> Optional[bool]: ... class DoesNotSuppress2: async def __aenter__(self) -> int: ... async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> Literal[False]: ... class DoesNotSuppress3: async def __aenter__(self) -> int: ... async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> Any: ... class DoesNotSuppress4: async def __aenter__(self) -> int: ... async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> None: ... @asynccontextmanager async def simple() -> AsyncIterator[int]: yield 3 def cond() -> bool: ... def noop() -> None: ... async def f_no_suppress_1a() -> int: async with DoesNotSuppress1(): return 3 noop() # E: Statement is unreachable async def f_no_suppress_1b() -> int: async with DoesNotSuppress1(): if cond(): return 3 else: return 3 noop() # E: Statement is unreachable async def f_no_suppress_2() -> int: async with DoesNotSuppress2(): return 3 noop() # E: Statement is unreachable async def f_no_suppress_3() -> int: async with DoesNotSuppress3(): return 3 noop() # E: Statement is unreachable async def f_no_suppress_4() -> int: async with DoesNotSuppress4(): return 3 noop() # E: Statement is unreachable async def f_no_suppress_5() -> int: async with simple(): return 3 noop() # E: Statement is unreachable [typing fixtures/typing-full.pyi] [builtins fixtures/tuple.pyi] [case testUnreachableFlagContextAsyncManagersSuppressed] # flags: --warn-unreachable from contextlib import asynccontextmanager from typing import Optional, AsyncIterator, Literal, Any class DoesNotSuppress: async def __aenter__(self) -> int: ... async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> Optional[bool]: ... class Suppresses1: async def __aenter__(self) -> int: ... async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> bool: ... class Suppresses2: async def __aenter__(self) -> int: ... async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> Literal[True]: ... def cond() -> bool: ... def noop() -> None: ... async def f_suppress_1() -> int: # E: Missing return statement async with Suppresses1(): return 3 noop() async def f_suppress_2() -> int: # E: Missing return statement async with Suppresses1(): if cond(): return 3 else: return 3 noop() async def f_suppress_3() -> int: # E: Missing return statement async with Suppresses2(): return 3 noop() async def f_mix() -> int: # E: Missing return statement async with DoesNotSuppress(), Suppresses1(), DoesNotSuppress(): return 3 noop() [typing fixtures/typing-full.pyi] [builtins fixtures/tuple.pyi] [case testUnreachableFlagContextAsyncManagersAbnormal] # flags: --warn-unreachable from contextlib import asynccontextmanager from typing import Optional, AsyncIterator, Literal, Any class RegularManager: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> bool: ... class AsyncManager: async def __aenter__(self) -> int: ... async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> bool: ... def noop() -> None: ... async def f_bad_1() -> int: async with RegularManager(): # E: "RegularManager" has no attribute "__aenter__"; maybe "__enter__"? \ # E: "RegularManager" has no attribute "__aexit__"; maybe "__exit__"? return 3 noop() # E: Statement is unreachable def f_bad_2() -> int: with AsyncManager(): # E: "AsyncManager" has no attribute "__enter__"; maybe "__aenter__"? \ # E: "AsyncManager" has no attribute "__exit__"; maybe "__aexit__"? return 3 noop() # E: Statement is unreachable # TODO: We should consider reporting an error when the user tries using # context manager with malformed signatures instead of silently continuing. class RegularManagerMalformedSignature: def __enter__(self) -> int: ... def __exit__(self, exctype: object, excvalue: object, traceback: object) -> object: ... class AsyncManagerMalformedSignature: async def __aenter__(self) -> int: ... async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> object: ... def f_malformed_1() -> int: with RegularManagerMalformedSignature(): return 3 noop() # E: Statement is unreachable async def f_malformed_2() -> int: async with AsyncManagerMalformedSignature(): return 3 noop() # E: Statement is unreachable [typing fixtures/typing-full.pyi] [builtins fixtures/tuple.pyi] [case testUnreachableUntypedFunction] # flags: --warn-unreachable def test_untyped_fn(obj): assert obj.prop is True obj.update(prop=False) obj.reload() assert obj.prop is False reveal_type(obj.prop) def test_typed_fn(obj) -> None: assert obj.prop is True obj.update(prop=False) obj.reload() assert obj.prop is False reveal_type(obj.prop) # E: Statement is unreachable [case testUnreachableCheckedUntypedFunction] # flags: --warn-unreachable --check-untyped-defs def test_untyped_fn(obj): assert obj.prop is True obj.update(prop=False) obj.reload() assert obj.prop is False reveal_type(obj.prop) # E: Statement is unreachable [case testConditionalTypeVarException] # every part of this test case was necessary to trigger the crash import sys from typing import TypeVar T = TypeVar("T", int, str) def f(t: T) -> None: if sys.platform == "lol": try: pass except BaseException as e: pass [builtins fixtures/dict.pyi] [case testUnreachableLiteral] # flags: --warn-unreachable from typing import Literal def nope() -> Literal[False]: ... def f() -> None: if nope(): x = 1 # E: Statement is unreachable [builtins fixtures/dict.pyi] [case testUnreachableLiteralFrom__bool__] # flags: --warn-unreachable from typing import Literal class Truth: def __bool__(self) -> Literal[True]: ... class Lie: def __bool__(self) -> Literal[False]: ... class Maybe: def __bool__(self) -> Literal[True | False]: ... t = Truth() if t: x = 1 else: x = 2 # E: Statement is unreachable if Lie(): x = 3 # E: Statement is unreachable if Maybe(): x = 4 def foo() -> bool: ... y = Truth() or foo() # E: Right operand of "or" is never evaluated z = Lie() and foo() # E: Right operand of "and" is never evaluated [builtins fixtures/dict.pyi] [case testUnreachableModuleBody1] # flags: --warn-unreachable from typing import NoReturn def foo() -> NoReturn: raise Exception("foo") foo() x = 1 # E: Statement is unreachable [builtins fixtures/exception.pyi] [case testUnreachableModuleBody2] # flags: --warn-unreachable raise Exception x = 1 # E: Statement is unreachable [builtins fixtures/exception.pyi] [case testUnreachableNoReturnBinaryOps] # flags: --warn-unreachable from typing import NoReturn a: NoReturn a and 1 # E: Right operand of "and" is never evaluated a or 1 # E: Right operand of "or" is never evaluated a or a # E: Right operand of "or" is never evaluated 1 and a and 1 # E: Right operand of "and" is never evaluated a and a # E: Right operand of "and" is never evaluated [builtins fixtures/exception.pyi] [case testUnreachableFlagWithTerminalBranchInDeferredNode] # flags: --warn-unreachable from typing import NoReturn def assert_never(x: NoReturn) -> NoReturn: ... def force_forward_ref() -> int: return 4 def f(value: None) -> None: x if value is not None: assert_never(value) x = force_forward_ref() [builtins fixtures/exception.pyi] [case testSetitemNoReturn] # flags: --warn-unreachable from typing import NoReturn class Foo: def __setitem__(self, key: str, value: str) -> NoReturn: raise Exception Foo()['a'] = 'a' x = 0 # E: Statement is unreachable [builtins fixtures/exception.pyi] [case TestNoImplicNoReturnFromError] # flags: --warn-unreachable from typing import TypeVar T = TypeVar("T") class Foo: def __setitem__(self, key: str, value: str) -> T: # E: A function returning TypeVar should receive at least one argument containing the same TypeVar raise Exception def f() -> None: Foo()['a'] = 'a' x = 0 # This should not be reported as unreachable [builtins fixtures/exception.pyi] [case testIntentionallyEmptyGeneratorFunction] # flags: --warn-unreachable from typing import Generator def f() -> Generator[None, None, None]: return yield [case testIntentionallyEmptyGeneratorFunction_None] # flags: --warn-unreachable from typing import Generator def f() -> Generator[None, None, None]: return None yield None [case testLambdaNoReturn] # flags: --warn-unreachable from typing import Callable, NoReturn def foo() -> NoReturn: raise f1 = lambda: foo() x = 0 # not unreachable f2: Callable[[], NoReturn] = lambda: foo() x = 0 # not unreachable [case testAttributeNoReturn] # flags: --warn-unreachable from typing import Optional, NoReturn, TypeVar def foo() -> NoReturn: raise T = TypeVar("T") def bar(x: Optional[list[T]] = None) -> T: ... reveal_type(bar().attr) # N: Revealed type is "Never" 1 # not unreachable reveal_type(foo().attr) # N: Revealed type is "Never" 1 # E: Statement is unreachable [case testIgnoreReturningNotImplemented] # flags: --warn-unreachable class C: def __add__(self, o: C) -> C: if not isinstance(o, C): return NotImplemented return C() def __sub__(self, o: C) -> C: if isinstance(o, C): return C() return NotImplemented def __mul__(self, o: C) -> C: if isinstance(o, C): return C() else: return NotImplemented [builtins fixtures/isinstance.pyi] [case testIgnoreReturningNotImplementedSimple] # flags: --warn-unreachable -- This behavior may or may not actually be desirable. -- This test just serves to document mypy's current behavior. -- And mypy's handling of NotImplemented has long been known -- to be suboptimal, eg https://github.com/python/mypy/issues/363. -- If you change this behavior, please change the corresponding docs -- https://mypy.readthedocs.io/en/stable/command_line.html#cmdoption-mypy-warn-unreachable def foo() -> None: return None return NotImplemented #no error return None # E: Statement is unreachable [builtins fixtures/isinstance.pyi] [case testPassAndEllipsisUnreachable] # flags: --warn-unreachable def f() -> None: return pass # E: Statement is unreachable def g() -> None: return ... # E: Statement is unreachable [builtins fixtures/isinstance.pyi] [case testUnreachableStatementPrettyHighlighting] # flags: --warn-unreachable --pretty def x() -> None: assert False if 5: pass [out] main:4: error: Statement is unreachable if 5: ^~~~~ [case testReachableEqualityNarrowingAny] # flags: --warn-unreachable # https://github.com/python/mypy/issues/20532 from __future__ import annotations from typing import Any def print(s: str): pass def main(contents: Any, commit: str | None) -> None: if ( contents.get("commit") == commit and (commit is not None or print("can_be_reached")) ): pass main({"commit": None}, None) [builtins fixtures/tuple.pyi]