Repository: pydantic/pydantic

Issue:
Mypy plugin nags about "Missing named argument __config__" on BaseSettings.construct()
### Checks

* [X] I added a descriptive title to this issue
* [X] I have searched (google, github) for similar issues and couldn't find anything
* [X] I have read and followed [the docs](https://pydantic-docs.helpmanual.io/) and still think this is a bug

# Bug

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.8.1
            pydantic compiled: True
                 install path: /home/musttu/.pyenv/versions/3.9.4/envs/py39/lib/python3.9/site-packages/pydantic
               python version: 3.9.4 (default, May  3 2021, 13:52:18)  [GCC 9.3.0]
                     platform: Linux-5.8.0-50-generic-x86_64-with-glibc2.31
     optional deps. installed: ['typing-extensions']
```

With `mypy.ini`:

```ini
[mypy]
plugins = pydantic.mypy
```

```py
import pydantic

class Foo(pydantic.BaseSettings):
    pass

Foo.construct()
```

```
$ mypy models.py
models.py:6: error: Missing named argument "__config__" for "construct" of "Foo"
Found 1 error in 1 file (checked 1 source file)
```

Only occurs if pydntic's mypy plugin is enabled. Why is that?


Discussion:

Resolving patch:
diff --git a/pydantic/env_settings.py b/pydantic/env_settings.py
--- a/pydantic/env_settings.py
+++ b/pydantic/env_settings.py
@@ -1,7 +1,7 @@
 import os
 import warnings
 from pathlib import Path
-from typing import AbstractSet, Any, Callable, Dict, List, Mapping, Optional, Tuple, Union
+from typing import AbstractSet, Any, Callable, ClassVar, Dict, List, Mapping, Optional, Tuple, Type, Union
 
 from .config import BaseConfig, Extra
 from .fields import ModelField
@@ -114,7 +114,7 @@ def customise_sources(
         ) -> Tuple[SettingsSourceCallable, ...]:
             return init_settings, env_settings, file_secret_settings
 
-    __config__: Config  # type: ignore
+    __config__: ClassVar[Type[Config]]  # type: ignore
 
 
 class InitSettingsSource:
@@ -170,7 +170,7 @@ def __call__(self, settings: BaseSettings) -> Dict[str, Any]:
 
             if field.is_complex():
                 try:
-                    env_val = settings.__config__.json_loads(env_val)  # type: ignore
+                    env_val = settings.__config__.json_loads(env_val)
                 except ValueError as e:
                     raise SettingsError(f'error parsing JSON for "{env_name}"') from e
             elif (
@@ -179,7 +179,7 @@ def __call__(self, settings: BaseSettings) -> Dict[str, Any]:
                 and any(f.is_complex() for f in field.sub_fields)
             ):
                 try:
-                    env_val = settings.__config__.json_loads(env_val)  # type: ignore
+                    env_val = settings.__config__.json_loads(env_val)
                 except ValueError:
                     pass
             d[field.alias] = env_val


Test patch:
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
@@ -1,6 +1,6 @@
 from typing import ClassVar, Optional, Union
 
-from pydantic import BaseModel, Field, create_model
+from pydantic import BaseModel, BaseSettings, Field, create_model
 from pydantic.dataclasses import dataclass
 
 
@@ -162,3 +162,10 @@ class Config:
 
 class ModelWithSelfField(BaseModel):
     self: str
+
+
+class SettingsModel(BaseSettings):
+    pass
+
+
+settings = SettingsModel.construct()