Skip to content

Commit

Permalink
fix: always call __post_init__ when set in dataclasses
Browse files Browse the repository at this point in the history
  • Loading branch information
PrettyWood committed Sep 5, 2022
1 parent 11903e3 commit f3644f0
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 3 deletions.
20 changes: 17 additions & 3 deletions pydantic/dataclasses.py
Expand Up @@ -256,7 +256,6 @@ def _add_pydantic_validation_attributes( # noqa: C901 (ignore complexity)
"""
init = dc_cls.__init__

@wraps(init)
def handle_extra_init(self: 'Dataclass', *args: Any, **kwargs: Any) -> None:
if config.extra == Extra.ignore:
init(self, *args, **{k: v for k, v in kwargs.items() if k in self.__dataclass_fields__})
Expand Down Expand Up @@ -285,8 +284,23 @@ def new_post_init(self: 'Dataclass', *args: Any, **kwargs: Any) -> None:
if config.post_init_call == 'after_validation':
post_init(self, *args, **kwargs)

setattr(dc_cls, '__init__', handle_extra_init)
setattr(dc_cls, '__post_init__', new_post_init)
if is_builtin_dataclass(dc_cls.__bases__[0]) and not hasattr(dc_cls.__bases__[0], '__post_init__'):
# `__post_init__` won't be called so we need to call it manually
@wraps(init)
def new_init(self: 'Dataclass', *args: Any, **kwargs: Any) -> None:
handle_extra_init(self, *args, **kwargs)
new_post_init(self, *args, **kwargs)

setattr(dc_cls, '__init__', new_init)
setattr(dc_cls, '__post_init__', new_post_init)
else:

@wraps(init)
def new_init(self: 'Dataclass', *args: Any, **kwargs: Any) -> None:
handle_extra_init(self, *args, **kwargs)

setattr(dc_cls, '__init__', handle_extra_init)
setattr(dc_cls, '__post_init__', new_post_init)

else:

Expand Down
54 changes: 54 additions & 0 deletions tests/test_dataclasses.py
Expand Up @@ -1395,3 +1395,57 @@ class Bar:
@pydantic.dataclasses.dataclass
class Foo:
a: List[Bar(a=1)]


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

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

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

assert B().a == 3.2 # 2 * 1.1 + 1


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

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

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

assert B().a == 4.2 # (1.1 + 1) * 2


def test_subclass_post_init():
@dataclasses.dataclass
class A:
a: float = 1.1

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

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

assert B().a == 3.2 # 2 * 1.1 + 1

0 comments on commit f3644f0

Please sign in to comment.