8000 Added support for dictionary expansion of a TypedDict within a dictio… · codean-io/scip-python@eb1ef07 · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit eb1ef07

Browse files
committed
Added support for dictionary expansion of a TypedDict within a dictionary literal expression.
1 parent 22c667f commit eb1ef07

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

packages/pyright-internal/src/analyzer/typeEvaluator.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12184,6 +12184,25 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
1218412184
const unexpandedType = unexpandedTypeResult.type;
1218512185
if (isAnyOrUnknown(unexpandedType)) {
1218612186
addUnknown = false;
12187+
} else if (isClassInstance(unexpandedType) && ClassType.isTypedDictClass(unexpandedType)) {
12188+
// Handle dictionary expansion for a TypedDict.
12189+
if (strClassType && isInstantiableClass(strClassType)) {
12190+
const strObject = ClassType.cloneAsInstance(strClassType);
12191+
const tdEntries = getTypedDictMembersForClass(
12192+
evaluatorInterface,
12193+
unexpandedTyp 10000 e,
12194+
/* allowNarrowed */ true
12195+
);
12196+
12197+
tdEntries.forEach((entry, name) => {
12198+
if (entry.isRequired || entry.isProvided) {
12199+
keyTypes.push(ClassType.cloneWithLiteral(strObject, name));
12200+
valueTypes.push(entry.valueType);
12201+
}
12202+
});
12203+
12204+
addUnknown = false;
12205+
}
1218712206
} else {
1218812207
// Verify that the type supports the `keys` and `__getitem__` methods.
1218912208
// This protocol is defined in the _typeshed stub. If we can't find
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# This sample tests the handling of dictionary expansion for TypedDicts.
2+
3+
from typing_extensions import NotRequired, Required, TypedDict
4+
5+
6+
class TD1(TypedDict):
7+
v1: Required[int]
8+
9+
10+
class TD2(TypedDict):
11+
v2: Required[str]
12+
13+
14+
class TD3(TypedDict):
15+
v1: NotRequired[int]
16+
17+
18+
class TD4(TD1, TD2):
19+
...
20+
21+
22+
td1: TD1 = {"v1": 0}
23+
td2: TD2 = {"v2": ""}
24+
td3_1: TD3 = {}
25+
td3_2: TD3 = {"v1": 0}
26+
27+
td4_1: TD4 = {**td1, **td2}
28+
29+
# This should generate an error because td3_1
30+
# does not include the required "v1" entry.
31+
td4_2: TD4 = {**td3_1, **td2}
32+
33+
td4_3: TD4 = {**td3_2, **td2}

packages/pyright-internal/src/tests/typeEvaluator2.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,3 +1287,9 @@ test('TypedDict20', () => {
12871287

12881288
TestUtils.validateResults(analysisResults, 0);
12891289
});
1290+
1291+
test('TypedDict21', () => {
1292+
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typedDict21.py']);
1293+
1294+
TestUtils.validateResults(analysisResults, 1);
1295+
});

0 commit comments

Comments
 (0)
0