Repository: pydantic/pydantic

Issue:
Call repr on model with class type field will cause exception
I define a model with class type field. It will raise exception when calling repr on this model.

env:
python version: ``3.6.4``
pydantic version: ``0.28``

code:
```py
import inspect
from pydantic import BaseSettings

class TestClass(object):
    pass


class TestModel(object):
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        if not (inspect.isclass(v) and issubclass(v, TestClass)):
            raise ValueError(f'TestClass expected not {type(v)}')
        return v

class TestSettings(BaseSettings):
    cls: TestModel = None

# this line will raise exception
print(TestSettings(cls=TestClass))
```

exception：
```
Traceback (most recent call last):
  File "test.py", line 23, in <module>
    print(TestSettings(cls=TestClass))
  File "pydantic/main.py", line 534, in pydantic.main.BaseModel.__str__
  File "pydantic/main.py", line 530, in genexpr
  File "pydantic/main.py", line 530, in genexpr
  File "pydantic/utils.py", line 158, in pydantic.utils.truncate
TypeError: descriptor '__repr__' of 'object' object needs an argument
```

I think the problem is the class object  ``__repr__`` property is not callable. [pydantic/utils.py :158](https://github.com/samuelcolvin/pydantic/blob/dd44fda8a6f6eed961cd03ad1e70049e523cdb40/pydantic/utils.py#L158)

```
def truncate(v: Union[str], *, max_len: int = 80) -> str:
    """
    Truncate a value and add a unicode ellipsis (three dots) to the end if it was too long
    """
    if isinstance(v, str) and len(v) > (max_len - 2):
        # -3 so quote + string + … + quote has correct length
        return (v[: (max_len - 3)] + '…').__repr__()
    v = v.__repr__()
    if len(v) > max_len:
        v = v[: max_len - 1] + '…'
    return v
```

Call repr on model with class type field will cause exception
I define a model with class type field. It will raise exception when calling repr on this model.

env:
python version: ``3.6.4``
pydantic version: ``0.28``

code:
```py
import inspect
from pydantic import BaseSettings

class TestClass(object):
    pass


class TestModel(object):
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        if not (inspect.isclass(v) and issubclass(v, TestClass)):
            raise ValueError(f'TestClass expected not {type(v)}')
        return v

class TestSettings(BaseSettings):
    cls: TestModel = None

# this line will raise exception
print(TestSettings(cls=TestClass))
```

exception：
```
Traceback (most recent call last):
  File "test.py", line 23, in <module>
    print(TestSettings(cls=TestClass))
  File "pydantic/main.py", line 534, in pydantic.main.BaseModel.__str__
  File "pydantic/main.py", line 530, in genexpr
  File "pydantic/main.py", line 530, in genexpr
  File "pydantic/utils.py", line 158, in pydantic.utils.truncate
TypeError: descriptor '__repr__' of 'object' object needs an argument
```

I think the problem is the class object  ``__repr__`` property is not callable. [pydantic/utils.py :158](https://github.com/samuelcolvin/pydantic/blob/dd44fda8a6f6eed961cd03ad1e70049e523cdb40/pydantic/utils.py#L158)

```
def truncate(v: Union[str], *, max_len: int = 80) -> str:
    """
    Truncate a value and add a unicode ellipsis (three dots) to the end if it was too long
    """
    if isinstance(v, str) and len(v) > (max_len - 2):
        # -3 so quote + string + … + quote has correct length
        return (v[: (max_len - 3)] + '…').__repr__()
    v = v.__repr__()
    if len(v) > max_len:
        v = v[: max_len - 1] + '…'
    return v
```



Discussion:

Resolving patch:
diff --git a/pydantic/utils.py b/pydantic/utils.py
--- a/pydantic/utils.py
+++ b/pydantic/utils.py
@@ -160,7 +160,10 @@ def truncate(v: Union[str], *, max_len: int = 80) -> str:
     if isinstance(v, str) and len(v) > (max_len - 2):
         # -3 so quote + string + … + quote has correct length
         return (v[: (max_len - 3)] + '…').__repr__()
-    v = v.__repr__()
+    try:
+        v = v.__repr__()
+    except TypeError:
+        v = type(v).__repr__(v)  # in case v is a type
     if len(v) > max_len:
         v = v[: max_len - 1] + '…'
     return v


Test patch:
diff --git a/tests/test_utils.py b/tests/test_utils.py
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -4,7 +4,7 @@
 
 import pytest
 
-from pydantic.utils import display_as_type, import_string, lenient_issubclass, make_dsn, validate_email
+from pydantic.utils import display_as_type, import_string, lenient_issubclass, make_dsn, truncate, validate_email
 
 try:
     import email_validator
@@ -146,3 +146,7 @@ class A(str):
 
 def test_lenient_issubclass_is_lenient():
     assert lenient_issubclass('a', 'a') is False
+
+
+def test_truncate_type():
+    assert truncate(object) == "<class 'object'>"