Repository: pydantic/pydantic

Issue:
mypy error "Unexpected keyword argument" on pydantic dataclass InitVar field
### Initial Checks

- [X] I have searched GitHub for a duplicate issue and I'm sure this is something new
- [X] I have searched Google & StackOverflow for a solution and couldn't find anything
- [X] I have read and followed [the docs](https://docs.pydantic.dev) and still think this is a bug
- [X] I am confident that the issue is with pydantic (not my code, or another library in the ecosystem like [FastAPI](https://fastapi.tiangolo.com) or [mypy](https://mypy.readthedocs.io/en/stable))


### Description

Since upgrading to pydantic 1.10.6, mypy started complaining about a kwarg being passed to the constructor of a dataclass if the field is an `InitVar`.

I'm guessing it might be related to https://github.com/pydantic/pydantic/pull/5111

```
$ mypy test.py
test.py:10: error: Unexpected keyword argument "foo" for "MyDataclass"  [call-arg]
Found 1 error in 1 file (checked 1 source file)
```


### Example Code

```Python
from pydantic.dataclasses import dataclass
from dataclasses import InitVar

@dataclass
class MyDataclass:
    foo: InitVar[str]
    bar: str

MyDataclass(foo="foo", bar="bar")
```


### Python, Pydantic & OS Version

```Text
pydantic version: 1.10.6
            pydantic compiled: True
                 install path: /home/brian/repos/medigator/venv/lib/python3.8/site-packages/pydantic
               python version: 3.8.10 (default, Nov 14 2022, 12:59:47)  [GCC 9.4.0]
                     platform: Linux-5.15.0-67-generic-x86_64-with-glibc2.29
     optional deps. installed: ['dotenv', 'email-validator', 'typing-extensions']
```


### Affected Components

- [ ] [Compatibility between releases](https://docs.pydantic.dev/changelog/)
- [ ] [Data validation/parsing](https://docs.pydantic.dev/usage/models/#basic-model-usage)
- [ ] [Data serialization](https://docs.pydantic.dev/usage/exporting_models/) - `.dict()` and `.json()`
- [ ] [JSON Schema](https://docs.pydantic.dev/usage/schema/)
- [X] [Dataclasses](https://docs.pydantic.dev/usage/dataclasses/)
- [ ] [Model Config](https://docs.pydantic.dev/usage/model_config/)
- [ ] [Field Types](https://docs.pydantic.dev/usage/types/) - adding or changing a particular data type
- [ ] [Function validation decorator](https://docs.pydantic.dev/usage/validation_decorator/)
- [ ] [Generic Models](https://docs.pydantic.dev/usage/models/#generic-models)
- [ ] [Other Model behaviour](https://docs.pydantic.dev/usage/models/) - `construct()`, pickling, private attributes, ORM mode
- [X] [Plugins](https://docs.pydantic.dev/) and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.


Discussion:
This won't be related to #2309, rather it will be related to #5111.

@cdce8p @dmontagu any ideas?
whoops, pasted the wrong link, thanks
@brianmedigate what is your mypy config? In particular, are you using the pydantic mypy plugin?
yes

```ini
[mypy]
follow_imports = silent
ignore_missing_imports = True
warn_unused_ignores = True
check_untyped_defs = True
disallow_untyped_defs = True
strict_equality = True
warn_redundant_casts = True
python_version = 3.8
platform = linux
plugins = pydantic.mypy

[pydantic-mypy]
init_forbid_extra = True
init_typed = True
warn_required_dynamic_aliases = True
warn_untyped_fields = True
```
Okay, considering you are using the mypy plugin I think it should be readily within our power to fix this (and is probably our fault, to be honest 😅). I will try to take a look at this today or tomorrow.
great, thank you!
Possible fix: #5162
Until now, the plugin manually applied the dataclass transform to pydantic dataclasses. This isn't necessary anymore with mypy `1.1.1` and the `@dataclass_transform` decorator as it also applies the same transform.

In fact, doing it twice results in the `InitVar` issue seen here.

Resolving patch:
diff --git a/pydantic/mypy.py b/pydantic/mypy.py
--- a/pydantic/mypy.py
+++ b/pydantic/mypy.py
@@ -1,7 +1,8 @@
+from __future__ import annotations
+
 import sys
 from configparser import ConfigParser
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-from typing import Type as TypingType
+from typing import Any, Callable
 
 from mypy.errorcodes import ErrorCode
 from mypy.nodes import (
@@ -28,6 +29,7 @@
     PassStmt,
     PlaceholderNode,
     RefExpr,
+    Statement,
     StrExpr,
     SymbolNode,
     SymbolTableNode,
@@ -78,20 +80,26 @@
 MODEL_METACLASS_FULLNAME = 'pydantic.main.ModelMetaclass'
 FIELD_FULLNAME = 'pydantic.fields.Field'
 DATACLASS_FULLNAME = 'pydantic.dataclasses.dataclass'
+DECORATOR_FULLNAMES = {
+    'pydantic.decorators.validator',
+    'pydantic.decorators.field_validator',
+    'pydantic.decorators.root_validator',
+    'pydantic.decorators.serializer',
+}
 
 
-def parse_mypy_version(version: str) -> Tuple[int, ...]:
-    return tuple(int(part) for part in version.split('+', 1)[0].split('.'))
+def parse_mypy_version(version: str) -> tuple[int, ...]:
+    return tuple(map(int, version.partition('+')[0].split('.')))
 
 
 MYPY_VERSION_TUPLE = parse_mypy_version(mypy_version)
 BUILTINS_NAME = 'builtins' if MYPY_VERSION_TUPLE >= (0, 930) else '__builtins__'
 
 # Increment version if plugin changes and mypy caches should be invalidated
-PLUGIN_VERSION = 1
+__version__ = 2
 
 
-def plugin(version: str) -> 'TypingType[Plugin]':
+def plugin(version: str) -> type[Plugin]:
     """
     `version` is the mypy version string
 
@@ -105,10 +113,9 @@ class PydanticPlugin(Plugin):
     def __init__(self, options: Options) -> None:
         self.plugin_config = PydanticPluginConfig(options)
         self._plugin_data = self.plugin_config.to_data()
-        self._plugin_data['version'] = PLUGIN_VERSION
         super().__init__(options)
 
-    def get_base_class_hook(self, fullname: str) -> 'Optional[Callable[[ClassDefContext], None]]':
+    def get_base_class_hook(self, fullname: str) -> Callable[[ClassDefContext], None] | None:
         sym = self.lookup_fully_qualified(fullname)
         if sym and isinstance(sym.node, TypeInfo):  # pragma: no branch
             # No branching may occur if the mypy cache has not been cleared
@@ -116,28 +123,32 @@ def get_base_class_hook(self, fullname: str) -> 'Optional[Callable[[ClassDefCont
                 return self._pydantic_model_class_maker_callback
         return None
 
-    def get_metaclass_hook(self, fullname: str) -> Optional[Callable[[ClassDefContext], None]]:
+    def get_metaclass_hook(self, fullname: str) -> Callable[[ClassDefContext], None] | None:
         if fullname == MODEL_METACLASS_FULLNAME:
             return self._pydantic_model_metaclass_marker_callback
         return None
 
-    def get_function_hook(self, fullname: str) -> 'Optional[Callable[[FunctionContext], Type]]':
+    def get_function_hook(self, fullname: str) -> Callable[[FunctionContext], Type] | None:
         sym = self.lookup_fully_qualified(fullname)
         if sym and sym.fullname == FIELD_FULLNAME:
             return self._pydantic_field_callback
         return None
 
-    def get_method_hook(self, fullname: str) -> Optional[Callable[[MethodContext], Type]]:
+    def get_method_hook(self, fullname: str) -> Callable[[MethodContext], Type] | None:
         if fullname.endswith('.from_orm'):
             return from_attributes_callback
         return None
 
-    def get_class_decorator_hook(self, fullname: str) -> Optional[Callable[[ClassDefContext], None]]:
-        if fullname == DATACLASS_FULLNAME:
+    def get_class_decorator_hook(self, fullname: str) -> Callable[[ClassDefContext], None] | None:
+        """Mark pydantic.dataclasses as dataclass.
+
+        Mypy version 1.1.1 added support for `@dataclass_transform` decorator.
+        """
+        if fullname == DATACLASS_FULLNAME and MYPY_VERSION_TUPLE < (1, 1):
             return dataclasses.dataclass_class_maker_callback  # type: ignore[return-value]
         return None
 
-    def report_config_data(self, ctx: ReportConfigContext) -> Dict[str, Any]:
+    def report_config_data(self, ctx: ReportConfigContext) -> dict[str, Any]:
         """Return all plugin config data.
 
         Used by mypy to determine if cache needs to be discarded.
@@ -161,7 +172,7 @@ def _pydantic_model_metaclass_marker_callback(self, ctx: ClassDefContext) -> Non
         if getattr(info_metaclass.type, 'dataclass_transform_spec', None):
             info_metaclass.type.dataclass_transform_spec = None
 
-    def _pydantic_field_callback(self, ctx: FunctionContext) -> 'Type':
+    def _pydantic_field_callback(self, ctx: FunctionContext) -> Type:
         """
         Extract the type of the `default` argument from the Field function, and use it as the return type.
 
@@ -216,13 +227,11 @@ class PydanticPluginConfig:
         'init_forbid_extra',
         'init_typed',
         'warn_required_dynamic_aliases',
-        'warn_untyped_fields',
         'debug_dataclass_transform',
     )
     init_forbid_extra: bool
     init_typed: bool
     warn_required_dynamic_aliases: bool
-    warn_untyped_fields: bool
     debug_dataclass_transform: bool  # undocumented
 
     def __init__(self, options: Options) -> None:
@@ -244,7 +253,7 @@ def __init__(self, options: Options) -> None:
                 setting = plugin_config.getboolean(CONFIGFILE_KEY, key, fallback=False)
                 setattr(self, key, setting)
 
-    def to_data(self) -> Dict[str, Any]:
+    def to_data(self) -> dict[str, Any]:
         return {key: getattr(self, key) for key in self.__slots__}
 
 
@@ -274,7 +283,7 @@ def from_attributes_callback(ctx: MethodContext) -> Type:
 
 
 class PydanticModelTransformer:
-    tracked_config_fields: Set[str] = {
+    tracked_config_fields: set[str] = {
         'extra',
         'frozen',
         'from_attributes',
@@ -323,22 +332,17 @@ def adjust_validator_signatures(self) -> None:
         Teach mypy this by marking any function whose outermost decorator is a `validator()`,
         `field_validator()` or `serializer()` call as a `classmethod`.
         """
-        decorator_names = (
-            'pydantic.decorators.validator',
-            'pydantic.decorators.serializer',
-            'pydantic.decorators.field_validator',
-        )
         for name, sym in self._ctx.cls.info.names.items():
             if isinstance(sym.node, Decorator):
                 first_dec = sym.node.original_decorators[0]
                 if (
                     isinstance(first_dec, CallExpr)
                     and isinstance(first_dec.callee, NameExpr)
-                    and first_dec.callee.fullname in decorator_names
+                    and first_dec.callee.fullname in DECORATOR_FULLNAMES
                 ):
                     sym.node.func.is_class = True
 
-    def collect_config(self) -> 'ModelConfigData':  # noqa: C901 (ignore complexity)
+    def collect_config(self) -> ModelConfigData:  # noqa: C901 (ignore complexity)
         """
         Collects the values of the config attributes that are used by the plugin, accounting for parent classes.
         """
@@ -405,69 +409,21 @@ def collect_config(self) -> 'ModelConfigData':  # noqa: C901 (ignore complexity)
                 config.setdefault(name, value)
         return config
 
-    def collect_fields(self, model_config: 'ModelConfigData') -> List['PydanticModelField']:
+    def collect_fields(self, model_config: ModelConfigData) -> list[PydanticModelField]:
         """
         Collects the fields for the model, accounting for parent classes
         """
         # First, collect fields belonging to the current class.
         ctx = self._ctx
         cls = self._ctx.cls
-        fields = []  # type: List[PydanticModelField]
-        known_fields = set()  # type: Set[str]
+        fields: list[PydanticModelField] = []
+        known_fields: set[str] = set()
         for stmt in cls.defs.body:
-            if not isinstance(stmt, AssignmentStmt):  # `and stmt.new_syntax` to require annotation
-                continue
-
-            lhs = stmt.lvalues[0]
-            if not isinstance(lhs, NameExpr) or lhs.name.startswith('_') or lhs.name == 'model_config':
-                continue
-
-            if not stmt.new_syntax and self.plugin_config.warn_untyped_fields:
-                error_untyped_fields(ctx.api, stmt)
-
-            # if lhs.name == '__config__':  # ConfigDict not well handled; I'm not sure why yet
-            #     continue
-
-            sym = cls.info.names.get(lhs.name)
-            if sym is None:  # pragma: no cover
-                # This is likely due to a star import (see the dataclasses plugin for a more detailed explanation)
-                # This is the same logic used in the dataclasses plugin
-                continue
+            maybe_field = self.collect_field_from_stmt(stmt, model_config)
+            if maybe_field is not None:
+                fields.append(maybe_field)
+                known_fields.add(maybe_field.name)
 
-            node = sym.node
-            if isinstance(node, PlaceholderNode):  # pragma: no cover
-                # See the PlaceholderNode docstring for more detail about how this can occur
-                # Basically, it is an edge case when dealing with complex import logic
-                # This is the same logic used in the dataclasses plugin
-                continue
-            if not isinstance(node, Var):  # pragma: no cover
-                # Don't know if this edge case still happens with the `is_valid_field` check above
-                # but better safe than sorry
-                continue
-
-            # x: ClassVar[int] is ignored by dataclasses.
-            if node.is_classvar:
-                continue
-
-            is_required = self.get_is_required(cls, stmt, lhs)
-            alias, has_dynamic_alias = self.get_alias_info(stmt)
-            if (
-                has_dynamic_alias
-                and not model_config.populate_by_name
-                and self.plugin_config.warn_required_dynamic_aliases
-            ):
-                error_required_dynamic_aliases(ctx.api, stmt)
-            fields.append(
-                PydanticModelField(
-                    name=lhs.name,
-                    is_required=is_required,
-                    alias=alias,
-                    has_dynamic_alias=has_dynamic_alias,
-                    line=stmt.line,
-                    column=stmt.column,
-                )
-            )
-            known_fields.add(lhs.name)
         all_fields = fields.copy()
         for info in cls.info.mro[1:]:  # 0 is the current class, -2 is BaseModel, -1 is object
             if METADATA_KEY not in info.metadata:
@@ -489,7 +445,67 @@ def collect_fields(self, model_config: 'ModelConfigData') -> List['PydanticModel
             all_fields = superclass_fields + all_fields
         return all_fields
 
-    def add_initializer(self, fields: List['PydanticModelField'], config: 'ModelConfigData') -> None:
+    def collect_field_from_stmt(self, stmt: Statement, model_config: ModelConfigData) -> PydanticModelField | None:
+        ctx = self._ctx
+        cls = self._ctx.cls
+        if not isinstance(stmt, AssignmentStmt):
+            return None
+
+        lhs = stmt.lvalues[0]
+        if not isinstance(lhs, NameExpr) or lhs.name.startswith('_') or lhs.name == 'model_config':
+            return None
+
+        if not stmt.new_syntax:
+            if (
+                isinstance(stmt.rvalue, CallExpr)
+                and isinstance(stmt.rvalue.callee, CallExpr)
+                and isinstance(stmt.rvalue.callee.callee, NameExpr)
+                and stmt.rvalue.callee.callee.fullname in DECORATOR_FULLNAMES
+            ):
+                # This is a (possibly-reused) validator or serializer, not a field
+                # TODO: We may want to inspect whatever replaces keep_untouched in the config
+                # In particular, it looks something like: my_validator = validator('my_field', allow_reuse=True)(f)
+                return None
+
+            # The assignment does not have an annotation, and it's not anything else we recognize
+            error_untyped_fields(ctx.api, stmt)
+            return None
+
+        sym = cls.info.names.get(lhs.name)
+        if sym is None:  # pragma: no cover
+            # This is likely due to a star import (see the dataclasses plugin for a more detailed explanation)
+            # This is the same logic used in the dataclasses plugin
+            return None
+
+        node = sym.node
+        if isinstance(node, PlaceholderNode):  # pragma: no cover
+            # See the PlaceholderNode docstring for more detail about how this can occur
+            # Basically, it is an edge case when dealing with complex import logic
+            # This is the same logic used in the dataclasses plugin
+            return None
+        if not isinstance(node, Var):  # pragma: no cover
+            # Don't know if this edge case still happens with the `is_valid_field` check above
+            # but better safe than sorry
+            return None
+
+        # x: ClassVar[int] is ignored by dataclasses.
+        if node.is_classvar:
+            return None
+
+        is_required = self.get_is_required(cls, stmt, lhs)
+        alias, has_dynamic_alias = self.get_alias_info(stmt)
+        if has_dynamic_alias and not model_config.populate_by_name and self.plugin_config.warn_required_dynamic_aliases:
+            error_required_dynamic_aliases(ctx.api, stmt)
+        return PydanticModelField(
+            name=lhs.name,
+            is_required=is_required,
+            alias=alias,
+            has_dynamic_alias=has_dynamic_alias,
+            line=stmt.line,
+            column=stmt.column,
+        )
+
+    def add_initializer(self, fields: list[PydanticModelField], config: ModelConfigData) -> None:
         """
         Adds a fields-aware `__init__` method to the class.
 
@@ -509,7 +525,7 @@ def add_initializer(self, fields: List['PydanticModelField'], config: 'ModelConf
         if '__init__' not in ctx.cls.info.names:
             add_method(ctx, '__init__', init_arguments, NoneType())
 
-    def add_model_construct_method(self, fields: List['PydanticModelField']) -> None:
+    def add_model_construct_method(self, fields: list[PydanticModelField]) -> None:
         """
         Adds a fully typed `model_construct` classmethod to the class.
 
@@ -541,7 +557,7 @@ def add_model_construct_method(self, fields: List['PydanticModelField']) -> None
             is_classmethod=True,
         )
 
-    def set_frozen(self, fields: List['PydanticModelField'], frozen: bool) -> None:
+    def set_frozen(self, fields: list[PydanticModelField], frozen: bool) -> None:
         """
         Marks all fields as properties so that attempts to set them trigger mypy errors.
 
@@ -574,7 +590,7 @@ def set_frozen(self, fields: List['PydanticModelField'], frozen: bool) -> None:
                 var._fullname = get_fullname(info) + '.' + get_name(var)
                 info.names[get_name(var)] = SymbolTableNode(MDEF, var)
 
-    def get_config_update(self, name: str, arg: Expression) -> Optional['ModelConfigData']:
+    def get_config_update(self, name: str, arg: Expression) -> ModelConfigData | None:
         """
         Determines the config update due to a single kwarg in the ConfigDict definition.
 
@@ -629,7 +645,7 @@ def get_is_required(cls: ClassDef, stmt: AssignmentStmt, lhs: NameExpr) -> bool:
         return isinstance(expr, EllipsisExpr)
 
     @staticmethod
-    def get_alias_info(stmt: AssignmentStmt) -> Tuple[Optional[str], bool]:
+    def get_alias_info(stmt: AssignmentStmt) -> tuple[str | None, bool]:
         """
         Returns a pair (alias, has_dynamic_alias), extracted from the declaration of the field defined in `stmt`.
 
@@ -658,8 +674,8 @@ def get_alias_info(stmt: AssignmentStmt) -> Tuple[Optional[str], bool]:
         return None, False
 
     def get_field_arguments(
-        self, fields: List['PydanticModelField'], typed: bool, force_all_optional: bool, use_alias: bool
-    ) -> List[Argument]:
+        self, fields: list[PydanticModelField], typed: bool, force_all_optional: bool, use_alias: bool
+    ) -> list[Argument]:
         """
         Helper function used during the construction of the `__init__` and `model_construct` method signatures.
 
@@ -673,7 +689,7 @@ def get_field_arguments(
         ]
         return arguments
 
-    def should_init_forbid_extra(self, fields: List['PydanticModelField'], config: 'ModelConfigData') -> bool:
+    def should_init_forbid_extra(self, fields: list[PydanticModelField], config: ModelConfigData) -> bool:
         """
         Indicates whether the generated `__init__` should get a `**kwargs` at the end of its signature
 
@@ -688,7 +704,7 @@ def should_init_forbid_extra(self, fields: List['PydanticModelField'], config: '
         return self.plugin_config.init_forbid_extra
 
     @staticmethod
-    def is_dynamic_alias_present(fields: List['PydanticModelField'], has_alias_generator: bool) -> bool:
+    def is_dynamic_alias_present(fields: list[PydanticModelField], has_alias_generator: bool) -> bool:
         """
         Returns whether any fields on the model have a "dynamic alias", i.e., an alias that cannot be
         determined during static analysis.
@@ -705,7 +721,7 @@ def is_dynamic_alias_present(fields: List['PydanticModelField'], has_alias_gener
 
 class PydanticModelField:
     def __init__(
-        self, name: str, is_required: bool, alias: Optional[str], has_dynamic_alias: bool, line: int, column: int
+        self, name: str, is_required: bool, alias: str | None, has_dynamic_alias: bool, line: int, column: int
     ):
         self.name = name
         self.is_required = is_required
@@ -736,18 +752,18 @@ def serialize(self) -> JsonDict:
         return self.__dict__
 
     @classmethod
-    def deserialize(cls, info: TypeInfo, data: JsonDict) -> 'PydanticModelField':
+    def deserialize(cls, info: TypeInfo, data: JsonDict) -> PydanticModelField:
         return cls(**data)
 
 
 class ModelConfigData:
     def __init__(
         self,
-        forbid_extra: Optional[bool] = None,
-        frozen: Optional[bool] = None,
-        from_attributes: Optional[bool] = None,
-        populate_by_name: Optional[bool] = None,
-        has_alias_generator: Optional[bool] = None,
+        forbid_extra: bool | None = None,
+        frozen: bool | None = None,
+        from_attributes: bool | None = None,
+        populate_by_name: bool | None = None,
+        has_alias_generator: bool | None = None,
     ):
         self.forbid_extra = forbid_extra
         self.frozen = frozen
@@ -755,10 +771,10 @@ def __init__(
         self.populate_by_name = populate_by_name
         self.has_alias_generator = has_alias_generator
 
-    def set_values_dict(self) -> Dict[str, Any]:
+    def set_values_dict(self) -> dict[str, Any]:
         return {k: v for k, v in self.__dict__.items() if v is not None}
 
-    def update(self, config: Optional['ModelConfigData']) -> None:
+    def update(self, config: ModelConfigData | None) -> None:
         if config is None:
             return
         for k, v in config.set_values_dict().items():
@@ -790,7 +806,7 @@ def error_required_dynamic_aliases(api: SemanticAnalyzerPluginInterface, context
 
 
 def error_unexpected_behavior(
-    detail: str, api: Union[CheckerPluginInterface, SemanticAnalyzerPluginInterface], context: Context
+    detail: str, api: CheckerPluginInterface | SemanticAnalyzerPluginInterface, context: Context
 ) -> None:  # pragma: no cover
     # Can't think of a good way to test this, but I confirmed it renders as desired by adding to a non-error path
     link = 'https://github.com/pydantic/pydantic/issues/new/choose'
@@ -810,10 +826,10 @@ def error_default_and_default_factory_specified(api: CheckerPluginInterface, con
 def add_method(
     ctx: ClassDefContext,
     name: str,
-    args: List[Argument],
+    args: list[Argument],
     return_type: Type,
-    self_type: Optional[Type] = None,
-    tvar_def: Optional[TypeVarDef] = None,
+    self_type: Type | None = None,
+    tvar_def: TypeVarDef | None = None,
     is_classmethod: bool = False,
     is_new: bool = False,
     # is_staticmethod: bool = False,
@@ -890,7 +906,7 @@ def add_method(
     info.defn.defs.body.append(func)
 
 
-def get_fullname(x: Union[FuncBase, SymbolNode]) -> str:
+def get_fullname(x: FuncBase | SymbolNode) -> str:
     """
     Used for compatibility with mypy 0.740; can be dropped once support for 0.740 is dropped.
     """
@@ -900,7 +916,7 @@ def get_fullname(x: Union[FuncBase, SymbolNode]) -> str:
     return fn
 
 
-def get_name(x: Union[FuncBase, SymbolNode]) -> str:
+def get_name(x: FuncBase | SymbolNode) -> str:
     """
     Used for compatibility with mypy 0.740; can be dropped once support for 0.740 is dropped.
     """
@@ -910,7 +926,7 @@ def get_name(x: Union[FuncBase, SymbolNode]) -> str:
     return fn
 
 
-def parse_toml(config_file: str) -> Optional[Dict[str, Any]]:
+def parse_toml(config_file: str) -> dict[str, Any] | None:
     if not config_file.endswith('.toml'):
         return None
 


Test patch:
diff --git a/tests/mypy/configs/mypy-plugin-strict-no-any.ini b/tests/mypy/configs/mypy-plugin-strict-no-any.ini
--- a/tests/mypy/configs/mypy-plugin-strict-no-any.ini
+++ b/tests/mypy/configs/mypy-plugin-strict-no-any.ini
@@ -20,7 +20,6 @@ warn_return_any = True
 init_forbid_extra = True
 init_typed = True
 warn_required_dynamic_aliases = True
-warn_untyped_fields = True
 
 [mypy-pydantic_core.*]
 follow_imports = skip
diff --git a/tests/mypy/configs/mypy-plugin-strict.ini b/tests/mypy/configs/mypy-plugin-strict.ini
--- a/tests/mypy/configs/mypy-plugin-strict.ini
+++ b/tests/mypy/configs/mypy-plugin-strict.ini
@@ -14,7 +14,6 @@ disallow_untyped_defs = True
 init_forbid_extra = True
 init_typed = True
 warn_required_dynamic_aliases = True
-warn_untyped_fields = True
 
 [mypy-pydantic_core.*]
 follow_imports = skip
diff --git a/tests/mypy/configs/pyproject-plugin-strict.toml b/tests/mypy/configs/pyproject-plugin-strict.toml
--- a/tests/mypy/configs/pyproject-plugin-strict.toml
+++ b/tests/mypy/configs/pyproject-plugin-strict.toml
@@ -33,7 +33,6 @@ disallow_untyped_defs = true
 init_forbid_extra = true
 init_typed = true
 warn_required_dynamic_aliases = true
-warn_untyped_fields = true
 
 [[tool.mypy.overrides]]
 module = [
diff --git a/tests/mypy/modules/plugin_success.py b/tests/mypy/modules/plugin_success.py
--- a/tests/mypy/modules/plugin_success.py
+++ b/tests/mypy/modules/plugin_success.py
@@ -11,8 +11,6 @@ class Model(BaseModel):
 
     model_config = ConfigDict(from_attributes=True)
 
-    not_config = ConfigDict(frozen=True)
-
 
 class SelfReferencingModel(BaseModel):
     submodel: Optional['SelfReferencingModel']
@@ -36,8 +34,6 @@ class KwargsModel(BaseModel, from_attributes=True):
     x: float
     y: str
 
-    not_config = ConfigDict(frozen=True)
-
 
 kwargs_model = KwargsModel(x=1, y='y')
 KwargsModel(x=1, y='y', z='z')
@@ -74,7 +70,7 @@ class NoMutationModel(BaseModel):
 
 
 class MutationModel(NoMutationModel):
-    a = 1
+    a: int = 1
 
     model_config = ConfigDict(frozen=False, from_attributes=True)
 
@@ -88,7 +84,7 @@ class KwargsNoMutationModel(BaseModel, frozen=True):
 
 
 class KwargsMutationModel(KwargsNoMutationModel, frozen=False, from_attributes=True):
-    a = 1
+    a: int = 1
 
 
 KwargsMutationModel(x=1).x = 2
@@ -260,3 +256,23 @@ def from_orm_optional(cls, model: Optional[_TModel]) -> Optional[_TType]:
         if model is None:
             return None
         return cls.from_orm(model)
+
+
+import sys  # noqa E402
+
+if sys.version_info >= (3, 8):
+    from dataclasses import InitVar  # E402
+
+    InitVarStr = InitVar[str]
+else:
+    # InitVar is not supported in 3.7 due to loss of type information
+    InitVarStr = str
+
+
+@dataclass
+class MyDataClass:
+    foo: InitVarStr
+    bar: str
+
+
+MyDataClass(foo='foo', bar='bar')
diff --git a/tests/mypy/modules/plugin_success_baseConfig.py b/tests/mypy/modules/plugin_success_baseConfig.py
--- a/tests/mypy/modules/plugin_success_baseConfig.py
+++ b/tests/mypy/modules/plugin_success_baseConfig.py
@@ -76,7 +76,7 @@ class NoMutationModel(BaseModel):
 
 
 class MutationModel(NoMutationModel):
-    a = 1
+    a: int = 1
 
     model_config = dict(frozen=False, from_attributes=True)
 
@@ -90,7 +90,7 @@ class KwargsNoMutationModel(BaseModel, frozen=True):
 
 
 class KwargsMutationModel(KwargsNoMutationModel, frozen=False, from_attributes=True):
-    a = 1
+    a: int = 1
 
 
 KwargsMutationModel(x=1).x = 2
diff --git a/tests/mypy/outputs/latest/plugin-fail-baseConfig.txt b/tests/mypy/outputs/latest/plugin-fail-baseConfig.txt
--- a/tests/mypy/outputs/latest/plugin-fail-baseConfig.txt
+++ b/tests/mypy/outputs/latest/plugin-fail-baseConfig.txt
@@ -15,12 +15,13 @@
 82: error: Invalid value for "Config.from_attributes"  [pydantic-config]
 85: error: Invalid value for "Config.from_attributes"  [pydantic-config]
 101: error: Incompatible types in assignment (expression has type "ellipsis", variable has type "int")  [assignment]
+104: error: Untyped fields disallowed  [pydantic-field]
 110: error: Incompatible types in assignment (expression has type "None", variable has type "int")  [assignment]
+111: error: Untyped fields disallowed  [pydantic-field]
 114: error: Missing named argument "a" for "DefaultTestingModel"  [call-arg]
 114: error: Missing named argument "b" for "DefaultTestingModel"  [call-arg]
 114: error: Missing named argument "c" for "DefaultTestingModel"  [call-arg]
 114: error: Missing named argument "d" for "DefaultTestingModel"  [call-arg]
-114: error: Missing named argument "e" for "DefaultTestingModel"  [call-arg]
 118: error: Name "Undefined" is not defined  [name-defined]
 121: error: Missing named argument "undefined" for "UndefinedAnnotationModel"  [call-arg]
 124: error: Missing named argument "y" for "model_construct" of "Model"  [call-arg]
@@ -28,7 +29,7 @@
 176: error: Missing named argument "x" for "DynamicAliasModel2"  [call-arg]
 185: error: Missing named argument "x" for "KwargsDynamicAliasModel"  [call-arg]
 204: error: Unused "type: ignore" comment
-211: error: Unused "type: ignore" comment
+210: error: Untyped fields disallowed  [pydantic-field]
 235: error: Name "Missing" is not defined  [name-defined]
 265: error: Property "y" defined in "FrozenModel" is read-only  [misc]
 286: error: Incompatible types in assignment (expression has type "None", variable has type "int")  [assignment]
diff --git a/tests/mypy/outputs/latest/plugin-fail-strict-baseConfig.txt b/tests/mypy/outputs/latest/plugin-fail-strict-baseConfig.txt
--- a/tests/mypy/outputs/latest/plugin-fail-strict-baseConfig.txt
+++ b/tests/mypy/outputs/latest/plugin-fail-strict-baseConfig.txt
@@ -22,7 +22,6 @@
 114: error: Missing named argument "b" for "DefaultTestingModel"  [call-arg]
 114: error: Missing named argument "c" for "DefaultTestingModel"  [call-arg]
 114: error: Missing named argument "d" for "DefaultTestingModel"  [call-arg]
-114: error: Missing named argument "e" for "DefaultTestingModel"  [call-arg]
 118: error: Name "Undefined" is not defined  [name-defined]
 121: error: Missing named argument "undefined" for "UndefinedAnnotationModel"  [call-arg]
 124: error: Missing named argument "y" for "model_construct" of "Model"  [call-arg]
diff --git a/tests/mypy/outputs/latest/plugin-fail-strict.txt b/tests/mypy/outputs/latest/plugin-fail-strict.txt
--- a/tests/mypy/outputs/latest/plugin-fail-strict.txt
+++ b/tests/mypy/outputs/latest/plugin-fail-strict.txt
@@ -25,7 +25,6 @@
 105: error: Missing named argument "b" for "DefaultTestingModel"  [call-arg]
 105: error: Missing named argument "c" for "DefaultTestingModel"  [call-arg]
 105: error: Missing named argument "d" for "DefaultTestingModel"  [call-arg]
-105: error: Missing named argument "e" for "DefaultTestingModel"  [call-arg]
 109: error: Name "Undefined" is not defined  [name-defined]
 112: error: Missing named argument "undefined" for "UndefinedAnnotationModel"  [call-arg]
 115: error: Missing named argument "y" for "model_construct" of "Model"  [call-arg]
diff --git a/tests/mypy/outputs/latest/plugin-fail.txt b/tests/mypy/outputs/latest/plugin-fail.txt
--- a/tests/mypy/outputs/latest/plugin-fail.txt
+++ b/tests/mypy/outputs/latest/plugin-fail.txt
@@ -18,12 +18,13 @@
 74: note: Error code "pydantic-config" not covered by "type: ignore" comment
 77: error: Invalid value for "Config.from_attributes"  [pydantic-config]
 92: error: Incompatible types in assignment (expression has type "ellipsis", variable has type "int")  [assignment]
+95: error: Untyped fields disallowed  [pydantic-field]
 101: error: Incompatible types in assignment (expression has type "None", variable has type "int")  [assignment]
+102: error: Untyped fields disallowed  [pydantic-field]
 105: error: Missing named argument "a" for "DefaultTestingModel"  [call-arg]
 105: error: Missing named argument "b" for "DefaultTestingModel"  [call-arg]
 105: error: Missing named argument "c" for "DefaultTestingModel"  [call-arg]
 105: error: Missing named argument "d" for "DefaultTestingModel"  [call-arg]
-105: error: Missing named argument "e" for "DefaultTestingModel"  [call-arg]
 109: error: Name "Undefined" is not defined  [name-defined]
 112: error: Missing named argument "undefined" for "UndefinedAnnotationModel"  [call-arg]
 115: error: Missing named argument "y" for "model_construct" of "Model"  [call-arg]
@@ -31,7 +32,7 @@
 166: error: Missing named argument "x" for "DynamicAliasModel2"  [call-arg]
 175: error: Missing named argument "x" for "KwargsDynamicAliasModel"  [call-arg]
 193: error: Unused "type: ignore" comment
-199: error: Unused "type: ignore" comment
+198: error: Untyped fields disallowed  [pydantic-field]
 223: error: Name "Missing" is not defined  [name-defined]
 250: error: Property "y" defined in "FrozenModel" is read-only  [misc]
 270: error: Incompatible types in assignment (expression has type "None", variable has type "int")  [assignment]
diff --git a/tests/mypy/outputs/latest/plugin-success-strict-baseConfig.txt b/tests/mypy/outputs/latest/plugin-success-strict-baseConfig.txt
--- a/tests/mypy/outputs/latest/plugin-success-strict-baseConfig.txt
+++ b/tests/mypy/outputs/latest/plugin-success-strict-baseConfig.txt
@@ -1,5 +1,2 @@
 29: error: Unexpected keyword argument "z" for "Model"  [call-arg]
 45: error: Unexpected keyword argument "z" for "KwargsModel"  [call-arg]
-79: error: Untyped fields disallowed  [pydantic-field]
-93: error: Untyped fields disallowed  [pydantic-field]
-203: error: Untyped fields disallowed  [pydantic-field]
diff --git a/tests/mypy/outputs/latest/plugin-success-strict.txt b/tests/mypy/outputs/latest/plugin-success-strict.txt
--- a/tests/mypy/outputs/latest/plugin-success-strict.txt
+++ b/tests/mypy/outputs/latest/plugin-success-strict.txt
@@ -1,7 +1,2 @@
-14: error: Untyped fields disallowed  [pydantic-field]
-28: error: Unexpected keyword argument "z" for "Model"  [call-arg]
-39: error: Untyped fields disallowed  [pydantic-field]
-43: error: Unexpected keyword argument "z" for "KwargsModel"  [call-arg]
-77: error: Untyped fields disallowed  [pydantic-field]
-91: error: Untyped fields disallowed  [pydantic-field]
-201: error: Untyped fields disallowed  [pydantic-field]
+26: error: Unexpected keyword argument "z" for "Model"  [call-arg]
+39: error: Unexpected keyword argument "z" for "KwargsModel"  [call-arg]
diff --git a/tests/mypy/outputs/latest/plugin_success.txt b/tests/mypy/outputs/latest/plugin_success.txt
--- a/tests/mypy/outputs/latest/plugin_success.txt
+++ b/tests/mypy/outputs/latest/plugin_success.txt
@@ -1,6 +1,6 @@
-28: error: Unexpected keyword argument "z" for "Model"  [call-arg]
-43: error: Unexpected keyword argument "z" for "KwargsModel"  [call-arg]
-86: error: Cannot inherit frozen dataclass from a non-frozen one  [misc]
-90: error: Cannot inherit non-frozen dataclass from a frozen one  [misc]
-94: error: Property "x" defined in "KwargsNoMutationModel" is read-only  [misc]
-179: error: Cannot inherit frozen dataclass from a non-frozen one  [misc]
+26: error: Unexpected keyword argument "z" for "Model"  [call-arg]
+39: error: Unexpected keyword argument "z" for "KwargsModel"  [call-arg]
+82: error: Cannot inherit frozen dataclass from a non-frozen one  [misc]
+86: error: Cannot inherit non-frozen dataclass from a frozen one  [misc]
+90: error: Property "x" defined in "KwargsNoMutationModel" is read-only  [misc]
+175: error: Cannot inherit frozen dataclass from a non-frozen one  [misc]
diff --git a/tests/mypy/outputs/v1.0.1/plugin_success.txt b/tests/mypy/outputs/v1.0.1/plugin_success.txt
--- a/tests/mypy/outputs/v1.0.1/plugin_success.txt
+++ b/tests/mypy/outputs/v1.0.1/plugin_success.txt
@@ -1,3 +1,5 @@
-140: error: Unexpected keyword argument "name" for "AddProject"  [call-arg]
-140: error: Unexpected keyword argument "slug" for "AddProject"  [call-arg]
-140: error: Unexpected keyword argument "description" for "AddProject"  [call-arg]
+136: error: Unexpected keyword argument "name" for "AddProject"  [call-arg]
+136: error: Unexpected keyword argument "slug" for "AddProject"  [call-arg]
+136: error: Unexpected keyword argument "description" for "AddProject"  [call-arg]
+278: error: Unexpected keyword argument "foo" for "MyDataClass"  [call-arg]
+278: error: Unexpected keyword argument "bar" for "MyDataClass"  [call-arg]