diff --git a/changes/4343-detachhead.md b/changes/4343-detachhead.md new file mode 100644 index 0000000000..8a9f424f48 --- /dev/null +++ b/changes/4343-detachhead.md @@ -0,0 +1 @@ +fix "extra fields not permitted" error when dataclass with `Extra.forbid` is validated multiple times \ No newline at end of file diff --git a/pydantic/dataclasses.py b/pydantic/dataclasses.py index 1ce738bde5..f60f04b239 100644 --- a/pydantic/dataclasses.py +++ b/pydantic/dataclasses.py @@ -386,6 +386,10 @@ def create_pydantic_model_from_dataclass( def _dataclass_validate_values(self: 'Dataclass') -> None: + # validation errors can occur if this function is called twice on an already initialised dataclass. + # for example if Extra.forbid is enabled, it would consider __pydantic_initialised__ an invalid extra property + if getattr(self, '__pydantic_initialised__'): + return if getattr(self, '__pydantic_has_field_info_default__', False): # We need to remove `FieldInfo` values since they are not valid as input # It's ok to do that because they are obviously the default values! diff --git a/tests/test_dataclasses.py b/tests/test_dataclasses.py index 93b6886ff9..f29bdfc3c8 100644 --- a/tests/test_dataclasses.py +++ b/tests/test_dataclasses.py @@ -1371,3 +1371,27 @@ class A: A(1, '') assert A(b='hi').b == 'hi' + + +def test_extra_forbid_list_no_error(): + @pydantic.dataclasses.dataclass(config=dict(extra=Extra.forbid)) + class Bar: + ... + + @pydantic.dataclasses.dataclass + class Foo: + a: List[Bar] + + assert isinstance(Foo(a=[Bar()]).a[0], Bar) + + +def test_extra_forbid_list_error(): + @pydantic.dataclasses.dataclass(config=dict(extra=Extra.forbid)) + class Bar: + ... + + with pytest.raises(TypeError, match=re.escape("__init__() got an unexpected keyword argument 'a'")): + + @pydantic.dataclasses.dataclass + class Foo: + a: List[Bar(a=1)]