diff --git a/mypy/nodes.py b/mypy/nodes.py index 4787930214f3..72e82bdbe222 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -3889,7 +3889,7 @@ def __init__( eq_default: bool | None = None, order_default: bool | None = None, kw_only_default: bool | None = None, - field_specifiers: tuple[str, ...] | None = None, + field_specifiers: list[str] | None = None, # Specified outside of PEP 681: # frozen_default was added to CPythonin https://github.com/python/cpython/pull/99958 citing # positive discussion in typing-sig @@ -3899,7 +3899,7 @@ def __init__( self.order_default = order_default if order_default is not None else False self.kw_only_default = kw_only_default if kw_only_default is not None else False self.frozen_default = frozen_default if frozen_default is not None else False - self.field_specifiers = field_specifiers if field_specifiers is not None else () + self.field_specifiers = field_specifiers or [] def serialize(self) -> JsonDict: return { diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index 6b1062d6457f..38dc53a263aa 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -70,7 +70,7 @@ order_default=False, kw_only_default=False, frozen_default=False, - field_specifiers=("dataclasses.Field", "dataclasses.field"), + field_specifiers=["dataclasses.Field", "dataclasses.field"], ) diff --git a/mypy/semanal.py b/mypy/semanal.py index d2fd92499679..b6c411aaeea3 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -6515,18 +6515,18 @@ def parse_dataclass_transform_spec(self, call: CallExpr) -> DataclassTransformSp return parameters - def parse_dataclass_transform_field_specifiers(self, arg: Expression) -> tuple[str, ...]: + def parse_dataclass_transform_field_specifiers(self, arg: Expression) -> list[str]: if not isinstance(arg, TupleExpr): self.fail('"field_specifiers" argument must be a tuple literal', arg) - return tuple() + return [] - names = [] + names: list[str] = [] for specifier in arg.items: if not isinstance(specifier, RefExpr): self.fail('"field_specifiers" must only contain identifiers', specifier) - return tuple() + return [] names.append(specifier.fullname) - return tuple(names) + return names def replace_implicit_first_type(sig: FunctionLike, new: Type) -> FunctionLike: diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index 58339828677d..953bcf97321f 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -10341,3 +10341,40 @@ reveal_type(x) [out] == a.py:3: note: Revealed type is "Union[def (x: builtins.int) -> builtins.int, def (*x: builtins.int) -> builtins.int]" + +[case testDataclassTransformFieldSpecifiers] +# flags: --python-version 3.7 +import b + +[file b.py] +from abc import ABCMeta +from typing import Any, Optional +from typing_extensions import dataclass_transform + +class Field: + def __init__(self, default: Any = None) -> None: ... + +class FieldInfo: + def __init__(self, default: Any = None, *, alias: Optional[str] = None) -> None: ... + +@dataclass_transform(field_specifiers=(Field, FieldInfo)) +class ModelMetaclass(ABCMeta): ... + +class BaseModel(metaclass=ModelMetaclass): ... + +class Event(BaseModel): + id: Optional[int] = None +[builtins fixtures/tuple.pyi] + +[file c.py] +from b import Event +Event() + +[file c.py.2] +from b import Event +Event() +reveal_type(1) + +[out] +== +c.py:3: note: Revealed type is "Literal[1]?"