Fixed bug that causes a false negative when a TypedDict overrides a parent with extra_items that are not ReadOnly with a ReadOnly field. This addresses #11037. (#11038)
Some checks failed
Run mypy_primer on push / Run mypy_primer on push (push) Has been cancelled
Validation / Typecheck (push) Has been cancelled
Validation / Style (push) Has been cancelled
Validation / Test macos-latest (push) Has been cancelled
Validation / Test ubuntu-latest (push) Has been cancelled
Validation / Test windows-latest (push) Has been cancelled
Validation / Build (push) Has been cancelled
Validation / Required (push) Has been cancelled

This commit is contained in:
Eric Traut 2025-10-15 22:13:38 -07:00 committed by GitHub
parent ba3f0d4313
commit 538053da7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 28 additions and 1 deletions

View file

@ -6337,6 +6337,12 @@ export class Checker extends ParseTreeWalker {
type: this._evaluator.printType(entry.valueType),
})
);
} else if (!baseTypedDictEntries.extraItems.isReadOnly && entry.isReadOnly) {
diag.addMessage(
LocAddendum.typedDictClosedFieldNotReadOnly().format({
name,
})
);
} else if (!baseTypedDictEntries.extraItems.isReadOnly && entry.isRequired) {
diag.addMessage(
LocAddendum.typedDictClosedFieldNotRequired().format({

View file

@ -1563,6 +1563,10 @@ export namespace Localizer {
new ParameterizedString<{ name: string; type: string }>(
getRawString('DiagnosticAddendum.typedDictClosedExtraTypeMismatch')
);
export const typedDictClosedFieldNotReadOnly = () =>
new ParameterizedString<{ name: string }>(
getRawString('DiagnosticAddendum.typedDictClosedFieldNotReadOnly')
);
export const typedDictClosedFieldNotRequired = () =>
new ParameterizedString<{ name: string }>(
getRawString('DiagnosticAddendum.typedDictClosedFieldNotRequired')

View file

@ -2114,6 +2114,10 @@
},
"typedDictClosedExtraNotAllowed": "Cannot add item \"{name}\"",
"typedDictClosedExtraTypeMismatch": "Cannot add item \"{name}\" with type \"{type}\"",
"typedDictClosedFieldNotReadOnly": {
"message": "Cannot add item \"{name}\" because it must be ReadOnly",
"comment": "{Locked='ReadOnly'}"
},
"typedDictClosedFieldNotRequired": {
"message": "Cannot add item \"{name}\" because it must be NotRequired",
"comment": "{Locked='NotRequired'}"

View file

@ -125,15 +125,28 @@ class MovieWithYear(MovieBase):
class ParentNonOpen5(TypedDict, closed=True):
pass
# This should generate an error because a subclass of
# a closed TypedDict cannot be open.
class ChildNotClosed5(ParentNonOpen5, closed=False):
pass
class ParentNonOpen6(TypedDict, extra_items=str):
pass
# This should generate an error because a subclass of
# a closed TypedDict cannot be open.
class ChildNotClosed6(ParentNonOpen6, closed=False):
pass
class ParentNonOpen7(TypedDict, extra_items=str):
pass
# This should generate an error because added fields
# cannot be ReadOnly.
class ChildNotClosed7(ParentNonOpen7):
a: NotRequired[ReadOnly[str]]

View file

@ -360,7 +360,7 @@ test('TypedDictClosed2', () => {
test('TypedDictClosed3', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typedDictClosed3.py']);
TestUtils.validateResults(analysisResults, 12);
TestUtils.validateResults(analysisResults, 13);
});
test('TypedDictClosed4', () => {