Removed support for inlined TypedDict annotations. This idea never gained enough support to make it into a PEP.

This commit is contained in:
Eric Traut 2024-05-30 18:16:13 -07:00
parent 1bc5949959
commit 0e42a7ea56
4 changed files with 2 additions and 102 deletions

View File

@ -286,7 +286,6 @@ import {
assignToTypedDict,
assignTypedDictToTypedDict,
createTypedDictType,
createTypedDictTypeInlined,
getTypeOfIndexedTypedDict,
getTypedDictDictEquivalent,
getTypedDictMappingEquivalent,
@ -352,7 +351,6 @@ interface GetTypeArgsOptions {
hasCustomClassGetItem?: boolean;
isFinalAnnotation?: boolean;
isClassVarAnnotation?: boolean;
supportsTypedDictTypeArg?: boolean;
}
interface MatchArgsToParamsResult {
@ -620,7 +618,6 @@ export function createTypeEvaluator(
let intClass: Type | undefined;
let strClass: Type | undefined;
let dictClass: Type | undefined;
let typedDictClass: Type | undefined;
let typedDictPrivateClass: Type | undefined;
let supportsKeysAndGetItemClass: Type | undefined;
let mappingClass: Type | undefined;
@ -965,7 +962,6 @@ export function createTypeEvaluator(
intClass = getBuiltInType(node, 'int');
strClass = getBuiltInType(node, 'str');
dictClass = getBuiltInType(node, 'dict');
typedDictClass = getTypingType(node, 'TypedDict');
typedDictPrivateClass = getTypingType(node, '_TypedDict');
awaitableClass = getTypingType(node, 'Awaitable');
mappingClass = getTypingType(node, 'Mapping');
@ -7074,19 +7070,11 @@ export function createTypeEvaluator(
const isClassVarAnnotation =
isInstantiableClass(concreteSubtype) && ClassType.isBuiltIn(concreteSubtype, 'ClassVar');
// Inlined TypedDicts are supported only for 'dict' (and not for 'Dict').
// This feature is currently experimental.
const supportsTypedDictTypeArg =
AnalyzerNodeInfo.getFileInfo(node).diagnosticRuleSet.enableExperimentalFeatures &&
ClassType.isBuiltIn(concreteSubtype, 'dict') &&
!ClassType.isBuiltIn(concreteSubtype, 'Dict');
let typeArgs = getTypeArgs(node, flags, {
isAnnotatedClass,
hasCustomClassGetItem: hasCustomClassGetItem || !isGenericClass,
isFinalAnnotation,
isClassVarAnnotation,
supportsTypedDictTypeArg,
});
if (!isAnnotatedClass) {
@ -7673,7 +7661,7 @@ export function createTypeEvaluator(
node: expr,
};
} else {
typeResult = getTypeArg(expr, adjFlags, !!options?.supportsTypedDictTypeArg && argIndex === 0);
typeResult = getTypeArg(expr, adjFlags);
}
return typeResult;
@ -7726,11 +7714,7 @@ export function createTypeEvaluator(
return typeArgs;
}
function getTypeArg(
node: ExpressionNode,
flags: EvaluatorFlags,
supportsDictExpression: boolean
): TypeResultWithNode {
function getTypeArg(node: ExpressionNode, flags: EvaluatorFlags): TypeResultWithNode {
let typeResult: TypeResultWithNode;
let adjustedFlags =
@ -7755,18 +7739,6 @@ export function createTypeEvaluator(
// Set the node's type so it isn't reevaluated later.
setTypeResultForNode(node, { type: UnknownType.create() });
} else if (node.nodeType === ParseNodeType.Dictionary && supportsDictExpression) {
const inlinedTypeDict =
typedDictClass && isInstantiableClass(typedDictClass)
? createTypedDictTypeInlined(evaluatorInterface, node, typedDictClass)
: undefined;
const keyTypeFallback = strClass && isInstantiableClass(strClass) ? strClass : UnknownType.create();
typeResult = {
type: keyTypeFallback,
inlinedTypeDict,
node,
};
} else {
typeResult = { ...getTypeOfExpression(node, adjustedFlags), node };

View File

@ -235,34 +235,6 @@ export function createTypedDictType(
return classType;
}
// Creates a new anonymous TypedDict class from an inlined dict[{}] type annotation.
export function createTypedDictTypeInlined(
evaluator: TypeEvaluator,
dictNode: DictionaryNode,
typedDictClass: ClassType
): ClassType {
const fileInfo = AnalyzerNodeInfo.getFileInfo(dictNode);
const className = '<TypedDict>';
const classType = ClassType.createInstantiable(
className,
ParseTreeUtils.getClassFullName(dictNode, fileInfo.moduleName, className),
fileInfo.moduleName,
fileInfo.fileUri,
ClassTypeFlags.TypedDictClass,
ParseTreeUtils.getTypeSourceId(dictNode),
/* declaredMetaclass */ undefined,
typedDictClass.details.effectiveMetaclass
);
classType.details.baseClasses.push(typedDictClass);
computeMroLinearization(classType);
getTypedDictFieldsFromDictSyntax(evaluator, dictNode, ClassType.getSymbolTable(classType), /* isInline */ true);
synthesizeTypedDictClassMethods(evaluator, dictNode, classType);
return classType;
}
export function synthesizeTypedDictClassMethods(
evaluator: TypeEvaluator,
node: ClassNode | ExpressionNode,

View File

@ -1,36 +0,0 @@
# This sample tests support for inlined TypedDict definitions.
from typing import Dict
td1: dict[{"a": int, "b": str}] = {"a": 0, "b": ""}
td2: dict[{"a": dict[{"b": int}]}] = {"a": {"b": 0}}
td3: dict[{"a": "list[float]"}] = {"a": [3]}
# This should generate two errors because dictionary literals can be used
# only with dict or Dict.
err1: list[{"a": 1}]
# This should generate an error because dictionary comprehensions
# are not allowed.
err2: dict[{"a": int for _ in range(1)}]
# This should generate an error because unpacked dictionary
# entries are not allowed.
err3: dict[{**{"a": int}}]
# This should generate three errors because Dict doesn't support inlined
# TypedDict. It generates an exception at runtime.
err4: Dict[{"c": int}]
# This should generate an error because an extra type argument is provided.
err5: dict[{"a": int}, str]
def func1(val: dict[{"a": int}]) -> dict[{"a": int}]:
return {"a": val["a"] + 1}
func1({"a": 3})

View File

@ -737,14 +737,6 @@ test('TypedDict24', () => {
TestUtils.validateResults(analysisResults, 1);
});
test('TypedDictInline1', () => {
const configOptions = new ConfigOptions(Uri.empty());
configOptions.diagnosticRuleSet.enableExperimentalFeatures = true;
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typedDictInline1.py'], configOptions);
TestUtils.validateResults(analysisResults, 9);
});
test('ClassVar1', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['classVar1.py']);