From 3c5e88888dbc47fc051dd6196c059ffeef95ed05 Mon Sep 17 00:00:00 2001 From: STerliakov Date: Thu, 22 May 2025 23:59:02 +0200 Subject: [PATCH] Forbid `.pop` of `Readonly` `NotRequired` items --- mypy/plugins/default.py | 2 +- test-data/unit/check-typeddict.test | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mypy/plugins/default.py b/mypy/plugins/default.py index 81d2f19dc17b..2002a4f06093 100644 --- a/mypy/plugins/default.py +++ b/mypy/plugins/default.py @@ -316,7 +316,7 @@ def typed_dict_pop_callback(ctx: MethodContext) -> Type: value_types = [] for key in keys: - if key in ctx.type.required_keys: + if key in ctx.type.required_keys or key in ctx.type.readonly_keys: ctx.api.msg.typeddict_key_cannot_be_deleted(ctx.type, key, key_expr) value_type = ctx.type.items.get(key) diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index 47c8a71ba0e3..cae90d56c3a6 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -3760,20 +3760,24 @@ del x["optional_key"] # E: Key "optional_key" of TypedDict "TP" cannot be delet [typing fixtures/typing-typeddict.pyi] [case testTypedDictReadOnlyMutateMethods] -from typing import ReadOnly, TypedDict +from typing import ReadOnly, NotRequired, TypedDict class TP(TypedDict): key: ReadOnly[str] + optional_key: ReadOnly[NotRequired[str]] other: ReadOnly[int] mutable: bool x: TP reveal_type(x.pop("key")) # N: Revealed type is "builtins.str" \ # E: Key "key" of TypedDict "TP" cannot be deleted +reveal_type(x.pop("optional_key")) # N: Revealed type is "builtins.str" \ + # E: Key "optional_key" of TypedDict "TP" cannot be deleted x.update({"key": "abc", "other": 1, "mutable": True}) # E: ReadOnly TypedDict keys ("key", "other") TypedDict are mutated x.setdefault("key", "abc") # E: ReadOnly TypedDict key "key" TypedDict is mutated +x.setdefault("optional_key", "foo") # E: ReadOnly TypedDict key "optional_key" TypedDict is mutated x.setdefault("other", 1) # E: ReadOnly TypedDict key "other" TypedDict is mutated x.setdefault("mutable", False) # ok [builtins fixtures/dict.pyi]