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

Calling __init__ when parsing nested models #440

Closed
dmontagu opened this issue Mar 14, 2023 · 3 comments
Closed

Calling __init__ when parsing nested models #440

dmontagu opened this issue Mar 14, 2023 · 3 comments
Assignees

Comments

@dmontagu
Copy link
Collaborator

In pydantic v1:

from pydantic import BaseModel

class B(BaseModel):
    y: int

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print('inner')


class A(BaseModel):
    x: B

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print('outer')


A.parse_obj({'x': {'y': 2}})

This results in:

inner
outer

This doesn't currently work with the way validation happens in v2.

(@samuelcolvin you wanted me to create an issue about this — feel free to add color.)

@samuelcolvin
Copy link
Member

samuelcolvin commented Mar 14, 2023

problem is that V2 does

let instance = (*raw_type).tp_new ...;
force_setattr(py, instance, intern!(py, "__dict__"), model_dict)?;
...
force_setattr(py, instance, intern!(py, "__fields_set__"), fields_set)?;

Thereby, __init__ is never called

see

let raw_type = self.class.as_ref(py).as_type_ptr();
let instance = unsafe {
// Safety: raw_type is known to be a non-null type object pointer
match (*raw_type).tp_new {
// Safety: the result of new_func is guaranteed to be either an owned pointer or null on error returns.
Some(new_func) => PyObject::from_owned_ptr_or_err(
py,
// Safety: the non-null pointers are known to be valid, and it's allowed to call tp_new with a
// null kwargs dict.
new_func(raw_type, args.as_ptr(), null_mut()),
)?,
None => return py_err!(PyTypeError; "base type without tp_new"),
}
};
let instance_ref = instance.as_ref(py);
force_setattr(py, instance_ref, intern!(py, "__dict__"), model_dict)?;
if let Some(fields_set) = fields_set {
force_setattr(py, instance_ref, intern!(py, "__fields_set__"), fields_set)?;
}

@dmontagu
Copy link
Collaborator Author

Solution: we'll tell people to use a mode='wrap' root_validator to handle this logic.

  • Need to confirm that you can override and call super().my_root_validator() and have it work the same as __init__ would
  • Need to add this to the migration guide

@samuelcolvin
Copy link
Member

This was fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants