diff --git a/pydantic/main.py b/pydantic/main.py index 7e13e173357..1e87497d50e 100644 --- a/pydantic/main.py +++ b/pydantic/main.py @@ -313,7 +313,7 @@ def __new__(mcs, name, bases, namespace, **kwargs): # noqa C901 '__schema_cache__': {}, '__json_encoder__': staticmethod(json_encoder), '__custom_root_type__': _custom_root_type, - '__hash__': (lambda self: hash(self.__dict__.values())) if not config.allow_mutation else None, + '__hash__': (lambda self: hash(tuple(self.__dict__.values()))) if not config.allow_mutation else None, **{n: v for n, v in namespace.items() if n not in fields}, } diff --git a/tests/test_main.py b/tests/test_main.py index 9253bbede55..35421a2f254 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -386,7 +386,7 @@ class Config: assert '"TestModel" object has no field "b"' in exc_info.value.args[0] -def test_immutable_are_hashable(): +def test_immutable_with_hashable_fields_are_hashable(): class TestModel(BaseModel): a: int = 10 @@ -398,6 +398,20 @@ class Config: assert isinstance(hash(m), int) +def test_immutable_with_unhashable_fields_are_not_hashable(): + class TestModel(BaseModel): + a: int = 10 + y: List[int] = [1, 2, 3] + + class Config: + allow_mutation = False + + m = TestModel() + with pytest.raises(TypeError) as exc_info: + hash(m) + assert "unhashable type: 'list'" in exc_info.value.args[0] + + def test_const_validates(): class Model(BaseModel): a: int = Field(3, const=True)