Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: dataclass wrapper was not always called #4484

Merged
merged 1 commit into from Sep 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/4477-PrettyWood.md
@@ -0,0 +1 @@
fix: dataclass wrapper was not always called
25 changes: 23 additions & 2 deletions pydantic/dataclasses.py
Expand Up @@ -34,7 +34,20 @@ class M:
import sys
from contextlib import contextmanager
from functools import wraps
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Generator, Optional, Type, TypeVar, Union, overload
from typing import (
TYPE_CHECKING,
Any,
Callable,
ClassVar,
Dict,
Generator,
Optional,
Set,
Type,
TypeVar,
Union,
overload,
)

from typing_extensions import dataclass_transform

Expand Down Expand Up @@ -184,7 +197,7 @@ def dataclass(
def wrap(cls: Type[Any]) -> 'DataclassClassOrWrapper':
import dataclasses

if is_builtin_dataclass(cls):
if is_builtin_dataclass(cls) and _extra_dc_args(_cls) == _extra_dc_args(_cls.__bases__[0]): # type: ignore
dc_cls_doc = ''
dc_cls = DataclassProxy(cls)
default_validate_on_init = False
Expand Down Expand Up @@ -418,6 +431,14 @@ def _dataclass_validate_assignment_setattr(self: 'Dataclass', name: str, value:
object.__setattr__(self, name, value)


def _extra_dc_args(cls: Type[Any]) -> Set[str]:
return {
x
for x in dir(cls)
if x not in getattr(cls, '__dataclass_fields__', {}) and not (x.startswith('__') and x.endswith('__'))
}


def is_builtin_dataclass(_cls: Type[Any]) -> bool:
"""
Whether a class is a stdlib dataclass
Expand Down
77 changes: 77 additions & 0 deletions tests/test_dataclasses.py
Expand Up @@ -1395,3 +1395,80 @@ class Bar:
@pydantic.dataclasses.dataclass
class Foo:
a: List[Bar(a=1)]


def test_parent_post_init():
@dataclasses.dataclass
class A:
a: float = 1

def __post_init__(self):
self.a *= 2

@pydantic.dataclasses.dataclass
class B(A):
@validator('a')
def validate_a(cls, value):
value += 3
return value

assert B().a == 5 # 1 * 2 + 3


def test_subclass_post_init_post_parse():
@dataclasses.dataclass
class A:
a: float = 1

@pydantic.dataclasses.dataclass
class B(A):
def __post_init_post_parse__(self):
self.a *= 2

@validator('a')
def validate_a(cls, value):
value += 3
return value

assert B().a == 8 # (1 + 3) * 2


def test_subclass_post_init():
@dataclasses.dataclass
class A:
a: int = 1

@pydantic.dataclasses.dataclass
class B(A):
def __post_init__(self):
self.a *= 2

@validator('a')
def validate_a(cls, value):
value += 3
return value

assert B().a == 5 # 1 * 2 + 3


def test_subclass_post_init_inheritance():
@dataclasses.dataclass
class A:
a: int = 1

@pydantic.dataclasses.dataclass
class B(A):
def __post_init__(self):
self.a *= 2

@validator('a')
def validate_a(cls, value):
value += 3
return value

@pydantic.dataclasses.dataclass
class C(B):
def __post_init__(self):
self.a *= 3

assert C().a == 6 # 1 * 3 + 3