Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitce14043

Browse files
Use more precise context for TypedDict plugin errors (#18293)
Fixes#12271Uses an applicable argument expression as the error context instead ofthe overall CallExpr.**Given:**```python# flags: --pretty --show-column-numberfrom typing import TypedDictclass A(TypedDict): x: inta: Ax.setdefault("y", 123)x.setdefault("x", "bad")# Non-TypedDict case for referenceb: dict[str, int]b.setdefault("x", "bad")```**Before:**```main.py:8:1: error: TypedDict "A" has no key "y" [typeddict-item] a.setdefault("y", 123) ^~~~~~~~~~~~~~~~~~~~~~main.py:9:1: error: Argument 2 to "setdefault" of "TypedDict" has incompatible type "str"; expected "int" [typeddict-item] a.setdefault("x", "bad") ^~~~~~~~~~~~~~~~~~~~~~~~main.py:13:19: error: Argument 2 to "setdefault" of "MutableMapping" has incompatible type "str"; expected "int" [arg-type] b.setdefault("x", "bad") ^~~~~Found 3 errors in 1 file (checked 1 source file)```**After:**```main.py:8:14: error: TypedDict "A" has no key "y" [typeddict-item] a.setdefault("y", 123) ^~~main.py:9:19: error: Argument 2 to "setdefault" of "TypedDict" has incompatible type "str"; expected "int" [typeddict-item] a.setdefault("x", "bad") ^~~~~main.py:13:19: error: Argument 2 to "setdefault" of "MutableMapping" has incompatible type "str"; expected "int" [arg-type] b.setdefault("x", "bad") ^~~~~Found 3 errors in 1 file (checked 1 source file)```
1 parent973618a commitce14043

File tree

4 files changed

+40
-22
lines changed

4 files changed

+40
-22
lines changed

‎mypy/plugins/default.py‎

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -304,25 +304,26 @@ def typed_dict_pop_callback(ctx: MethodContext) -> Type:
304304
andlen(ctx.arg_types)>=1
305305
andlen(ctx.arg_types[0])==1
306306
):
307-
keys=try_getting_str_literals(ctx.args[0][0],ctx.arg_types[0][0])
307+
key_expr=ctx.args[0][0]
308+
keys=try_getting_str_literals(key_expr,ctx.arg_types[0][0])
308309
ifkeysisNone:
309310
ctx.api.fail(
310311
message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL,
311-
ctx.context,
312+
key_expr,
312313
code=codes.LITERAL_REQ,
313314
)
314315
returnAnyType(TypeOfAny.from_error)
315316

316317
value_types= []
317318
forkeyinkeys:
318319
ifkeyinctx.type.required_keys:
319-
ctx.api.msg.typeddict_key_cannot_be_deleted(ctx.type,key,ctx.context)
320+
ctx.api.msg.typeddict_key_cannot_be_deleted(ctx.type,key,key_expr)
320321

321322
value_type=ctx.type.items.get(key)
322323
ifvalue_type:
323324
value_types.append(value_type)
324325
else:
325-
ctx.api.msg.typeddict_key_not_found(ctx.type,key,ctx.context)
326+
ctx.api.msg.typeddict_key_not_found(ctx.type,key,key_expr)
326327
returnAnyType(TypeOfAny.from_error)
327328

328329
iflen(ctx.args[1])==0:
@@ -363,27 +364,29 @@ def typed_dict_setdefault_callback(ctx: MethodContext) -> Type:
363364
andlen(ctx.arg_types[0])==1
364365
andlen(ctx.arg_types[1])==1
365366
):
366-
keys=try_getting_str_literals(ctx.args[0][0],ctx.arg_types[0][0])
367+
key_expr=ctx.args[0][0]
368+
keys=try_getting_str_literals(key_expr,ctx.arg_types[0][0])
367369
ifkeysisNone:
368370
ctx.api.fail(
369371
message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL,
370-
ctx.context,
372+
key_expr,
371373
code=codes.LITERAL_REQ,
372374
)
373375
returnAnyType(TypeOfAny.from_error)
374376

375377
assigned_readonly_keys=ctx.type.readonly_keys&set(keys)
376378
ifassigned_readonly_keys:
377-
ctx.api.msg.readonly_keys_mutated(assigned_readonly_keys,context=ctx.context)
379+
ctx.api.msg.readonly_keys_mutated(assigned_readonly_keys,context=key_expr)
378380

379381
default_type=ctx.arg_types[1][0]
382+
default_expr=ctx.args[1][0]
380383

381384
value_types= []
382385
forkeyinkeys:
383386
value_type=ctx.type.items.get(key)
384387

385388
ifvalue_typeisNone:
386-
ctx.api.msg.typeddict_key_not_found(ctx.type,key,ctx.context)
389+
ctx.api.msg.typeddict_key_not_found(ctx.type,key,key_expr)
387390
returnAnyType(TypeOfAny.from_error)
388391

389392
# The signature_callback above can't always infer the right signature
@@ -392,7 +395,7 @@ def typed_dict_setdefault_callback(ctx: MethodContext) -> Type:
392395
# default can be assigned to all key-value pairs we're updating.
393396
ifnotis_subtype(default_type,value_type):
394397
ctx.api.msg.typeddict_setdefault_arguments_inconsistent(
395-
default_type,value_type,ctx.context
398+
default_type,value_type,default_expr
396399
)
397400
returnAnyType(TypeOfAny.from_error)
398401

