From 06f7de3a37706df5880137e4253e8373dc49ff8c Mon Sep 17 00:00:00 2001 From: detachhead Date: Tue, 9 Aug 2022 10:37:40 +1000 Subject: [PATCH] fix "extra fields not permitted" error when dataclass with `Extra.forbid` is validated multiple times --- changes/4343-detachhead.md | 1 + pydantic/dataclasses.py | 4 ++++ tests/test_dataclasses.py | 24 ++++++++++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 changes/4343-detachhead.md 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 1a9008cc6c..36529a88fa 100644 --- a/pydantic/dataclasses.py +++ b/pydantic/dataclasses.py @@ -385,6 +385,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 f74b087485..ff300afa0d 100644 --- a/tests/test_dataclasses.py +++ b/tests/test_dataclasses.py @@ -1360,3 +1360,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)]