blob: 3bd18068811c93cf1a79182f135287aabf08bba3 [file] [log] [blame]
-- Tests for strict Optional behavior
[case testImplicitNoneType]
x = None # E: Need type annotation for "x"
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]
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")
pass
[out]
[case testInferOptionalFromDefaultNoneComment]
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")
# 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 = 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 testOptionalWhitelistSuppressesOptionalErrors]
# flags: --strict-optional-whitelist
import a
import b
[file a.py]
from typing import Optional
x = None # type: Optional[str]
x + "foo"
[file b.py]
from typing import Optional
x = None # type: Optional[int]
x + 1
[builtins fixtures/primitives.pyi]
[case testOptionalWhitelistPermitsOtherErrors]
# flags: --strict-optional-whitelist
import a
import b
[file a.py]
from typing import Optional
x = None # type: Optional[str]
x + "foo"
[file b.py]
from typing import Optional
x = None # type: Optional[int]
x + 1
1 + "foo"
[builtins fixtures/primitives.pyi]
[out]
tmp/b.py:4: error: Unsupported operand types for + ("int" and "str")
[case testOptionalWhitelistPermitsWhitelistedFiles]
# flags: --strict-optional-whitelist **/a.py
import a
import b
[file a.py]
from typing import Optional
x = None # type: Optional[str]
x + "foo"
[file b.py]
from typing import Optional
x = None # type: Optional[int]
x + 1
[builtins fixtures/primitives.pyi]
[out]
tmp/a.py:3: error: Unsupported left operand type for + ("None")
tmp/a.py:3: note: Left operand is of type "Optional[str]"
[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 = 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]