@@ -409,20 +412,21 @@ def typed_dict_delitem_callback(ctx: MethodContext) -> Type:
409412
andlen(ctx.arg_types)==1
410413
andlen(ctx.arg_types[0])==1
411414
):
412-
keys=try_getting_str_literals(ctx.args[0][0],ctx.arg_types[0][0])
415+
key_expr=ctx.args[0][0]
416+
keys=try_getting_str_literals(key_expr,ctx.arg_types[0][0])
413417
ifkeysisNone:
414418
ctx.api.fail(
415419
message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL,
416-
ctx.context,
420+
key_expr,
417421
code=codes.LITERAL_REQ,
418422
)
419423
returnAnyType(TypeOfAny.from_error)
420424

421425
forkeyinkeys:
422426
ifkeyinctx.type.required_keysorkeyinctx.type.readonly_keys:
423-
ctx.api.msg.typeddict_key_cannot_be_deleted(ctx.type,key,ctx.context)
427+
ctx.api.msg.typeddict_key_cannot_be_deleted(ctx.type,key,key_expr)
424428
elifkeynotinctx.type.items:
425-
ctx.api.msg.typeddict_key_not_found(ctx.type,key,ctx.context)
429+
ctx.api.msg.typeddict_key_not_found(ctx.type,key,key_expr)
426430
returnctx.default_return_type
427431

428432

‎test-data/unit/check-columns.test‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,19 @@ class D(TypedDict):
227227
x: int
228228
t: D = {'x':
229229
'y'} # E:5: Incompatible types (expression has type "str", TypedDict item "x" has type "int")
230+
s: str
230231

231232
if int():
232-
del t['y'] # E:5: TypedDict "D" has no key "y"
233+
del t[s] # E:11: Expected TypedDict key to be string literal
234+
del t["x"] # E:11: Key "x" of TypedDict "D" cannot be deleted
235+
del t["y"] # E:11: TypedDict "D" has no key "y"
236+
237+
t.pop(s) # E:7: Expected TypedDict key to be string literal
238+
t.pop("y") # E:7: TypedDict "D" has no key "y"
239+
240+
t.setdefault(s, 123) # E:14: Expected TypedDict key to be string literal
241+
t.setdefault("x", "a") # E:19: Argument 2 to "setdefault" of "TypedDict" has incompatible type "str"; expected "int"
242+
t.setdefault("y", 123) # E:14: TypedDict "D" has no key "y"
233243
[builtins fixtures/dict.pyi]
234244
[typing fixtures/typing-typeddict.pyi]
235245

‎test-data/unit/check-literal.test‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,8 +1909,9 @@ reveal_type(d.get(a_key, u)) # N: Revealed type is "Union[builtins.int, __main_
19091909
reveal_type(d.get(b_key, u)) # N: Revealed type is "Union[builtins.str, __main__.Unrelated]"
19101910
reveal_type(d.get(c_key, u)) # N: Revealed type is "builtins.object"
19111911

1912-
reveal_type(d.pop(a_key)) # E: Key "a" of TypedDict "Outer" cannot be deleted \
1913-
# N: Revealed type is "builtins.int"
1912+
reveal_type(d.pop(a_key)) # N: Revealed type is "builtins.int" \
1913+
# E: Key "a" of TypedDict "Outer" cannot be deleted
1914+
19141915
reveal_type(d.pop(b_key)) # N: Revealed type is "builtins.str"
19151916
d.pop(c_key) # E: TypedDict "Outer" has no key "c"
19161917

‎test-data/unit/check-typeddict.test‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,8 +1747,9 @@ td: Union[TDA, TDB]
17471747

17481748
reveal_type(td.pop('a')) # N: Revealed type is "builtins.int"
17491749
reveal_type(td.pop('b')) # N: Revealed type is "Union[builtins.str, builtins.int]"
1750-
reveal_type(td.pop('c')) # E: TypedDict "TDA" has no key "c" \
1751-
# N: Revealed type is "Union[Any, builtins.int]"
1750+
reveal_type(td.pop('c')) # N: Revealed type is "Union[Any, builtins.int]" \
1751+
# E: TypedDict "TDA" has no key "c"
1752+
17521753
[builtins fixtures/dict.pyi]
17531754
[typing fixtures/typing-typeddict.pyi]
17541755

@@ -2614,8 +2615,9 @@ def func(foo: Union[Foo1, Foo2]):
26142615

26152616
del foo["missing"] # E: TypedDict "Foo1" has no key "missing" \
26162617
# E: TypedDict "Foo2" has no key "missing"
2617-
del foo[1] # E: Expected TypedDict key to be string literal \
2618-
# E: Argument 1 to "__delitem__" has incompatible type "int"; expected "str"
2618+
del foo[1] # E: Argument 1 to "__delitem__" has incompatible type "int"; expected "str" \
2619+
# E: Expected TypedDict key to be string literal
2620+
26192621
[builtins fixtures/dict.pyi]
26202622
[typing fixtures/typing-typeddict.pyi]
26212623

@@ -3726,8 +3728,9 @@ class TP(TypedDict):
37263728
mutable: bool
37273729

37283730
x: TP
3729-
reveal_type(x.pop("key")) # E: Key "key" of TypedDict "TP" cannot be deleted \
3730-
# N: Revealed type is "builtins.str"
3731+
reveal_type(x.pop("key")) # N: Revealed type is "builtins.str" \
3732+
# E: Key "key" of TypedDict "TP" cannot be deleted
3733+
37313734

37323735
x.update({"key": "abc", "other": 1, "mutable": True}) # E: ReadOnly TypedDict keys ("key", "other") TypedDict are mutated
37333736
x.setdefault("key", "abc") # E: ReadOnly TypedDict key "key" TypedDict is mutated

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp