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

Could __post_init_original__ run before pydantic validation? #557

Closed
HeavenVolkoff opened this issue May 28, 2019 · 4 comments
Closed

Could __post_init_original__ run before pydantic validation? #557

HeavenVolkoff opened this issue May 28, 2019 · 4 comments
Labels
feature request help wanted Pull Request welcome

Comments

@HeavenVolkoff
Copy link
Contributor

HeavenVolkoff commented May 28, 2019

Question

  • OS:

    Linux 64-bit

  • Python version import sys; print(sys.version):

    3.7.3 (default, Mar 26 2019, 21:43:19)
    [GCC 8.2.1 20181127]

  • Pydantic version import pydantic; print(pydantic.VERSION):

    0.26

Currently pydantic runs a dataclass' original __post_init__ after its validation. However that limits valid use cases in which a required field is calculated inside the __post_init__. This is exemplified in python's dataclass documentation here.

Python's example fails pydantic's validation:

from dataclasses import field
from pydantic.dataclasses import dataclass

@dataclass
class C:
    a: float
    b: float
    c: float = field(init=False)

    def __post_init__(self):
        self.c = self.a + self.b

c = C(0.1, 0.2)
# Raises:
# ValidationError: 1 validation error
# c
#   field required (type=value_error.missing)

This behaviour is enforced here:
https://github.com/samuelcolvin/pydantic/blob/426325820738328ce4c023d43fbddad07d62f4a0/pydantic/dataclasses.py#L27-L32

@samuelcolvin
Copy link
Member

I'd be happy with the change if it didn't break any existing tests.

@HeavenVolkoff
Copy link
Contributor Author

@samuelcolvin I opened pull request #560 with the changes. All tests seem to be passing fine. Could you review it?

@sevaho
Copy link
Contributor

sevaho commented May 31, 2019

If I many I want to reopen this issue.

Shouldn't there be a way to disable this functionality with a global config variable?
I liked it that pydantic has done it's validation and then your code in the post_init gets triggered.

Now you kinda have to validate the payload inside the post_init again or is my workflow wrong?

from dataclasses import asdict

from pydantic.dataclasses import dataclass


class GlobalConfig:
    validate_assignment = True
    validate_all = True
    use_enum_values = True


@dataclass(config=GlobalConfig)
class Date(object):
    year: int
    month: int
    day: int


@dataclass(config=GlobalConfig)
class Calendar(object):
    date: Date

    def __post_init__(self):
        print("TRIGGERED")
        print(type(self.date))


try:
    # this triggers the post_init without validation
    calendar2 = Calendar(**{"date": {"year": 1995, "month": 3, "day": "wong"}})
except Exception:
    pass

Yes the fix is easy here just create a Date object and do Calendar(**{date: date_object})

But what if I have a deep nested structure with a lot of composition do I need to create each object separately before creating my parent class?

@samuelcolvin
Copy link
Member

Moved that discussion to another issue, see #566.

alexdrydew pushed a commit to alexdrydew/pydantic that referenced this issue Dec 23, 2023
* Use __pydantic_serializer__ for serializing to JSON

* Make to_json(by_alias=False) work

* Use presence of __pydantic_serializer__ instead of anything else to go down model serialization path
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request help wanted Pull Request welcome
Projects
None yet
Development

No branches or pull requests

3 participants