Repository: pydantic/pydantic

Issue:
Mypy complains about PyObject
# Question

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.4
            pydantic compiled: False
                 install path: /Users/slafs/.pyenv/versions/3.8.1/envs/tapper-core-py38/lib/python3.8/site-packages/pydantic
               python version: 3.8.1 (default, Feb 11 2020, 12:59:26)  [Clang 10.0.1 (clang-1001.0.46.4)]
                     platform: macOS-10.15.4-x86_64-i386-64bit
     optional deps. installed: ['typing-extensions']
```

I was wondering how can I get mypy to validate the following snippet and at the same time get the fantastic feature of `PyObject` in my `BaseSettings` class.

```py
from datetime import date

from pydantic import BaseSettings, PyObject


class MyConf(BaseSettings):
    str_pyobject: PyObject = 'datetime.date'
    callable_pyobject: PyObject = date


conf = MyConf()

var1: date = conf.str_pyobject(2020, 12, 20)
var2: date = conf.callable_pyobject(2111, 1, 1)

print(var1, var2)
```

I've configured the pydantic mypy pluging the way described in https://pydantic-docs.helpmanual.io/mypy_plugin/.

But mypy complains with:
```
pyobject_fiddle.py:6: error: Incompatible types in assignment (expression has type "str", variable has type "PyObject")
pyobject_fiddle.py:7: error: Incompatible types in assignment (expression has type "Type[date]", variable has type "PyObject")
pyobject_fiddle.py:12: error: "PyObject" not callable
pyobject_fiddle.py:13: error: "PyObject" not callable
Found 4 errors in 1 file (checked 1 source file)
```

I tried to fix the errors by subclassing PyObject and creating my own custom type like this:
```py
class MyPyObj(PyObject):

    def __call__(self, *args: Any, **kwargs: Any) -> Any:
        pass

MyPyObjType = Union[MyPyObj, str, Callable[..., Any]]
```

which almost works, but then I get errors about the var1 and var2 assignements:
```
pyobject_fiddle.py:21: error: "str" not callable
pyobject_fiddle.py:22: error: "str" not callable
```

So, I'm not sure what would be the best approach/fix here? BTW is this a pydantic "bug" in any way?



Discussion:
Thanks for reporting, and sorry for the slow reply.

I'd welcome a PR to "fix" this by adding the above `__call__` method and making sure it doesn't break again by adding this example to mypy tests.
Is this an easy fix for a first time contributor? If so I like to volunteer 👋

Resolving patch:
diff --git a/pydantic/types.py b/pydantic/types.py
--- a/pydantic/types.py
+++ b/pydantic/types.py
@@ -317,6 +317,11 @@ def validate(cls, value: Any) -> Any:
         except ImportError as e:
             raise errors.PyObjectError(error_message=str(e))
 
+    if TYPE_CHECKING:
+
+        def __call__(self, *args: Any, **kwargs: Any) -> Any:
+            ...
+
 
 class ConstrainedNumberMeta(type):
     def __new__(cls, name: str, bases: Any, dct: Dict[str, Any]) -> 'ConstrainedInt':  # type: ignore


Test patch:
diff --git a/tests/mypy/modules/success.py b/tests/mypy/modules/success.py
--- a/tests/mypy/modules/success.py
+++ b/tests/mypy/modules/success.py
@@ -5,10 +5,10 @@
 """
 import json
 import sys
-from datetime import datetime
+from datetime import date, datetime
 from typing import Any, Dict, Generic, List, Optional, TypeVar
 
-from pydantic import BaseModel, NoneStr, StrictBool, root_validator, validate_arguments, validator
+from pydantic import BaseModel, NoneStr, PyObject, StrictBool, root_validator, validate_arguments, validator
 from pydantic.fields import Field
 from pydantic.generics import GenericModel
 
@@ -127,3 +127,13 @@ def foo(a: int, *, c: str = 'x') -> str:
 
 foo(1, c='thing')
 foo(1)
+
+
+class MyConf(BaseModel):
+    str_pyobject: PyObject = Field('datetime.date')
+    callable_pyobject: PyObject = Field(date)
+
+
+conf = MyConf()
+var1: date = conf.str_pyobject(2020, 12, 20)
+var2: date = conf.callable_pyobject(2111, 1, 1)