| -- Tests for strict Optional behavior |
| |
| [case testImplicitNoneType] |
| 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) # E: Revealed type is 'builtins.int' |
| else: |
| reveal_type(x) # E: Revealed type is 'builtins.None' |
| [builtins fixtures/isinstance.pyi] |
| |
| [case testIfCases] |
| from typing import Optional |
| x = None # type: Optional[int] |
| if x: |
| reveal_type(x) # E: Revealed type is 'builtins.int' |
| else: |
| reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.None]' |
| [builtins fixtures/bool.pyi] |
| |
| [case testIfNotCases] |
| from typing import Optional |
| x = None # type: Optional[int] |
| if not x: |
| reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.None]' |
| else: |
| reveal_type(x) # E: 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) # E: Revealed type is 'builtins.int' |
| else: |
| reveal_type(x) # E: Revealed type is 'builtins.None' |
| [builtins fixtures/bool.pyi] |
| |
| [case testIsNoneCases] |
| from typing import Optional |
| x = None # type: Optional[int] |
| if x is None: |
| reveal_type(x) # E: Revealed type is 'builtins.None' |
| else: |
| reveal_type(x) # E: Revealed type is 'builtins.int' |
| [builtins fixtures/bool.pyi] |
| |
| [case testOrCases] |
| from typing import Optional |
| x = None # type: Optional[str] |
| y1 = x or 'a' |
| reveal_type(y1) # E: Revealed type is 'builtins.str' |
| y2 = x or 1 |
| reveal_type(y2) # E: Revealed type is 'Union[builtins.str, builtins.int]' |
| z1 = 'a' or x |
| reveal_type(z1) # E: Revealed type is 'Union[builtins.str, builtins.None]' |
| z2 = int() or x |
| reveal_type(z2) # E: Revealed type is 'Union[builtins.int, builtins.str, builtins.None]' |
| |
| [case testAndCases] |
| from typing import Optional |
| x = None # type: Optional[str] |
| y1 = x and 'b' |
| reveal_type(y1) # E: Revealed type is 'Union[builtins.str, builtins.None]' |
| y2 = x and 1 # x could be '', so... |
| reveal_type(y2) # E: Revealed type is 'Union[builtins.str, builtins.None, builtins.int]' |
| z1 = 'b' and x |
| reveal_type(z1) # E: Revealed type is 'Union[builtins.str, builtins.None]' |
| z2 = int() and x |
| reveal_type(z2) # E: Revealed type is 'Union[builtins.int, builtins.str, builtins.None]' |
| |
| [case testLambdaReturningNone] |
| f = lambda: None |
| x = f() # E: Function does not return a value |
| |
| [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 + (some union) |
| f(None) |
| [out] |
| |
| [case testInferOptionalFromDefaultNoneWithFastParser] |
| # flags: --fast-parser |
| def f(x: int = None) -> None: |
| x + 1 # E: Unsupported left operand type for + (some union) |
| f(None) |
| [out] |
| |
| [case testInferOptionalFromDefaultNoneComment] |
| def f(x=None): |
| # type: (int) -> None |
| x + 1 # E: Unsupported left operand type for + (some union) |
| f(None) |
| [out] |
| |
| [case testInferOptionalFromDefaultNoneCommentWithFastParser] |
| # flags: --fast-parser |
| def f(x=None): |
| # type: (int) -> None |
| x + 1 # E: Unsupported left operand type for + (some union) |
| f(None) |
| [out] |
| |
| [case testInferOptionalType] |
| x = None |
| if bool(): |
| # scope limit assignment |
| x = 1 |
| # in scope of the assignment, x is an int |
| reveal_type(x) # E: Revealed type is 'builtins.int' |
| # out of scope of the assignment, it's an Optional[int] |
| reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.None]' |
| [builtins fixtures/bool.pyi] |
| |
| [case testInferOptionalTypeLocallyBound] |
| x = None |
| x = 1 |
| reveal_type(x) # E: Revealed type is 'builtins.int' |
| |
| |
| [case testInferOptionalTypeFromOptional] |
| from typing import Optional |
| y = None # type: Optional[int] |
| x = None |
| x = y |
| reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.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"; 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") |
| [out] |
| |
| [case testOverloadWithNone] |
| from typing import overload |
| @overload |
| def f(x: None) -> str: pass |
| @overload |
| def f(x: int) -> int: pass |
| reveal_type(f(None)) # E: Revealed type is 'builtins.str' |
| reveal_type(f(0)) # E: 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: error: Revealed type is 'Union[builtins.int, builtins.None]' |
| main:5: error: Revealed type is 'Union[builtins.int, builtins.None]' |
| |
| [case testOptionalTypeOrTypeComplexUnion] |
| from typing import Union |
| def f(a: Union[int, str, None]) -> None: |
| reveal_type(a or 'default') |
| [out] |
| main:3: error: 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) # E: Revealed type is 'builtins.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: Function does not return a value |
| f() + 1 # E: Function does not return a value |
| g(f()) # E: Function 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) # E: Revealed type is 'Union[builtins.int, builtins.None]' |
| [builtins fixtures/bool.pyi] |
| |
| [case testListWithNone] |
| reveal_type([0, None, 0]) # E: Revealed type is 'builtins.list[Union[builtins.int, builtins.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 |
| |
| [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" |
| [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 |
| [out] |
| tmp/a.py:3: error: Unsupported left operand type for + (some union) |
| |
| [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) # E: Revealed type is 'typing.Generator[builtins.str, builtins.None, builtins.None]' |
| l = [f()] |
| reveal_type(l) # E: Revealed type is 'builtins.list[typing.Generator*[builtins.str, builtins.None, builtins.None]]' |
| [builtins fixtures/list.pyi] |
| |
| [case testNoneListTernary] |
| x = [None] if "" else [1] # E: List item 0 has incompatible type "int" |
| [builtins fixtures/list.pyi] |
| |
| [case testInferEqualsNotOptional] |
| from typing import Optional |
| x = '' # type: Optional[str] |
| if x == '<string>': |
| reveal_type(x) # E: Revealed type is 'builtins.str' |
| else: |
| reveal_type(x) # E: Revealed type is 'Union[builtins.str, builtins.None]' |
| [builtins fixtures/ops.pyi] |
| |
| [case testInferEqualsNotOptionalWithUnion] |
| from typing import Union |
| x = '' # type: Union[str, int, None] |
| if x == '<string>': |
| reveal_type(x) # E: Revealed type is 'Union[builtins.str, builtins.int]' |
| else: |
| reveal_type(x) # E: Revealed type is 'Union[builtins.str, builtins.int, builtins.None]' |
| [builtins fixtures/ops.pyi] |
| |
| [case testInferEqualsNotOptionalWithOverlap] |
| from typing import Union |
| x = '' # type: Union[str, int, None] |
| if x == object(): |
| reveal_type(x) # E: Revealed type is 'Union[builtins.str, builtins.int]' |
| else: |
| reveal_type(x) # E: Revealed type is 'Union[builtins.str, builtins.int, builtins.None]' |
| [builtins fixtures/ops.pyi] |
| |
| [case testInferEqualsStillOptionalWithNoOverlap] |
| from typing import Optional |
| x = '' # type: Optional[str] |
| if x == 0: |
| reveal_type(x) # E: Revealed type is 'Union[builtins.str, builtins.None]' |
| else: |
| reveal_type(x) # E: Revealed type is 'Union[builtins.str, builtins.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) # E: Revealed type is 'Union[builtins.str, builtins.int, builtins.None]' |
| else: |
| reveal_type(x) # E: Revealed type is 'Union[builtins.str, builtins.int, builtins.None]' |
| [builtins fixtures/ops.pyi] |
| |
| [case testWarnNoReturnWorksWithStrictOptional] |
| # flags: --warn-no-return |
| def f() -> None: |
| 1 + 1 # no error |
| |
| def g() -> int: |
| 1 + 1 # |
| [out] |
| main:5: note: 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] |
| x = f(1) |
| x = f('x') # E: Argument 1 to "f" has incompatible type "str"; expected "int" |
| |
| x.x = 1 # E: Some element of union has no attribute "x" |
| if x is not None: |
| x.x = 1 # OK here |
| |
| [builtins fixtures/ops.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] |