mirror of
https://github.com/microsoft/pyright.git
synced 2025-12-23 09:19:29 +00:00
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
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:
parent
ba3f0d4313
commit
538053da7a
5 changed files with 28 additions and 1 deletions
|
|
@ -6337,6 +6337,12 @@ export class Checker extends ParseTreeWalker {
|
||||||
type: this._evaluator.printType(entry.valueType),
|
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) {
|
} else if (!baseTypedDictEntries.extraItems.isReadOnly && entry.isRequired) {
|
||||||
diag.addMessage(
|
diag.addMessage(
|
||||||
LocAddendum.typedDictClosedFieldNotRequired().format({
|
LocAddendum.typedDictClosedFieldNotRequired().format({
|
||||||
|
|
|
||||||
|
|
@ -1563,6 +1563,10 @@ export namespace Localizer {
|
||||||
new ParameterizedString<{ name: string; type: string }>(
|
new ParameterizedString<{ name: string; type: string }>(
|
||||||
getRawString('DiagnosticAddendum.typedDictClosedExtraTypeMismatch')
|
getRawString('DiagnosticAddendum.typedDictClosedExtraTypeMismatch')
|
||||||
);
|
);
|
||||||
|
export const typedDictClosedFieldNotReadOnly = () =>
|
||||||
|
new ParameterizedString<{ name: string }>(
|
||||||
|
getRawString('DiagnosticAddendum.typedDictClosedFieldNotReadOnly')
|
||||||
|
);
|
||||||
export const typedDictClosedFieldNotRequired = () =>
|
export const typedDictClosedFieldNotRequired = () =>
|
||||||
new ParameterizedString<{ name: string }>(
|
new ParameterizedString<{ name: string }>(
|
||||||
getRawString('DiagnosticAddendum.typedDictClosedFieldNotRequired')
|
getRawString('DiagnosticAddendum.typedDictClosedFieldNotRequired')
|
||||||
|
|
|
||||||
|
|
@ -2114,6 +2114,10 @@
|
||||||
},
|
},
|
||||||
"typedDictClosedExtraNotAllowed": "Cannot add item \"{name}\"",
|
"typedDictClosedExtraNotAllowed": "Cannot add item \"{name}\"",
|
||||||
"typedDictClosedExtraTypeMismatch": "Cannot add item \"{name}\" with type \"{type}\"",
|
"typedDictClosedExtraTypeMismatch": "Cannot add item \"{name}\" with type \"{type}\"",
|
||||||
|
"typedDictClosedFieldNotReadOnly": {
|
||||||
|
"message": "Cannot add item \"{name}\" because it must be ReadOnly",
|
||||||
|
"comment": "{Locked='ReadOnly'}"
|
||||||
|
},
|
||||||
"typedDictClosedFieldNotRequired": {
|
"typedDictClosedFieldNotRequired": {
|
||||||
"message": "Cannot add item \"{name}\" because it must be NotRequired",
|
"message": "Cannot add item \"{name}\" because it must be NotRequired",
|
||||||
"comment": "{Locked='NotRequired'}"
|
"comment": "{Locked='NotRequired'}"
|
||||||
|
|
|
||||||
|
|
@ -125,15 +125,28 @@ class MovieWithYear(MovieBase):
|
||||||
class ParentNonOpen5(TypedDict, closed=True):
|
class ParentNonOpen5(TypedDict, closed=True):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# This should generate an error because a subclass of
|
# This should generate an error because a subclass of
|
||||||
# a closed TypedDict cannot be open.
|
# a closed TypedDict cannot be open.
|
||||||
class ChildNotClosed5(ParentNonOpen5, closed=False):
|
class ChildNotClosed5(ParentNonOpen5, closed=False):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ParentNonOpen6(TypedDict, extra_items=str):
|
class ParentNonOpen6(TypedDict, extra_items=str):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# This should generate an error because a subclass of
|
# This should generate an error because a subclass of
|
||||||
# a closed TypedDict cannot be open.
|
# a closed TypedDict cannot be open.
|
||||||
class ChildNotClosed6(ParentNonOpen6, closed=False):
|
class ChildNotClosed6(ParentNonOpen6, closed=False):
|
||||||
pass
|
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]]
|
||||||
|
|
|
||||||
|
|
@ -360,7 +360,7 @@ test('TypedDictClosed2', () => {
|
||||||
|
|
||||||
test('TypedDictClosed3', () => {
|
test('TypedDictClosed3', () => {
|
||||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typedDictClosed3.py']);
|
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typedDictClosed3.py']);
|
||||||
TestUtils.validateResults(analysisResults, 12);
|
TestUtils.validateResults(analysisResults, 13);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('TypedDictClosed4', () => {
|
test('TypedDictClosed4', () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue