Add __get_pydantic_core_schema__ to domain classes.#273
Conversation
|
@JeanLucPons and @gupichon Can you take a look at what I tested? I only made the changes for I think this approach has many advantages but there is one major disadvantage which I'm feeling might make it a bad idea. I discovered that for arbitrary types to act the same as types that are already supported by pydantic, you can't just return the schema but you need to also build an object of the class. Otherwise nested structures are not resolved. Validation and creation now becomes mixed together. Also, I think it's quite confusing for the user because What do you think? My feeling at the moment is that it is better to keep validation and building objects as two separate concerns and not mix them together like this. |
|
What about dynamically creating 2 schema (one for validation, one for json schema) as aggregate of the class ? |
|
Yes, I think that is a better option. I don't really like the What do you think about what I did for the |
|
Ok, there are some very good pros ! |
|
With @JeanLucPons suggestion I think we can get rid of the ConfigModel and make the domain class the source of truth. We can have a I will make a new PR tomorrow for that option. |
Yes it allow flexibility, we get rid off ConfigModel, no requirement of pydantic knowledge for the users, easy to disable but:
|
I have made a PR to explore the option to use
__get_pydantic_core_schema__to make arbitrary types behave as if they are types supported by Pydantic.So far I have only modified
Elementto test the idea.Idea:
__get_pydantic_core_schema__using a decorator.Examples:
Build the element without validation
Do validation before building the element
Generate JSON schema
This is what I have found so far:
Pros:
A
ConfigModelis no longer needed. You can create an object of a domain class directly.You can use the domain classes directly in nested models and the validation will automatically work as for types already supported by pydantic. For example:
Generating JSON schemas work as if the type would be already supported by pydantic.
The user can first write the domain class and when they are happy with the business logic they can think about the validation.
Automatically adding
__get_pydantic_core_schema__to a class is easy with the decorator. This also makes pydantic a loose dependency since you can choose to not use the decorator and the domain class will be pydantic free.Cons:
For validation of nested structures to work in the same way as for other types
__get_pydantic_core_schema__doesn't only need to return the schema, but also do the validation and build an object of the class. It is possible to have__get_pydantic_core_schema__to only return the schema but the class will then not fully behave as expected by pydantic. Instead ofit will give
This means that
__get_pydantic_core_schema__doesn't only add validation functionality to the class but also starts acting as a factory and the separation of concerns is not good. It is possible to ignore this and just return the schema but it might become confusing to have some types following the principles of pydantic and some not.The decorator relies on the constructor having annotations. It will throw an error if there is a field which doesn't have one but potentially this can be a source of bugs since it is only caught at runtime.
Not sure how well this will work for more complicated constructors. However, it is always possible for a user to not use the decorator and instead write their own
__get_pydantic_core_schema__in the class. But that requires some pydantic knowledge.