Repository: pydantic/pydantic

Issue:
"none is not an allowed value" for Hashable field
Although `None` is `Hashable`, it fails to validate below. Even stranger, it still fails with the same error if the field is explicitly annotated as `Optional[Hashable]`

```py
from collections.abc import Hashable
from typing import Optional
from pydantic.dataclasses import dataclass


class Config:
    arbitrary_types_allowed = True

@dataclass(config=Config)
class Model:
    v: Hashable
    # v: Optional[Hashable]

assert isinstance(None, Hashable)

Model(None)

# output:
#
#pydantic.error_wrappers.ValidationError: 1 validation error for Model
#v
#  none is not an allowed value (type=type_error.none.not_allowed)
```
Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:

```
pydantic version: 1.4
pydantic compiled: True
python version: 3.6.9 (default, Nov  7 2019, 10:44:02)  [GCC 8.3.0]
platform: Linux-4.15.0-76-generic-x86_64-with-Ubuntu-18.04-bionic
optional deps. installed: ['typing-extensions']
```



Discussion:

Resolving patch:
diff --git a/pydantic/errors.py b/pydantic/errors.py
--- a/pydantic/errors.py
+++ b/pydantic/errors.py
@@ -61,6 +61,7 @@
     'DateError',
     'TimeError',
     'DurationError',
+    'HashableError',
     'UUIDError',
     'UUIDVersionError',
     'ArbitraryTypeError',
@@ -392,6 +393,10 @@ class DurationError(PydanticValueError):
     msg_template = 'invalid duration format'
 
 
+class HashableError(PydanticTypeError):
+    msg_template = 'value is not a valid hashable'
+
+
 class UUIDError(PydanticTypeError):
     msg_template = 'value is not a valid uuid'
 
diff --git a/pydantic/fields.py b/pydantic/fields.py
--- a/pydantic/fields.py
+++ b/pydantic/fields.py
@@ -401,6 +401,9 @@ def _type_analysis(self) -> None:  # noqa: C901 (ignore complexity)
         origin = getattr(self.type_, '__origin__', None)
         if origin is None:
             # field is not "typing" object eg. Union, Dict, List etc.
+            # allow None for virtual superclasses of NoneType, e.g. Hashable
+            if isinstance(self.type_, type) and isinstance(None, self.type_):
+                self.allow_none = True
             return
         if origin is Callable:
             return
diff --git a/pydantic/validators.py b/pydantic/validators.py
--- a/pydantic/validators.py
+++ b/pydantic/validators.py
@@ -1,6 +1,7 @@
 import re
 import sys
 from collections import OrderedDict
+from collections.abc import Hashable
 from datetime import date, datetime, time, timedelta
 from decimal import Decimal, DecimalException
 from enum import Enum, IntEnum
@@ -284,6 +285,13 @@ def decimal_validator(v: Any) -> Decimal:
     return v
 
 
+def hashable_validator(v: Any) -> Hashable:
+    if isinstance(v, Hashable):
+        return v
+
+    raise errors.HashableError()
+
+
 def ip_v4_address_validator(v: Any) -> IPv4Address:
     if isinstance(v, IPv4Address):
         return v
@@ -539,6 +547,9 @@ def find_validators(  # noqa: C901 (ignore complexity)
     if type_ is Pattern:
         yield pattern_validator
         return
+    if type_ is Hashable:
+        yield hashable_validator
+        return
     if is_callable_type(type_):
         yield callable_validator
         return


Test patch:
diff --git a/tests/test_dataclasses.py b/tests/test_dataclasses.py
--- a/tests/test_dataclasses.py
+++ b/tests/test_dataclasses.py
@@ -1,4 +1,5 @@
 import dataclasses
+from collections.abc import Hashable
 from datetime import datetime
 from pathlib import Path
 from typing import ClassVar, Dict, FrozenSet, Optional
@@ -578,3 +579,29 @@ class Child(Base):
 
     Child(a=1, b=2)
     assert post_init_called
+
+
+def test_hashable_required():
+    @pydantic.dataclasses.dataclass
+    class MyDataclass:
+        v: Hashable
+
+    MyDataclass(v=None)
+    with pytest.raises(ValidationError) as exc_info:
+        MyDataclass(v=[])
+    assert exc_info.value.errors() == [
+        {'loc': ('v',), 'msg': 'value is not a valid hashable', 'type': 'type_error.hashable'}
+    ]
+    with pytest.raises(TypeError) as exc_info:
+        MyDataclass()
+    assert str(exc_info.value) == "__init__() missing 1 required positional argument: 'v'"
+
+
+@pytest.mark.parametrize('default', [1, None, ...])
+def test_hashable_optional(default):
+    @pydantic.dataclasses.dataclass
+    class MyDataclass:
+        v: Hashable = default
+
+    MyDataclass()
+    MyDataclass(v=None)
diff --git a/tests/test_edge_cases.py b/tests/test_edge_cases.py
--- a/tests/test_edge_cases.py
+++ b/tests/test_edge_cases.py
@@ -1,4 +1,5 @@
 import sys
+from collections.abc import Hashable
 from decimal import Decimal
 from enum import Enum
 from typing import Any, Dict, FrozenSet, Generic, List, Optional, Set, Tuple, Type, TypeVar, Union
@@ -1478,3 +1479,27 @@ def __init__(self, t1: T1, t2: T2):
         class Model(BaseModel):
             a: str
             gen: MyGen[str, bool]
+
+
+def test_hashable_required():
+    class Model(BaseModel):
+        v: Hashable
+
+    Model(v=None)
+    with pytest.raises(ValidationError) as exc_info:
+        Model(v=[])
+    assert exc_info.value.errors() == [
+        {'loc': ('v',), 'msg': 'value is not a valid hashable', 'type': 'type_error.hashable'}
+    ]
+    with pytest.raises(ValidationError) as exc_info:
+        Model()
+    assert exc_info.value.errors() == [{'loc': ('v',), 'msg': 'field required', 'type': 'value_error.missing'}]
+
+
+@pytest.mark.parametrize('default', [1, None])
+def test_hashable_optional(default):
+    class Model(BaseModel):
+        v: Hashable = default
+
+    Model(v=None)
+    Model()