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

Make BaseModel.model_validate() more consistent with BaseModel.model_dump(mode='...') #9306

Closed
4 of 13 tasks
maksutovaynur opened this issue Apr 23, 2024 · 2 comments
Closed
4 of 13 tasks

Comments

@maksutovaynur
Copy link

Initial Checks

  • I have searched Google & GitHub for similar requests and couldn't find anything
  • I have read and followed the docs and still think this feature is missing

Description

BaseModel's model_dump method allows to dump model to jsonable container (not to json string), using mode='json':

class MyModel(BaseModel):
    ...

jsonable_dict = MyModel(...).model_dump(mode='json')

This gives nice jsonable dict.
But there is no symmetrical mode='json' argument to MyModel.model_validate(...) function:

MyModel.model_validate(jsonable_dict, mode='json')

Yes, you can just use .model_validate() without any arguments and it works for many built-in types (i.e. bytes).
But problems can be faced with user-defined types (with __get_pydantic_core_schema__ defined):

class SomeValidator:
    def create_with_info(self, base_data: Any, info: core_schema.ValidationInfo) -> SomeUserDefinedType:
        if info.mode ==  'json':
            ... # one validation
        elif info.mode == 'python':
            ... # another validation

    def __get_pydantic_core_schema__(self, _source_type: Any, _handler: GetCoreSchemaHandler):
        validations = [
            core_schema.with_info_plain_validator_function(self.create_with_info),
            ...
        ]
        ...
        return core_schema.chain_schema(validations)

MyType = Annotated[SomeUserDefinedType, SomeValidator(...)]

class MyModel(BaseModel):
    a: MyType

MyModel.model_validate_json(json_string)   # works nicely with validating directly from json string, `info.mode=='json'`
MyModel.model_validate(jsonable_dict)      # unfortunately, always `info.mode=='python'`

Is it by design? Could mode='json' be added to model_validate() in the next versions of Pydantic?

Affected Components

@maksutovaynur
Copy link
Author

Another source of inconsistency: you can pass any mode while model_dump():

class MyModel(BaseModel):
    a: Annotated[UserDefinedType, UserDefinedTypeCustomSerializer]

MyModel(...).model_dump(mode='custom_mode')  # This gives `info.mode=='custom_mode'` inside serializer

# More about UserDefinedTypeCustomSerializer

class UserDefinedTypeCustomSerializer:
    @classmethod
    def _serialize(cls,
                   arr:  UserDefinedType,
                   handler: core_schema.SerializerFunctionWrapHandler,
                   info: core_schema.SerializationInfo):
        if info.mode == 'custom_mode':
            ... # this works

    @classmethod
    def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler):
        return core_schema.no_info_after_validator_function(
            lambda x: x,
            handler(source_type),
            serialization=core_schema.wrap_serializer_function_ser_schema(cls._serialize, info_arg=True),
        )

But you can not do the same while model_validate(...), because mode argument is not passed here.

This feature might be helpful when defining custom serialization formats, i.e. BSON.

@sydney-runkle
Copy link
Member

I think this is definitely a reasonable feature request. Given that this is discussed already in #9009, I'm going to close this as a duplicate, but it will good to have this issue as a reference when #9009 is being worked on!

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

No branches or pull requests

2 participants