Skip to content

Commit 3ec0284

Browse files
authored
Fix error message for dataclasses.field with positional argument (#11180)
Fixes #10248 The crash due to dataclasses.field was fixed in the recent PR #11137, but the error message was wrong when positional arguments are used. I update the error message based on #10248 (comment) (Thanks @JelleZijlstra!)
1 parent 8b47a03 commit 3ec0284

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

mypy/plugins/dataclasses.py

+11-9
Original file line numberDiff line numberDiff line change
@@ -460,16 +460,18 @@ def _collect_field_args(expr: Expression,
460460
):
461461
# field() only takes keyword arguments.
462462
args = {}
463-
for name, arg in zip(expr.arg_names, expr.args):
464-
if name is None:
465-
# This means that `field` is used with `**` unpacking,
466-
# the best we can do for now is not to fail.
467-
# TODO: we can infer what's inside `**` and try to collect it.
468-
ctx.api.fail(
469-
'Unpacking **kwargs in "field()" is not supported',
470-
expr,
471-
)
463+
for name, arg, kind in zip(expr.arg_names, expr.args, expr.arg_kinds):
464+
if not kind.is_named():
465+
if kind.is_named(star=True):
466+
# This means that `field` is used with `**` unpacking,
467+
# the best we can do for now is not to fail.
468+
# TODO: we can infer what's inside `**` and try to collect it.
469+
message = 'Unpacking **kwargs in "field()" is not supported'
470+
else:
471+
message = '"field()" does not accept positional arguments'
472+
ctx.api.fail(message, expr)
472473
return True, {}
474+
assert name is not None
473475
args[name] = arg
474476
return True, args
475477
return False, {}

test-data/unit/check-dataclasses.test

+13
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,19 @@ main:7: note: def [_T] field(*, default_factory: Callable[[], _T], init: boo
13201320
main:7: note: def field(*, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> Any
13211321
[builtins fixtures/dataclasses.pyi]
13221322

1323+
[case testDataclassFieldWithPositionalArguments]
1324+
# flags: --python-version 3.7
1325+
from dataclasses import dataclass, field
1326+
1327+
@dataclass
1328+
class C:
1329+
x: int = field(0) # E: "field()" does not accept positional arguments \
1330+
# E: No overload variant of "field" matches argument type "int" \
1331+
# N: Possible overload variants: \
1332+
# N: def [_T] field(*, default: _T, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> _T \
1333+
# N: def [_T] field(*, default_factory: Callable[[], _T], init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> _T \
1334+
# N: def field(*, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> Any
1335+
[builtins fixtures/dataclasses.pyi]
13231336

13241337
[case testDataclassFieldWithTypedDictUnpacking]
13251338
# flags: --python-version 3.7

0 commit comments

Comments
 (0)