blob: fa77c09bfd9321db9d8b2f665aac3ab44b7df44f [file] [log] [blame] [edit]
-- 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 testConditionalTypeAliasPY3_python2]
import typing
def f(): pass
PY3 = f()
if PY3:
t = int
x = object() + 'x'
else:
t = str
y = 'x' / 1 # E: "str" has no attribute "__div__"
y
z = '' # 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 testConditionalAssignmentPY2_python2]
import typing
def f(): pass
PY2 = f()
if PY2:
x = object() + 'x' # E: Unsupported left operand type for + ("object")
else:
y = 'x' / 1
x
[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/latest/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
[out]
main:3: error: Cannot find implementation or library stub for module named 'pow123'
main:3: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
[case testTypeCheckingConditionalFromImport]
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import pow123 # E
else:
import xyz753
[out]
main:3: error: Cannot find implementation or library stub for module named 'pow123'
main:3: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
[case testNegatedTypeCheckingConditional]
import typing
if not typing.TYPE_CHECKING:
import pow123 # E
else:
import xyz753
[builtins fixtures/bool.pyi]
[out]
main:5: error: Cannot find implementation or library stub for module named 'xyz753'
main:5: note: See https://mypy.readthedocs.io/en/latest/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/latest/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_python2]
import sys
if sys.version_info[0] >= 3:
def foo():
# type: () -> int
return 0
else:
def foo():
# type: () -> str
return ''
reveal_type(foo()) # N: Revealed type is 'builtins.str'
[builtins_py2 fixtures/ops.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 testSysVersionInfoNegated_python2]
import sys
if not (sys.version_info[0] < 3):
def foo():
# type: () -> int
return 0
else:
def foo():
# type: () -> str
return ''
reveal_type(foo()) # N: Revealed type is 'builtins.str'
[builtins_py2 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
[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
[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.5
import sys
if sys.version_info == (3, 5):
x = "foo"
else:
x = 3
reveal_type(x) # N: Revealed type is 'builtins.str'
[builtins fixtures/ops.pyi]
[out]
[case testCustomSysVersionInfo2]
# flags: --python-version 3.5
import sys
if sys.version_info == (3, 6):
x = "foo"
else:
x = 3
reveal_type(x) # N: Revealed type is 'builtins.int'
[builtins fixtures/ops.pyi]
[out]
[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]
# 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]
# 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 's'
b = PY3 and 's'
c = PY2 or 's'
d = PY3 or 's'
e = (PY2 or PY3) and 's'
f = (PY3 or PY2) and 's'
g = (PY2 or PY3) or 's'
h = (PY3 or PY2) or 's'
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 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 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]
[case testUnreachableWhenSuperclassIsAny]
# flags: --strict-optional
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 'builtins.int'
assert sys.platform == 'lol'
reveal_type('') # No error here :-)
[builtins fixtures/ops.pyi]
[case testUnreachableAfterToplevelAssert2]
import sys
reveal_type(0) # N: Revealed type is 'builtins.int'
assert sys.version_info[0] == 1
reveal_type('') # No error here :-)
[builtins fixtures/ops.pyi]
[case testUnreachableAfterToplevelAssert3]
reveal_type(0) # N: Revealed type is 'builtins.int'
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 'builtins.int'
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 testUnreachableAfterToplevelAssertNotInsideIf]
import sys
if sys.version_info[0] >= 2:
assert sys.platform == 'lol'
reveal_type('') # N: Revealed type is 'builtins.str'
reveal_type('') # N: Revealed type is 'builtins.str'
[builtins fixtures/ops.pyi]
[case testUnreachableFlagWithBadControlFlow]
# 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
b: int
while isinstance(b, int):
reveal_type(b) # N: Revealed type is 'builtins.int'
else:
reveal_type(b) # E: Statement is 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
d: int
if False:
reveal_type(d) # E: Statement is 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]
# flags: --warn-unreachable --python-version 3.7 --platform win32 --always-false FOOBAR
import sys
from typing import TYPE_CHECKING
x: int
if TYPE_CHECKING:
reveal_type(x) # N: Revealed type is 'builtins.int'
else:
reveal_type(x)
if not TYPE_CHECKING:
reveal_type(x)
else:
reveal_type(x) # N: Revealed type is 'builtins.int'
if sys.platform == 'darwin':
reveal_type(x)
else:
reveal_type(x) # N: Revealed type is 'builtins.int'
if sys.platform == 'win32':
reveal_type(x) # N: Revealed type is 'builtins.int'
else:
reveal_type(x)
if sys.version_info == (2, 7):
reveal_type(x)
else:
reveal_type(x) # N: Revealed type is 'builtins.int'
if sys.version_info == (3, 7):
reveal_type(x) # N: Revealed type is 'builtins.int'
else:
reveal_type(x)
FOOBAR = ""
if FOOBAR:
reveal_type(x)
else:
reveal_type(x) # N: Revealed type is 'builtins.int'
[builtins fixtures/ops.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]
[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)
if False:
raise Exception()
reveal_type(x)
if False:
assert_never(x)
reveal_type(x)
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)
[builtins fixtures/exception.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 = False or foo() # E: Left operand of 'or' is always false
c = True and foo() # E: Left operand of 'and' is always true
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
g = 3 if True else 4 # E: If condition is always true
h = 3 if False else 4 # E: If condition is always false
i = [x for x in lst if True] # E: If condition in comprehension is always true
j = [x for x in lst if False] # E: If condition in comprehension is always false
k = [x for x in lst if isinstance(x, int) or foo()] # E: If condition in comprehension is always true \
# 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: 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)
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)
[builtins fixtures/isinstancelist.pyi]
[case testUnreachableFlagContextManagersNoSuppress]
# flags: --warn-unreachable
from contextlib import contextmanager
from typing import Optional, Iterator, Any
from typing_extensions import Literal
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-full.pyi]
[case testUnreachableFlagContextManagersSuppressed]
# flags: --warn-unreachable
from contextlib import contextmanager
from typing import Optional, Iterator, Any
from typing_extensions import Literal
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-full.pyi]
[case testUnreachableFlagContextManagersSuppressedNoStrictOptional]
# flags: --warn-unreachable --no-strict-optional
from contextlib import contextmanager
from typing import Optional, Iterator, Any
from typing_extensions import Literal
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-full.pyi]
[case testUnreachableFlagContextAsyncManagersNoSuppress]
# flags: --warn-unreachable --python-version 3.7
from contextlib import asynccontextmanager
from typing import Optional, AsyncIterator, Any
from typing_extensions import Literal
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]
[case testUnreachableFlagContextAsyncManagersSuppressed]
# flags: --warn-unreachable --python-version 3.7
from contextlib import asynccontextmanager
from typing import Optional, AsyncIterator, Any
from typing_extensions import Literal
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]
[case testUnreachableFlagContextAsyncManagersAbnormal]
# flags: --warn-unreachable --python-version 3.7
from contextlib import asynccontextmanager
from typing import Optional, AsyncIterator, Any
from typing_extensions import Literal
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]