mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 16:06:39 +03:00
Added provisional support for draft PEP 742 (TypeIs).
This commit is contained in:
parent
1700e5451b
commit
08d3f6d38c
@ -4101,6 +4101,7 @@ export class Binder extends ParseTreeWalker {
|
||||
'Never',
|
||||
'LiteralString',
|
||||
'OrderedDict',
|
||||
'TypeIs',
|
||||
]);
|
||||
|
||||
const assignedName = assignedNameNode.value;
|
||||
|
@ -660,7 +660,7 @@ export class Checker extends ParseTreeWalker {
|
||||
// Verify common dunder signatures.
|
||||
this._validateDunderSignatures(node, functionTypeResult.functionType, containingClassNode !== undefined);
|
||||
|
||||
// Verify TypeGuard functions.
|
||||
// Verify TypeGuard and TypeIs functions.
|
||||
this._validateTypeGuardFunction(node, functionTypeResult.functionType, containingClassNode !== undefined);
|
||||
|
||||
this._validateFunctionTypeVarUsage(node, functionTypeResult);
|
||||
@ -4589,7 +4589,10 @@ export class Checker extends ParseTreeWalker {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ClassType.isBuiltIn(returnType, 'TypeGuard')) {
|
||||
const isTypeGuard = ClassType.isBuiltIn(returnType, 'TypeGuard');
|
||||
const isTypeIs = ClassType.isBuiltIn(returnType, 'TypeIs');
|
||||
|
||||
if (!isTypeGuard && !isTypeIs) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4612,6 +4615,34 @@ export class Checker extends ParseTreeWalker {
|
||||
node.name
|
||||
);
|
||||
}
|
||||
|
||||
if (isTypeIs) {
|
||||
const typeGuardType = returnType.typeArguments[0];
|
||||
|
||||
// Determine the type of the first parameter.
|
||||
const paramIndex = isMethod && !FunctionType.isStaticMethod(functionType) ? 1 : 0;
|
||||
if (paramIndex >= functionType.details.parameters.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const paramType = FunctionType.getEffectiveParameterType(functionType, paramIndex);
|
||||
|
||||
// Verify that the typeGuardType is a narrower type than the paramType.
|
||||
if (!this._evaluator.assignType(paramType, typeGuardType)) {
|
||||
const returnAnnotation =
|
||||
node.returnTypeAnnotation || node.functionAnnotationComment?.returnTypeAnnotation;
|
||||
if (returnAnnotation) {
|
||||
this._evaluator.addDiagnostic(
|
||||
DiagnosticRule.reportGeneralTypeIssues,
|
||||
LocMessage.typeIsReturnType().format({
|
||||
type: this._evaluator.printType(paramType),
|
||||
returnType: this._evaluator.printType(typeGuardType),
|
||||
}),
|
||||
returnAnnotation
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _validateDunderSignatures(node: FunctionNode, functionType: FunctionType, isMethod: boolean) {
|
||||
|
@ -11418,16 +11418,13 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
specializedReturnType = ClassType.cloneForUnpacked(specializedReturnType, /* isUnpackedTuple */ false);
|
||||
}
|
||||
|
||||
// Handle 'TypeGuard' specially. We'll transform the return type into a 'bool'
|
||||
// object with a type argument that reflects the narrowed type.
|
||||
// Handle 'TypeGuard' and 'TypeIs' specially. We'll transform the return type
|
||||
// into a 'bool' object with a type argument that reflects the narrowed type.
|
||||
if (
|
||||
isClassInstance(specializedReturnType) &&
|
||||
ClassType.isBuiltIn(specializedReturnType, 'TypeGuard') &&
|
||||
ClassType.isBuiltIn(specializedReturnType, ['TypeGuard', 'TypeIs']) &&
|
||||
specializedReturnType.typeArguments &&
|
||||
specializedReturnType.typeArguments.length > 0 &&
|
||||
isClassInstance(returnType) &&
|
||||
returnType.typeArguments &&
|
||||
returnType.typeArguments.length > 0
|
||||
specializedReturnType.typeArguments.length > 0
|
||||
) {
|
||||
if (boolClassType && isInstantiableClass(boolClassType)) {
|
||||
let typeGuardType = specializedReturnType.typeArguments[0];
|
||||
@ -11447,25 +11444,9 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
}
|
||||
}
|
||||
|
||||
let useStrictTypeGuardSemantics = false;
|
||||
|
||||
if (AnalyzerNodeInfo.getFileInfo(errorNode).diagnosticRuleSet.enableExperimentalFeatures) {
|
||||
// Determine the type of the first parameter.
|
||||
const paramIndex = type.boundToType ? 1 : 0;
|
||||
if (paramIndex < type.details.parameters.length) {
|
||||
const paramType = FunctionType.getEffectiveParameterType(type, paramIndex);
|
||||
|
||||
// If the type guard meets the requirements that the first parameter
|
||||
// type is a proper subtype of the return type, we can use strict
|
||||
// type guard semantics.
|
||||
if (assignType(paramType, returnType.typeArguments[0])) {
|
||||
useStrictTypeGuardSemantics = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const useTypeIsSemantics = ClassType.isBuiltIn(specializedReturnType, 'TypeIs');
|
||||
specializedReturnType = ClassType.cloneAsInstance(
|
||||
ClassType.cloneForTypeGuard(boolClassType, typeGuardType, useStrictTypeGuardSemantics)
|
||||
ClassType.cloneForTypeGuard(boolClassType, typeGuardType, useTypeIsSemantics)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -14649,7 +14630,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
return type;
|
||||
}
|
||||
|
||||
// Creates a "TypeGuard" type. This is an alias for 'bool', which
|
||||
// Creates a "TypeGuard" and "TypeIs" type. This is an alias for 'bool', which
|
||||
// isn't a generic type and therefore doesn't have a typeParameter.
|
||||
// We'll abuse our internal types a bit by specializing it with
|
||||
// a type argument anyway.
|
||||
@ -15437,6 +15418,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
['Never', { alias: '', module: 'builtins', isSpecialForm: true }],
|
||||
['LiteralString', { alias: '', module: 'builtins', isSpecialForm: true }],
|
||||
['ReadOnly', { alias: '', module: 'builtins', isSpecialForm: true }],
|
||||
['TypeIs', { alias: '', module: 'builtins', isSpecialForm: true }],
|
||||
]);
|
||||
|
||||
const aliasMapEntry = specialTypes.get(assignedName);
|
||||
@ -19445,7 +19427,8 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
return { type: createConcatenateType(classType, errorNode, typeArgs, flags) };
|
||||
}
|
||||
|
||||
case 'TypeGuard': {
|
||||
case 'TypeGuard':
|
||||
case 'TypeIs': {
|
||||
return { type: createTypeGuardType(classType, errorNode, typeArgs, flags) };
|
||||
}
|
||||
|
||||
@ -23189,7 +23172,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
const isLiteral = isClass(srcType) && srcType.literalValue !== undefined;
|
||||
return !isLiteral;
|
||||
}
|
||||
} else if (ClassType.isBuiltIn(destType, 'TypeGuard')) {
|
||||
} else if (ClassType.isBuiltIn(destType, ['TypeGuard', 'TypeIs'])) {
|
||||
// All the source to be a "bool".
|
||||
if ((originalFlags & AssignTypeFlags.AllowBoolTypeGuard) !== 0) {
|
||||
if (isClassInstance(srcType) && ClassType.isBuiltIn(srcType, 'bool')) {
|
||||
@ -25058,11 +25041,12 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
) {
|
||||
isReturnTypeCompatible = true;
|
||||
} else {
|
||||
// Handle the special case where the return type is a TypeGuard[T].
|
||||
// This should also act as a bool, since that's its type at runtime.
|
||||
// Handle the special case where the return type is a TypeGuard[T]
|
||||
// or TypeIs[T]. This should also act as a bool, since that's its
|
||||
// type at runtime.
|
||||
if (
|
||||
isClassInstance(srcReturnType) &&
|
||||
ClassType.isBuiltIn(srcReturnType, 'TypeGuard') &&
|
||||
ClassType.isBuiltIn(srcReturnType, ['TypeGuard', 'TypeIs']) &&
|
||||
boolClassType &&
|
||||
isInstantiableClass(boolClassType)
|
||||
) {
|
||||
|
@ -715,7 +715,7 @@ export function getTypeNarrowingCallback(
|
||||
return (
|
||||
type.details.declaredReturnType &&
|
||||
isClassInstance(type.details.declaredReturnType) &&
|
||||
ClassType.isBuiltIn(type.details.declaredReturnType, 'TypeGuard')
|
||||
ClassType.isBuiltIn(type.details.declaredReturnType, ['TypeGuard', 'TypeIs'])
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -2933,6 +2933,7 @@ export function requiresTypeArguments(classType: ClassType) {
|
||||
'Literal',
|
||||
'Annotated',
|
||||
'TypeGuard',
|
||||
'TypeIs',
|
||||
];
|
||||
|
||||
if (specialClasses.some((t) => t === (classType.aliasName || classType.details.name))) {
|
||||
|
@ -980,6 +980,8 @@ export namespace Localizer {
|
||||
new ParameterizedString<{ type: string }>(getRawString('Diagnostic.typeExpectedClass'));
|
||||
export const typeGuardArgCount = () => getRawString('Diagnostic.typeGuardArgCount');
|
||||
export const typeGuardParamCount = () => getRawString('Diagnostic.typeGuardParamCount');
|
||||
export const typeIsReturnType = () =>
|
||||
new ParameterizedString<{ type: string; returnType: string }>(getRawString('Diagnostic.typeIsReturnType'));
|
||||
export const typeNotAwaitable = () =>
|
||||
new ParameterizedString<{ type: string }>(getRawString('Diagnostic.typeNotAwaitable'));
|
||||
export const typeNotIntantiable = () =>
|
||||
|
@ -490,8 +490,9 @@
|
||||
"typedDictSecondArgDictEntry": "Expected simple dictionary entry",
|
||||
"typedDictSet": "Could not assign item in TypedDict",
|
||||
"typeExpectedClass": "Expected type expression but received \"{type}\"",
|
||||
"typeGuardArgCount": "Expected a single type argument after \"TypeGuard\"",
|
||||
"typeGuardArgCount": "Expected a single type argument after \"TypeGuard\" or \"TypeIs\"",
|
||||
"typeGuardParamCount": "User-defined type guard functions and methods must have at least one input parameter",
|
||||
"typeIsReturnType": "Return type of TypeIs (\"{returnType}\") is not consistent with value parameter type (\"{type}\")",
|
||||
"typeNotAwaitable": "\"{type}\" is not awaitable",
|
||||
"typeNotIntantiable": "\"{type}\" cannot be instantiated",
|
||||
"typeNotIterable": "\"{type}\" is not iterable",
|
||||
|
@ -1,194 +1,54 @@
|
||||
# This sample tests the TypeGuard using "strict" semantics.
|
||||
# This sample tests that user-defined TypeGuard can
|
||||
# be used in an overloaded function.
|
||||
|
||||
from typing import Any, Literal, Mapping, Sequence, TypeVar, Union
|
||||
from typing_extensions import TypeGuard
|
||||
from enum import Enum
|
||||
from typing import Literal, overload
|
||||
from typing_extensions import TypeGuard, TypeIs
|
||||
|
||||
|
||||
def is_str1(val: Union[str, int]) -> TypeGuard[str]:
|
||||
return isinstance(val, str)
|
||||
class TypeGuardMode(Enum):
|
||||
NoTypeGuard = 0
|
||||
TypeGuard = 1
|
||||
TypeIs = 2
|
||||
|
||||
|
||||
def func1(val: Union[str, int]):
|
||||
if is_str1(val):
|
||||
reveal_type(val, expected_text="str")
|
||||
@overload
|
||||
def is_int(obj: object, mode: Literal[TypeGuardMode.NoTypeGuard]) -> bool:
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def is_int(obj: object, mode: Literal[TypeGuardMode.TypeGuard]) -> TypeGuard[int]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def is_int(
|
||||
obj: object, mode: Literal[TypeGuardMode.TypeIs]
|
||||
) -> TypeIs[int]:
|
||||
...
|
||||
|
||||
|
||||
|
||||
def is_int(obj: object, mode: TypeGuardMode) -> bool | TypeGuard[int] | TypeIs[int]:
|
||||
...
|
||||
|
||||
|
||||
def func_no_typeguard(val: int | str):
|
||||
if is_int(val, TypeGuardMode.NoTypeGuard):
|
||||
reveal_type(val, expected_text="int | str")
|
||||
else:
|
||||
reveal_type(val, expected_text="int | str")
|
||||
|
||||
|
||||
def func_typeguard(val: int | str):
|
||||
if is_int(val, TypeGuardMode.TypeGuard):
|
||||
reveal_type(val, expected_text="int")
|
||||
|
||||
|
||||
def is_true(o: object) -> TypeGuard[Literal[True]]:
|
||||
...
|
||||
|
||||
|
||||
def func2(val: bool):
|
||||
if not is_true(val):
|
||||
reveal_type(val, expected_text="bool")
|
||||
else:
|
||||
reveal_type(val, expected_text="Literal[True]")
|
||||
|
||||
reveal_type(val, expected_text="bool")
|
||||
reveal_type(val, expected_text="int | str")
|
||||
|
||||
|
||||
def is_list(val: object) -> TypeGuard[list[Any]]:
|
||||
return isinstance(val, list)
|
||||
|
||||
|
||||
def func3(val: dict[str, str] | list[str] | list[int] | Sequence[int]):
|
||||
if is_list(val):
|
||||
reveal_type(val, expected_text="list[str] | list[int] | list[Any]")
|
||||
def func_typeis(val: int | str):
|
||||
if is_int(val, TypeGuardMode.TypeIs):
|
||||
reveal_type(val, expected_text="int")
|
||||
else:
|
||||
reveal_type(val, expected_text="dict[str, str] | Sequence[int]")
|
||||
|
||||
|
||||
def func4(val: dict[str, str] | list[str] | list[int] | tuple[int]):
|
||||
if is_list(val):
|
||||
reveal_type(val, expected_text="list[str] | list[int]")
|
||||
else:
|
||||
reveal_type(val, expected_text="dict[str, str] | tuple[int]")
|
||||
|
||||
|
||||
_K = TypeVar("_K")
|
||||
_V = TypeVar("_V")
|
||||
|
||||
|
||||
def is_dict(val: Mapping[_K, _V]) -> TypeGuard[dict[_K, _V]]:
|
||||
return isinstance(val, dict)
|
||||
|
||||
|
||||
def func5(val: dict[_K, _V] | Mapping[_K, _V]):
|
||||
if not is_dict(val):
|
||||
reveal_type(val, expected_text="Mapping[_K@func5, _V@func5]")
|
||||
else:
|
||||
reveal_type(val, expected_text="dict[_K@func5, _V@func5]")
|
||||
|
||||
|
||||
def is_cardinal_direction(val: str) -> TypeGuard[Literal["N", "S", "E", "W"]]:
|
||||
return val in ("N", "S", "E", "W")
|
||||
|
||||
|
||||
def func6(direction: Literal["NW", "E"]):
|
||||
if is_cardinal_direction(direction):
|
||||
reveal_type(direction, expected_text="Literal['E']")
|
||||
else:
|
||||
reveal_type(direction, expected_text="Literal['NW']")
|
||||
|
||||
|
||||
class Animal:
|
||||
...
|
||||
|
||||
|
||||
class Kangaroo(Animal):
|
||||
...
|
||||
|
||||
|
||||
class Koala(Animal):
|
||||
...
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def is_marsupial(val: Animal) -> TypeGuard[Kangaroo | Koala]:
|
||||
return isinstance(val, Kangaroo | Koala)
|
||||
|
||||
|
||||
class A1:
|
||||
...
|
||||
|
||||
|
||||
class A2(A1):
|
||||
...
|
||||
|
||||
|
||||
class B1:
|
||||
...
|
||||
|
||||
|
||||
class B2(B1):
|
||||
...
|
||||
|
||||
|
||||
class C1:
|
||||
...
|
||||
|
||||
|
||||
class C2(C1):
|
||||
...
|
||||
|
||||
|
||||
def guard1(val: A1 | B1 | C1) -> TypeGuard[A1 | B1]:
|
||||
return isinstance(val, (A1, B1))
|
||||
|
||||
|
||||
def func7_1(val: A1 | B1 | C1):
|
||||
if guard1(val):
|
||||
reveal_type(val, expected_text="A1 | B1")
|
||||
else:
|
||||
reveal_type(val, expected_text="C1")
|
||||
|
||||
|
||||
def func7_2(val: A2 | B2 | C2):
|
||||
if guard1(val):
|
||||
reveal_type(val, expected_text="A2 | B2")
|
||||
else:
|
||||
reveal_type(val, expected_text="C2")
|
||||
|
||||
|
||||
def func7_3(val: A2 | B2 | C2 | Any):
|
||||
if guard1(val):
|
||||
reveal_type(val, expected_text="A2 | B2 | A1 | B1")
|
||||
else:
|
||||
reveal_type(val, expected_text="C2 | Any")
|
||||
|
||||
|
||||
def guard2(val: A1 | B1 | C1) -> TypeGuard[A2 | B2]:
|
||||
return isinstance(val, (A2, B2))
|
||||
|
||||
|
||||
def func8_1(val: A1 | B1 | C1):
|
||||
if guard2(val):
|
||||
reveal_type(val, expected_text="A2 | B2")
|
||||
else:
|
||||
reveal_type(val, expected_text="A1 | B1 | C1")
|
||||
|
||||
|
||||
def func8_2(val: A2 | B2 | C2):
|
||||
if guard2(val):
|
||||
reveal_type(val, expected_text="A2 | B2")
|
||||
else:
|
||||
reveal_type(val, expected_text="C2")
|
||||
|
||||
|
||||
def func8_3(val: A2 | B2 | C2 | Any):
|
||||
if guard2(val):
|
||||
reveal_type(val, expected_text="A2 | B2")
|
||||
else:
|
||||
reveal_type(val, expected_text="C2 | Any")
|
||||
|
||||
|
||||
def guard3(val: A2 | B2 | C2) -> TypeGuard[A2 | B2 | Any]:
|
||||
return isinstance(val, (A1, B1))
|
||||
|
||||
|
||||
def func3_1(val: A2 | C2):
|
||||
if guard3(val):
|
||||
reveal_type(val, expected_text="A2 | C2")
|
||||
else:
|
||||
reveal_type(val, expected_text="C2")
|
||||
|
||||
|
||||
def func3_2(val: A2 | B2 | C2 | Any):
|
||||
if guard3(val):
|
||||
reveal_type(val, expected_text="A2 | B2 | C2 | Any")
|
||||
else:
|
||||
reveal_type(val, expected_text="C2 | Any")
|
||||
|
||||
|
||||
def guard4(o: type) -> TypeGuard[type[A1]]:
|
||||
...
|
||||
|
||||
|
||||
def func4_1(cls: type):
|
||||
if guard4(cls):
|
||||
reveal_type(cls, expected_text="type[A1]")
|
||||
else:
|
||||
reveal_type(cls, expected_text="type")
|
||||
reveal_type(val, expected_text="str")
|
||||
|
@ -1,39 +0,0 @@
|
||||
# This sample tests that user-defined TypeGuard can
|
||||
# be used in an overloaded function.
|
||||
|
||||
from enum import Enum
|
||||
from typing import Literal, overload
|
||||
from typing_extensions import TypeGuard
|
||||
|
||||
|
||||
class TypeGuardMode(Enum):
|
||||
NoTypeGuard = 0
|
||||
TypeGuard = 1
|
||||
|
||||
|
||||
@overload
|
||||
def is_int(obj: object, mode: Literal[TypeGuardMode.NoTypeGuard]) -> bool:
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def is_int(obj: object, mode: Literal[TypeGuardMode.TypeGuard]) -> TypeGuard[int]:
|
||||
...
|
||||
|
||||
|
||||
def is_int(obj: object, mode: TypeGuardMode) -> bool | TypeGuard[int]:
|
||||
...
|
||||
|
||||
|
||||
def func_no_typeguard(val: int | str):
|
||||
if is_int(val, TypeGuardMode.NoTypeGuard):
|
||||
reveal_type(val, expected_text="int | str")
|
||||
else:
|
||||
reveal_type(val, expected_text="int | str")
|
||||
|
||||
|
||||
def func_typeguard(val: int | str):
|
||||
if is_int(val, TypeGuardMode.TypeGuard):
|
||||
reveal_type(val, expected_text="int")
|
||||
else:
|
||||
reveal_type(val, expected_text="str")
|
94
packages/pyright-internal/src/tests/samples/typeIs1.py
Normal file
94
packages/pyright-internal/src/tests/samples/typeIs1.py
Normal file
@ -0,0 +1,94 @@
|
||||
# This sample tests the TypeIs form.
|
||||
|
||||
from typing import Any, Literal, Mapping, Sequence, TypeVar, Union
|
||||
from typing_extensions import TypeIs
|
||||
|
||||
|
||||
def is_str1(val: Union[str, int]) -> TypeIs[str]:
|
||||
return isinstance(val, str)
|
||||
|
||||
|
||||
def func1(val: Union[str, int]):
|
||||
if is_str1(val):
|
||||
reveal_type(val, expected_text="str")
|
||||
else:
|
||||
reveal_type(val, expected_text="int")
|
||||
|
||||
|
||||
def is_true(o: object) -> TypeIs[Literal[True]]: ...
|
||||
|
||||
|
||||
def func2(val: bool):
|
||||
if not is_true(val):
|
||||
reveal_type(val, expected_text="bool")
|
||||
else:
|
||||
reveal_type(val, expected_text="Literal[True]")
|
||||
|
||||
reveal_type(val, expected_text="bool")
|
||||
|
||||
|
||||
def is_list(val: object) -> TypeIs[list[Any]]:
|
||||
return isinstance(val, list)
|
||||
|
||||
|
||||
def func3(val: dict[str, str] | list[str] | list[int] | Sequence[int]):
|
||||
if is_list(val):
|
||||
reveal_type(val, expected_text="list[str] | list[int] | list[Any]")
|
||||
else:
|
||||
reveal_type(val, expected_text="dict[str, str] | Sequence[int]")
|
||||
|
||||
|
||||
def func4(val: dict[str, str] | list[str] | list[int] | tuple[int]):
|
||||
if is_list(val):
|
||||
reveal_type(val, expected_text="list[str] | list[int]")
|
||||
else:
|
||||
reveal_type(val, expected_text="dict[str, str] | tuple[int]")
|
||||
|
||||
|
||||
_K = TypeVar("_K")
|
||||
_V = TypeVar("_V")
|
||||
|
||||
|
||||
def is_dict(val: Mapping[_K, _V]) -> TypeIs[dict[_K, _V]]:
|
||||
return isinstance(val, dict)
|
||||
|
||||
|
||||
def func5(val: dict[_K, _V] | Mapping[_K, _V]):
|
||||
if not is_dict(val):
|
||||
reveal_type(val, expected_text="Mapping[_K@func5, _V@func5]")
|
||||
else:
|
||||
reveal_type(val, expected_text="dict[_K@func5, _V@func5]")
|
||||
|
||||
|
||||
def is_cardinal_direction(val: str) -> TypeIs[Literal["N", "S", "E", "W"]]:
|
||||
return val in ("N", "S", "E", "W")
|
||||
|
||||
|
||||
def func6(direction: Literal["NW", "E"]):
|
||||
if is_cardinal_direction(direction):
|
||||
reveal_type(direction, expected_text="Literal['E']")
|
||||
else:
|
||||
reveal_type(direction, expected_text="Literal['NW']")
|
||||
|
||||
|
||||
class Animal: ...
|
||||
|
||||
|
||||
class Kangaroo(Animal): ...
|
||||
|
||||
|
||||
class Koala(Animal): ...
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def is_marsupial(val: Animal) -> TypeIs[Kangaroo | Koala]:
|
||||
return isinstance(val, Kangaroo | Koala)
|
||||
|
||||
|
||||
# This should generate an error because list[T] isn't consistent with list[T | None].
|
||||
def has_no_nones(
|
||||
val: list[T | None],
|
||||
) -> TypeIs[list[T]]:
|
||||
return None not in val
|
@ -987,19 +987,13 @@ test('TypeGuard2', () => {
|
||||
});
|
||||
|
||||
test('TypeGuard3', () => {
|
||||
const configOptions = new ConfigOptions(Uri.empty());
|
||||
configOptions.diagnosticRuleSet.enableExperimentalFeatures = true;
|
||||
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typeGuard3.py'], configOptions);
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typeGuard3.py']);
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('TypeGuard4', () => {
|
||||
const configOptions = new ConfigOptions(Uri.empty());
|
||||
configOptions.diagnosticRuleSet.enableExperimentalFeatures = true;
|
||||
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typeGuard4.py'], configOptions);
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
test('TypeIs1', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typeIs1.py']);
|
||||
TestUtils.validateResults(analysisResults, 1);
|
||||
});
|
||||
|
||||
test('Never1', () => {
|
||||
|
Loading…
Reference in New Issue
Block a user