blob: ae247b0047f15fa263e2c190c6f17770cbdf5431 [file] [log] [blame] [edit]
-- Tests for strict Optional behavior
[case testImplicitNoneType]
x = None
x() # E: "None" not callable
[case testImplicitNoneTypeInNestedFunction]
def f() -> None:
def g() -> None:
x = None
x() # E: "None" not callable
[case testExplicitNoneType]
x = None # type: None
x() # E: "None" not callable
[case testNoneMemberOfOptional]
from typing import Optional
x = None # type: Optional[int]
[case testTypeMemberOfOptional]
from typing import Optional
x = 0 # type: Optional[int]
[case testNoneNotMemberOfType]
x = None # type: int
[out]
main:1: error: Incompatible types in assignment (expression has type "None", variable has type "int")
[case testTypeNotMemberOfNone]
x = 0 # type: None
[out]
main:1: error: Incompatible types in assignment (expression has type "int", variable has type "None")
[case testOptionalNotMemberOfType]
from typing import Optional
def f(a: int) -> None: pass
x = None # type: Optional[int]
f(x) # E: Argument 1 to "f" has incompatible type "Optional[int]"; expected "int"
[case testIsinstanceCases]
from typing import Optional
x = None # type: Optional[int]
if isinstance(x, int):
reveal_type(x) # N: Revealed type is "builtins.int"
else:
reveal_type(x) # N: Revealed type is "None"
[builtins fixtures/isinstance.pyi]
[case testIfCases]
from typing import Optional
x = None # type: Optional[int]
if x:
reveal_type(x) # N: Revealed type is "builtins.int"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.int, None]"
[builtins fixtures/bool.pyi]
[case testIfNotCases]
from typing import Optional
x = None # type: Optional[int]
if not x:
reveal_type(x) # N: Revealed type is "Union[builtins.int, None]"
else:
reveal_type(x) # N: Revealed type is "builtins.int"
[builtins fixtures/bool.pyi]
[case testIsNotNoneCases]
from typing import Optional
x = None # type: Optional[int]
if x is not None:
reveal_type(x) # N: Revealed type is "builtins.int"
else:
reveal_type(x) # N: Revealed type is "None"
[builtins fixtures/bool.pyi]
[case testIsNoneCases]
from typing import Optional
x = None # type: Optional[int]
if x is None:
reveal_type(x) # N: Revealed type is "None"
else:
reveal_type(x) # N: Revealed type is "builtins.int"
reveal_type(x) # N: Revealed type is "Union[builtins.int, None]"
[builtins fixtures/bool.pyi]
[case testAnyCanBeNone]
from typing import Optional, Any
x = None # type: Any
if x is None:
reveal_type(x) # N: Revealed type is "None"
else:
reveal_type(x) # N: Revealed type is "Any"
[builtins fixtures/bool.pyi]
[case testOrCases]
from typing import Optional
x = None # type: Optional[str]
y1 = x or 'a'
reveal_type(y1) # N: Revealed type is "builtins.str"
y2 = x or 1
reveal_type(y2) # N: Revealed type is "Union[builtins.str, builtins.int]"
z1 = 'a' or x
reveal_type(z1) # N: Revealed type is "Union[builtins.str, None]"
z2 = int() or x
reveal_type(z2) # N: Revealed type is "Union[builtins.int, builtins.str, None]"
[case testAndCases]
from typing import Optional
x = None # type: Optional[str]
y1 = x and 'b'
reveal_type(y1) # N: Revealed type is "Union[builtins.str, None]"
y2 = x and 1 # x could be '', so...
reveal_type(y2) # N: Revealed type is "Union[builtins.str, None, builtins.int]"
z1 = 'b' and x
reveal_type(z1) # N: Revealed type is "Union[builtins.str, None]"
z2 = int() and x
reveal_type(z2) # N: Revealed type is "Union[builtins.int, builtins.str, None]"
[case testLambdaReturningNone]
f = lambda: None
x = f()
reveal_type(x) # N: Revealed type is "None"
[case testNoneArgumentType]
def f(x: None) -> None: pass
f(None)
[case testInferOptionalFromDefaultNone]
# flags: --implicit-optional
def f(x: int = None) -> None:
x + 1 # E: Unsupported left operand type for + ("None") \
# N: Left operand is of type "Optional[int]"
f(None)
[out]
[case testNoInferOptionalFromDefaultNone]
# flags: --no-implicit-optional
def f(x: int = None) -> None: # E: Incompatible default for argument "x" (default has type "None", argument has type "int") \
# N: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True \
# N: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
pass
[out]
[case testInferOptionalFromDefaultNoneComment]
# flags: --implicit-optional
def f(x=None):
# type: (int) -> None
x + 1 # E: Unsupported left operand type for + ("None") \
# N: Left operand is of type "Optional[int]"
f(None)
[out]
[case testNoInferOptionalFromDefaultNoneComment]
# flags: --no-implicit-optional
def f(x=None): # E: Incompatible default for argument "x" (default has type "None", argument has type "int") \
# N: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True \
# N: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
# type: (int) -> None
pass
[out]
[case testInferOptionalType]
x = None
if bool():
# scope limit assignment
x = 1
# in scope of the assignment, x is an int
reveal_type(x) # N: Revealed type is "builtins.int"
# out of scope of the assignment, it's an Optional[int]
reveal_type(x) # N: Revealed type is "Union[builtins.int, None]"
[builtins fixtures/bool.pyi]
[case testInferOptionalTypeLocallyBound]
x = None
x = 1
reveal_type(x) # N: Revealed type is "builtins.int"
[case testInferOptionalAnyType]
from typing import Any
x = None
a = None # type: Any
if bool():
x = a
reveal_type(x) # N: Revealed type is "Any"
reveal_type(x) # N: Revealed type is "Union[Any, None]"
[builtins fixtures/bool.pyi]
[case testInferOptionalTypeFromOptional]
from typing import Optional
y = None # type: Optional[int]
x = None
x = y
reveal_type(x) # N: Revealed type is "Union[builtins.int, None]"
[case testInferOptionalListType]
x = [None]
x.append(1) # E: Argument 1 to "append" of "list" has incompatible type "int"; expected "None"
[builtins fixtures/list.pyi]
[case testInferNonOptionalListType]
x = []
x.append(1)
x() # E: "List[int]" not callable
[builtins fixtures/list.pyi]
[case testInferOptionalDictKeyValueTypes]
x = {None: None}
x["bar"] = 1
[builtins fixtures/dict.pyi]
[out]
main:2: error: Invalid index type "str" for "Dict[None, None]"; expected type "None"
main:2: error: Incompatible types in assignment (expression has type "int", target has type "None")
[case testInferNonOptionalDictType]
x = {}
x["bar"] = 1
x() # E: "Dict[str, int]" not callable
[builtins fixtures/dict.pyi]
[case testNoneClassVariable]
from typing import Optional
class C:
x = None # type: int
def __init__(self) -> None:
self.x = 0
[case testNoneClassVariableInInit]
from typing import Optional
class C:
x = None # type: int
def __init__(self) -> None:
self.x = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
[out]
[case testMultipleAssignmentNoneClassVariableInInit]
from typing import Optional
class C:
x, y = None, None # type: int, str
def __init__(self) -> None:
self.x = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
self.y = None # E: Incompatible types in assignment (expression has type "None", variable has type "str")
[builtins fixtures/tuple.pyi]
[out]
[case testOverloadWithNone]
from foo import *
[file foo.pyi]
from typing import overload
@overload
def f(x: None) -> str: pass
@overload
def f(x: int) -> int: pass
reveal_type(f(None)) # N: Revealed type is "builtins.str"
reveal_type(f(0)) # N: Revealed type is "builtins.int"
[case testOptionalTypeOrTypePlain]
from typing import Optional
def f(a: Optional[int]) -> int:
return a or 0
[out]
[case testOptionalTypeOrTypeTypeVar]
from typing import Optional, TypeVar
T = TypeVar('T')
def f(a: Optional[T], b: T) -> T:
return a or b
[out]
[case testOptionalTypeOrTypeBothOptional]
from typing import Optional
def f(a: Optional[int], b: Optional[int]) -> None:
reveal_type(a or b)
def g(a: int, b: Optional[int]) -> None:
reveal_type(a or b)
[out]
main:3: note: Revealed type is "Union[builtins.int, None]"
main:5: note: Revealed type is "Union[builtins.int, None]"
[case testOptionalTypeOrTypeComplexUnion]
from typing import Union
def f(a: Union[int, str, None]) -> None:
reveal_type(a or 'default')
[out]
main:3: note: Revealed type is "Union[builtins.int, builtins.str]"
[case testOptionalTypeOrTypeNoTriggerPlain]
from typing import Optional
def f(a: Optional[int], b: int) -> int:
return b or a
[out]
main:3: error: Incompatible return value type (got "Optional[int]", expected "int")
[case testOptionalTypeOrTypeNoTriggerTypeVar]
from typing import Optional, TypeVar
T = TypeVar('T')
def f(a: Optional[T], b: T) -> T:
return b or a
[out]
main:4: error: Incompatible return value type (got "Optional[T]", expected "T")
[case testNoneOrStringIsString]
def f() -> str:
a = None
b = ''
return a or b
[out]
[case testNoneOrTypeVarIsTypeVar]
from typing import TypeVar
T = TypeVar('T')
def f(b: T) -> T:
a = None
return a or b
[out]
[case testYieldNothingInFunctionReturningGenerator]
from typing import Generator
def f() -> Generator[None, None, None]:
yield
[out]
[case testNoneAndStringIsNone]
a = None
b = "foo"
reveal_type(a and b) # N: Revealed type is "None"
[case testNoneMatchesObjectInOverload]
import a
a.f(None)
[file a.pyi]
from typing import overload
@overload
def f() -> None: ...
@overload
def f(o: object) -> None: ...
[case testGenericSubclassReturningNone]
from typing import Generic, TypeVar
T = TypeVar('T')
class Base(Generic[T]):
def f(self) -> T:
pass
class SubNone(Base[None]):
def f(self) -> None:
pass
class SubInt(Base[int]):
def f(self) -> int:
return 1
[case testUseOfNoneReturningFunction]
from typing import Optional
def f() -> None:
pass
def g(x: Optional[int]) -> int:
pass
x = f() # E: "f" does not return a value
f() + 1 # E: "f" does not return a value
g(f()) # E: "f" does not return a value
[case testEmptyReturn]
def f() -> None:
return
[case testReturnNone]
def f() -> None:
return None
[case testNoneCallable]
from typing import Callable
def f() -> None: pass
x = f # type: Callable[[], None]
[case testOptionalCallable]
from typing import Callable, Optional
T = Optional[Callable[..., None]]
[case testAnyTypeInPartialTypeList]
# flags: --check-untyped-defs
def f(): ...
def lookup_field(name, obj):
try:
pass
except:
attr = f()
else:
attr = None
[case testTernaryWithNone]
reveal_type(None if bool() else 0) # N: Revealed type is "Union[Literal[0]?, None]"
[builtins fixtures/bool.pyi]
[case testListWithNone]
reveal_type([0, None, 0]) # N: Revealed type is "builtins.list[Union[builtins.int, None]]"
[builtins fixtures/list.pyi]
[case testNoneContextInference]
from typing import Dict, List
def f() -> List[None]:
return []
def g() -> Dict[None, None]:
return {}
[builtins fixtures/dict.pyi]
[case testRaiseFromNone]
raise BaseException from None
[builtins fixtures/exception.pyi]
[case testOptionalNonPartialTypeWithNone]
from typing import Generator
def f() -> Generator[str, None, None]: pass
x = f()
reveal_type(x) # N: Revealed type is "typing.Generator[builtins.str, None, None]"
l = [f()]
reveal_type(l) # N: Revealed type is "builtins.list[typing.Generator[builtins.str, None, None]]"
[builtins fixtures/list.pyi]
[case testNoneListTernary]
x = [None] if "" else [1] # E: List item 0 has incompatible type "int"; expected "None"
[builtins fixtures/list.pyi]
[case testListIncompatibleErrorMessage]
from typing import List, Callable
def foo(l: List[Callable[[], str]]) -> None: pass
def f() -> int:
return 42
foo([f]) # E: List item 0 has incompatible type "Callable[[], int]"; expected "Callable[[], str]"
[builtins fixtures/list.pyi]
[case testInferEqualsNotOptional]
from typing import Optional
x = '' # type: Optional[str]
if x == '<string>':
reveal_type(x) # N: Revealed type is "builtins.str"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.str, None]"
if x is '<string>':
reveal_type(x) # N: Revealed type is "builtins.str"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.str, None]"
[builtins fixtures/ops.pyi]
[case testInferEqualsNotOptionalWithUnion]
from typing import Union
x = '' # type: Union[str, int, None]
if x == '<string>':
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int]"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int, None]"
if x is '<string>':
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int]"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int, None]"
[builtins fixtures/ops.pyi]
[case testInferEqualsNotOptionalWithOverlap]
from typing import Union
x = '' # type: Union[str, int, None]
if x == object():
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int]"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int, None]"
if x is object():
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int]"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int, None]"
[builtins fixtures/ops.pyi]
[case testInferEqualsStillOptionalWithNoOverlap]
from typing import Optional
x = '' # type: Optional[str]
if x == 0:
reveal_type(x) # N: Revealed type is "Union[builtins.str, None]"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.str, None]"
if x is 0:
reveal_type(x) # N: Revealed type is "Union[builtins.str, None]"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.str, None]"
[builtins fixtures/ops.pyi]
[case testInferEqualsStillOptionalWithBothOptional]
from typing import Union
x = '' # type: Union[str, int, None]
y = '' # type: Union[str, None]
if x == y:
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int, None]"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int, None]"
if x is y:
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int, None]"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int, None]"
[builtins fixtures/ops.pyi]
[case testInferEqualsNotOptionalWithMultipleArgs]
from typing import Optional
x: Optional[int]
y: Optional[int]
if x == y == 1:
reveal_type(x) # N: Revealed type is "builtins.int"
reveal_type(y) # N: Revealed type is "builtins.int"
else:
reveal_type(x) # N: Revealed type is "Union[builtins.int, None]"
reveal_type(y) # N: Revealed type is "Union[builtins.int, None]"
class A: pass
a: Optional[A]
b: Optional[A]
if a == b == object():
reveal_type(a) # N: Revealed type is "__main__.A"
reveal_type(b) # N: Revealed type is "__main__.A"
else:
reveal_type(a) # N: Revealed type is "Union[__main__.A, None]"
reveal_type(b) # N: Revealed type is "Union[__main__.A, None]"
[builtins fixtures/ops.pyi]
[case testInferInWithErasedTypes]
from typing import TypeVar, Callable
T = TypeVar('T')
def foo(f: Callable[[T], bool], it: T) -> None: ...
foo(lambda x: x in [1, 2] and bool(), 3)
[builtins fixtures/list.pyi]
[case testWarnNoReturnWorksWithStrictOptional]
# flags: --warn-no-return
def f() -> None:
1 + 1 # no error
def g() -> int:
1 + 1 #
[out]
main:5: error: Missing return statement
[case testGenericTypeAliasesOptional]
from typing import TypeVar, Generic, Optional
T = TypeVar('T')
class Node(Generic[T]):
def __init__(self, x: T) -> None:
self.x = x
ONode = Optional[Node[T]]
def f(x: T) -> ONode[T]:
if 1 > 0:
return Node(x)
else:
return None
x = None # type: ONode[int]
if int():
x = f(1)
if int():
x = f('x') # E: Argument 1 to "f" has incompatible type "str"; expected "int"
x.x = 1 # E: Item "None" of "Optional[Node[int]]" has no attribute "x"
if x is not None:
x.x = 1 # OK here
[builtins fixtures/ops.pyi]
[case testOptionalTypeNarrowedInBooleanStatement]
from typing import Optional
x: Optional[int] = None
x is not None and x + 42
x is not None and x + '42' # E: Unsupported operand types for + ("int" and "str")
[builtins fixtures/isinstance.pyi]
[case testInvalidBooleanBranchIgnored]
from typing import Optional
x = None
x is not None and x + 42
[builtins fixtures/isinstance.pyi]
[case testOptionalLambdaInference]
from typing import Optional, Callable
f = None # type: Optional[Callable[[int], None]]
f = lambda x: None
f(0)
[builtins fixtures/function.pyi]
[case testDontSimplifyNoneUnionsWithStrictOptional]
from typing import Any, TypeVar, Union
A = None # type: Any
class C(A): pass
T = TypeVar('T')
S = TypeVar('S')
def u(x: T, y: S) -> Union[S, T]: pass
a = None # type: Any
# Test both orders
reveal_type(u(C(), None)) # N: Revealed type is "Union[None, __main__.C]"
reveal_type(u(None, C())) # N: Revealed type is "Union[__main__.C, None]"
reveal_type(u(a, None)) # N: Revealed type is "Union[None, Any]"
reveal_type(u(None, a)) # N: Revealed type is "Union[Any, None]"
reveal_type(u(1, None)) # N: Revealed type is "Union[None, builtins.int]"
reveal_type(u(None, 1)) # N: Revealed type is "Union[builtins.int, None]"
[case testOptionalAndAnyBaseClass]
from typing import Any, Optional
A = None # type: Any
class C(A):
pass
x = None # type: Optional[C]
x.foo() # E: Item "None" of "Optional[C]" has no attribute "foo"
[case testIsinstanceAndOptionalAndAnyBase]
from typing import Any, Optional
B = None # type: Any
class A(B): pass
def f(a: Optional[A]):
reveal_type(a) # N: Revealed type is "Union[__main__.A, None]"
if a is not None:
reveal_type(a) # N: Revealed type is "__main__.A"
else:
reveal_type(a) # N: Revealed type is "None"
reveal_type(a) # N: Revealed type is "Union[__main__.A, None]"
[builtins fixtures/isinstance.pyi]
[case testFlattenOptionalUnion]
from typing import Optional, Union
x: Optional[Union[int, str]]
reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str, None]"
y: Optional[Union[int, None]]
reveal_type(y) # N: Revealed type is "Union[builtins.int, None]"
[case testOverloadWithNoneAndOptional]
from typing import overload, Optional
@overload
def f(x: int) -> str: ...
@overload
def f(x: Optional[int]) -> Optional[str]: ...
def f(x): return x
reveal_type(f(1)) # N: Revealed type is "builtins.str"
reveal_type(f(None)) # N: Revealed type is "Union[builtins.str, None]"
x: Optional[int]
reveal_type(f(x)) # N: Revealed type is "Union[builtins.str, None]"
[case testUnionTruthinessTracking]
from typing import Optional, Any
def test_or_shortcut(value: Optional[Any]) -> None:
if not value:
pass
if not value or value.get('foo') == 'hello':
pass
[builtins fixtures/bool.pyi]
[case testNarrowingFromObjectToOptional]
from typing import Optional
x: object
y: Optional[int]
x = y
reveal_type(x) # N: Revealed type is "Union[builtins.int, None]"
[out]
[case testNarrowOptionalOutsideLambda]
from typing import Optional
class A:
a: int
def f(x: Optional[A]) -> None:
assert x
lambda: x.a
[builtins fixtures/isinstancelist.pyi]
[case testNarrowOptionalOutsideLambdaWithDeferred]
from typing import Optional
class A:
a: int
def f(self, x: Optional['A']) -> None:
assert x
lambda: (self.y, x.a) # E: Cannot determine type of "y"
self.y = int()
[builtins fixtures/isinstancelist.pyi]
[case testDeferredAndOptionalInferenceSpecialCase]
def f() -> str:
y
x = None
if int():
x = ''
if x is None:
x = ''
g(x)
return x
def g(x: str) -> None: pass
y = int()
[builtins fixtures/bool.pyi]
[case testOptionalAssignAny1]
from typing import Optional
def f():
return 0
def g(x: Optional[int]) -> int:
if x is None:
reveal_type(x) # N: Revealed type is "None"
# As a special case for Unions containing None, during
x = f()
reveal_type(x) # N: Revealed type is "Union[builtins.int, Any]"
reveal_type(x) # N: Revealed type is "Union[builtins.int, Any]"
return x
[builtins fixtures/bool.pyi]
[case testOptionalAssignAny2]
from typing import Optional
def f():
return 0
def g(x: Optional[int]) -> int:
if x is None:
reveal_type(x) # N: Revealed type is "None"
x = 1
reveal_type(x) # N: Revealed type is "builtins.int"
# Since we've assigned to x, the special case None behavior shouldn't happen
x = f()
reveal_type(x) # N: Revealed type is "Union[builtins.int, None]"
reveal_type(x) # N: Revealed type is "Union[builtins.int, None]"
return x # E: Incompatible return value type (got "Optional[int]", expected "int")
[builtins fixtures/bool.pyi]
[case testOptionalAssignAny3]
from typing import Optional
def f():
return 0
def g(x: Optional[int]) -> int:
if x is not None:
return x
reveal_type(x) # N: Revealed type is "None"
if 1:
x = f()
reveal_type(x) # N: Revealed type is "Union[builtins.int, Any]"
return x
[builtins fixtures/bool.pyi]
[case testStrictOptionalCovarianceCrossModule]
# flags: --config-file tmp/mypy.ini
from a import asdf
x = ["lol"]
asdf(x)
[file a.py]
from typing import List, Optional
def asdf(x: List[Optional[str]]) -> None:
pass
x = ["lol"]
asdf(x)
[file mypy.ini]
\[mypy]
\[mypy-a]
strict_optional = False
[out]
main:4: error: Argument 1 to "asdf" has incompatible type "List[str]"; expected "List[Optional[str]]"
main:4: note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
main:4: note: Consider using "Sequence" instead, which is covariant
[builtins fixtures/list.pyi]
[case testOptionalBackwards1]
from typing import Any, Optional
def f1(b: bool) -> Optional[int]:
if b:
z = 10
reveal_type(z) # N: Revealed type is "builtins.int"
else:
z = None
reveal_type(z) # N: Revealed type is "None"
reveal_type(z) # N: Revealed type is "Union[builtins.int, None]"
return z
def f2(b: bool) -> int:
if b:
z = 10
else:
z = None
return z # E: Incompatible return value type (got "Optional[int]", expected "int")
def f3(b: bool) -> int:
# XXX: This one is a little questionable! Maybe we *do* want to allow this?
z = 10
if b:
z = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
return z
def f4() -> Optional[int]:
z = 10
z = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
return z
def f5() -> None:
z = 10
def f() -> None:
nonlocal z
z = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
def f6(b: bool) -> None:
if b:
z = 10
else:
z = 11
def f() -> None:
nonlocal z
z = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
def f7(b: bool) -> None:
if b:
z = 10
else:
z = 11
z = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
def f8(b: bool, c: bool) -> Optional[int]:
if b:
if c:
z = 10
else:
z = 11
else:
z = None
return z
def f9(b: bool) -> None:
if b:
z: int = 10
else:
z = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
def f10(b: bool) -> None:
z: int
if b:
z = 10
else:
z = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
def f11(b: bool, c: bool) -> None:
if b:
z = 10
elif c:
z = 30
else:
z = None
def f12(b: bool, a: Any) -> None:
if b:
z = a
else:
z = None
reveal_type(z) # N: Revealed type is "Any"
def f13(b: bool, a: Any) -> None:
if b:
try:
z = f2(True)
except Exception:
raise RuntimeError
else:
z = None
def f14(b: bool, a: Any) -> None:
if b:
with a:
z = 10
else:
z = None
def f15() -> None:
try:
z = f2(True)
except Exception:
z = None
reveal_type(z) # N: Revealed type is "Union[builtins.int, None]"
def f16(z: Any) -> None:
for x in z:
if x == 0:
y = 50
break
else:
y = None
reveal_type(y) # N: Revealed type is "Union[builtins.int, None]"
def f17(b: bool, c: bool, d: bool) -> None:
if b:
z = 2
elif c:
z = None
elif d:
z = 3
reveal_type(z) # N: Revealed type is "Union[builtins.int, None]"
def f18(b: bool, c: bool, d: bool) -> None:
if b:
z = 4
else:
if c:
z = 5
else:
z = None
reveal_type(z) # N: Revealed type is "Union[builtins.int, None]"
def f19(b: bool, c: bool, d: bool) -> None:
if b:
z = 5
else:
z = None
if c:
z = 6
reveal_type(z) # N: Revealed type is "Union[builtins.int, None]"
def f20(b: bool) -> None:
if b:
x: Any = 5
else:
x = None
reveal_type(x) # N: Revealed type is "Any"
def f_unannot(): pass
def f21(b: bool) -> None:
if b:
x = f_unannot()
else:
x = None
reveal_type(x) # N: Revealed type is "Any"
def f22(b: bool) -> None:
if b:
z = 10
if not b:
z = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
def f23(b: bool) -> None:
if b:
z = 10
if b:
z = 11
else:
z = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
[builtins fixtures/exception.pyi]
[case testOptionalBackwards2]
def f1(b: bool) -> None:
if b:
x = [] # E: Need type annotation for "x" (hint: "x: List[<type>] = ...")
else:
x = None
def f2(b: bool) -> None:
if b:
x = []
x.append(1)
else:
x = None
reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.int], None]"
[builtins fixtures/list.pyi]
[case testOptionalBackwards3]
# We don't allow this sort of updating for globals or attributes currently.
gb: bool
if gb:
Z = 10
else:
Z = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
class Foo:
def __init__(self, b: bool) -> None:
if b:
self.x = 5
else:
self.x = None # E: Incompatible types in assignment (expression has type "None", variable has type "int")
def foo(self) -> None:
reveal_type(self.x) # N: Revealed type is "builtins.int"
[case testOptionalBackwards4]
from typing import Any, Optional
def f1(b: bool) -> Optional[int]:
if b:
z = 10
reveal_type(z) # N: Revealed type is "builtins.int"
else:
# Force the node to get deferred between the two assignments
Defer().defer
z = None
reveal_type(z) # N: Revealed type is "None"
reveal_type(z) # N: Revealed type is "Union[builtins.int, None]"
return z
class Defer:
def __init__(self) -> None:
self.defer = 10
[case testOptionalIterator]
# mypy: no-strict-optional
from typing import Optional, List
x: Optional[List[int]]
if 3 in x:
pass
[case testNarrowedVariableInNestedFunctionBasic]
from typing import Optional
def can_narrow(x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return reveal_type(x) # N: Revealed type is "builtins.str"
nested()
def foo(a): pass
class C:
def can_narrow_in_method(self, x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return reveal_type(x) # N: Revealed type is "builtins.str"
# Reading the variable is fine
y = x
with foo(x):
foo(x)
for a in foo(x):
foo(x)
nested()
def can_narrow_lambda(x: Optional[str]) -> None:
if x is None:
x = "a"
nested = lambda: x
reveal_type(nested()) # N: Revealed type is "builtins.str"
def cannot_narrow_if_reassigned(x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
if int():
x = None
nested()
x: Optional[str] = "x"
def narrow_global_in_func() -> None:
global x
if x is None:
x = "a"
def nested() -> str:
# This should perhaps not be narrowed, since the nested function could outlive
# the outer function, and since other functions could also assign to x, but
# this seems like a minor issue.
return x
nested()
x = "y"
def narrowing_global_at_top_level_not_propagated() -> str:
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
[case testNarrowedVariableInNestedFunctionMore1]
from typing import Optional, overload
class C:
a: Optional[str]
def attribute_narrowing(c: C) -> None:
# This case is not supported, since we can't keep track of assignments to attributes.
c.a = "x"
def nested() -> str:
return c.a # E: Incompatible return value type (got "Optional[str]", expected "str")
nested()
def assignment_in_for(x: Optional[str]) -> None:
if x is None:
x = "e"
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
for x in ["x"]:
pass
def foo(): pass
def assignment_in_with(x: Optional[str]) -> None:
if x is None:
x = "e"
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
with foo() as x:
pass
g: Optional[str]
def assign_to_global() -> None:
global g
g = "x"
# This is unsafe, but we don't generate an error, for convenience. Besides,
# this is probably a very rare case.
def nested() -> str:
return g
def assign_to_nonlocal(x: Optional[str]) -> None:
def nested() -> str:
nonlocal x
if x is None:
x = "a"
def nested2() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
return nested2()
nested()
x = None
def dec(f):
return f
@dec
def decorated_outer(x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return x
nested()
@dec
def decorated_outer_bad(x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
x = None
nested()
def decorated_inner(x: Optional[str]) -> None:
if x is None:
x = "a"
@dec
def nested() -> str:
return x
nested()
def decorated_inner_bad(x: Optional[str]) -> None:
if x is None:
x = "a"
@dec
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
x = None
nested()
@overload
def overloaded_outer(x: None) -> None: ...
@overload
def overloaded_outer(x: str) -> None: ...
def overloaded_outer(x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return x
nested()
@overload
def overloaded_outer_bad(x: None) -> None: ...
@overload
def overloaded_outer_bad(x: str) -> None: ...
def overloaded_outer_bad(x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
x = None
nested()
[case testNarrowedVariableInNestedFunctionMore2]
from typing import Optional
def narrow_multiple(x: Optional[str], y: Optional[int]) -> None:
z: Optional[str] = x
if x is None:
x = ""
if y is None:
y = 1
if int():
if z is None:
z = ""
def nested() -> None:
a: str = x
b: int = y
c: str = z
nested()
def narrow_multiple_partial(x: Optional[str], y: Optional[int]) -> None:
z: Optional[str] = x
if x is None:
x = ""
if isinstance(y, int):
if z is None:
z = ""
def nested() -> None:
a: str = x
b: int = y
c: str = z # E: Incompatible types in assignment (expression has type "Optional[str]", variable has type "str")
z = None
nested()
def multiple_nested_functions(x: Optional[str], y: Optional[str]) -> None:
if x is None:
x = ""
def nested1() -> str:
return x
if y is None:
y = ""
def nested2() -> str:
a: str = y
return x
class C:
a: str
def __setitem__(self, key, value): pass
def narrowed_variable_used_in_lvalue_but_not_assigned(c: Optional[C]) -> None:
if c is None:
c = C()
def nested() -> C:
return c
c.a = "x"
c[1] = 2
cc = C()
cc[c] = 3
nested()
def narrow_with_multi_lvalues_1(x: Optional[str]) -> None:
if x is None:
x = ""
def nested() -> str:
return x
y = z = None
def narrow_with_multi_lvalue_2(x: Optional[str]) -> None:
if x is None:
x = ""
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
x = y = None
def narrow_with_multi_lvalue_3(x: Optional[str]) -> None:
if x is None:
x = ""
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
y = x = None
def narrow_with_multi_assign_1(x: Optional[str]) -> None:
if x is None:
x = ""
def nested() -> str:
return x
y, z = None, None
def narrow_with_multi_assign_2(x: Optional[str]) -> None:
if x is None:
x = ""
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
x, y = None, None
def narrow_with_multi_assign_3(x: Optional[str]) -> None:
if x is None:
x = ""
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
y, x = None, None
[builtins fixtures/isinstance.pyi]
[case testNestedFunctionSpecialCase]
class C:
def __enter__(self, *args): ...
def __exit__(self, *args) -> bool: ...
def f(x: object) -> None:
if x is not None:
pass
def nested() -> None:
with C():
pass
[builtins fixtures/tuple.pyi]