Issue
Assume I have an external Class OriginalExternalClass
whose code I can not be modified. I want to use that external class as a field of another class called PydanticClassWithExternalClassMember
which derives from pydantic BaseModel
.
I want circumvent using the arbitrary types flag, as I want to implement type checking and serialization capabilities for the OriginalExternalClass
field. To code works and looks the following:
from typing import Any
from pydantic_core import core_schema
import pydantic
class OriginalExternalClass:
def __init__(self, a: int, b: str) -> None:
self.a = a
self.b = b
class PydanticExternalClass(OriginalExternalClass):
@classmethod
def __get_pydantic_core_schema__(
cls,
_source_type: Any,
_handler: pydantic.GetCoreSchemaHandler,
) -> core_schema.CoreSchema:
def json_schema(value: dict) -> OriginalExternalClass:
# NEVER CALLED!!!
print("json_schema called")
result = OriginalExternalClass(**value)
return result
def python_schema(
value: OriginalExternalClass,
) -> OriginalExternalClass:
print("python_schema called")
if isinstance(value, dict):
value = OriginalExternalClass(**value)
if not isinstance(value, OriginalExternalClass):
raise pydantic.ValidationError(
msg="Expected a `ExternalClass` instance",
loc=("third_party_type",),
type=OriginalExternalClass,
)
return value
def serialization(value: OriginalExternalClass) -> dict:
print("serialization called")
return {"a": value.a, "b": value.b}
return core_schema.json_or_python_schema(
json_schema=core_schema.no_info_plain_validator_function(json_schema),
python_schema=core_schema.no_info_plain_validator_function(python_schema),
serialization=core_schema.plain_serializer_function_ser_schema(
serialization
),
)
class PydanticClassWithExternalClassMember(pydantic.BaseModel):
x: PydanticExternalClass
However, what I do not understand, is when is the json_schema
attribute of JsonOrPythonSchema
genereated by json_schema=core_schema.no_info_plain_validator_function(json_schema)
used? What is it needed for? The function json_schema is never called when executing:
print(
"m1 = PydanticClassWithExternalClassMember(x=PydanticExternalClass(1, 'basgsadf'))"
)
m1 = PydanticClassWithExternalClassMember(x=PydanticExternalClass(1, "basgsadf"))
print("d = m1.model_dump()")
d = m1.model_dump()
print("m1 = PydanticClassWithExternalClassMember(**d)")
m1 = PydanticClassWithExternalClassMember(**d)
And the output is
m1 = PydanticClassWithExternalClassMember(x=PydanticExternalClass(1, 'basgsadf'))
python_schema called
d = m1.model_dump()
serialization called
m1 = PydanticClassWithExternalClassMember(**d)
python_schema called
Solution
That's because you're not testing JSON deserialisation there.
If you did this, though:
adapter = pydantic.TypeAdapter(PydanticClassWithExternalClassMember)
value = adapter.validate_json("""{"x": {"a": 1, "b": "basgsadf"}}""")
print("Got", value.model_dump())
...it does. See output:
m1 = PydanticClassWithExternalClassMember(x=PydanticExternalClass(1, 'basgsadf'))
python_schema called
json_schema called
serialization called
Got {'x': {'a': 1, 'b': 'basgsadf'}}
d = m1.model_dump()
serialization called
m1 = PydanticClassWithExternalClassMember(**d)
python_schema called
Answered By - declension
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.