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
Config / runtime option for SerializeAsAny
#6423
Comments
Related: pydantic/pydantic-core#740 |
Hi, I would really vote for this feature as upgrading a project to add SerializeAsAny on multiple places is very tiresome and brings multiples errors. |
@adriangb where do things stand with the more global ways of enabling duck-typing serialization? Not sure if that was abandoned or paused or what. Seems like it might be worth a config setting unless I'm misremembering challenges with that. I know you had the PR for the runtime flag but not sure if that addresses the "make it work everywhere by default" use case. |
I think I ran into technical limitations getting it working, but I don’t fully remember. We can try again. |
Thanks, that would be appreciated! We can probably workaround this by own schema generation but it is not nice. |
Is this still something planned for release? If there are specific tasks remaining I would be happy to help. This change has proven to be quite annoying compared to more typical ways to deal with this issue like annotating fields as sensitive/hidden. |
We have code that uses pydantic and have been unable to upgrade due to the serialization change as we'd need to make changes in many places in the code. We wanted to share that this config option would be a very helpful feature for us. |
I still think this is a good idea and would be preferred/helpful for a lot of people. @sydney-runkle I think this is worth adding to the priorities list. I also personally think we should prioritize getting something out to address well before any kind of v3 push (just don't want this to get lumped into the "we'll do it in v3" pile). |
I think we should call this "seared duck" as it's duck typing serialisation. |
FWIW this is also a blocker for upgrading our large pydantic-based project to v2. We have a custom BaseModel subclass used throughout, with lots of nested models inheriting from it. Not keen on adding SerializeAsAny everywhere. This new serialization behavior default in v2 is also a bit surprising. We use |
Is there any reasonable workaround for this, perhaps by overwriting class MyModel(BaseModel):
@classmethod
def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
return SerializeAsAny(). __get_pydantic_core_schema__(source, handler) But this results in I'm building tools used by scientists who are unlikely to understand or remember that they need to use the |
@rmorshea This is how I have worked around it for now (though excited for a better solution). Many thanks to #6381 for inspiration from pydantic import BaseModel, SerializeAsAny
from pydantic._internal._model_construction import ModelMetaclass
from typing import Any, Dict, Tuple
# See https://github.com/pydantic/pydantic/issues/6381
class _SerializeAsAnyMeta(ModelMetaclass):
def __new__(self, name: str, bases: Tuple[type], namespaces: Dict[str, Any], **kwargs):
annotations: dict = namespaces.get("__annotations__", {})
for base in bases:
for base_ in base.__mro__:
if base_ is BaseModel:
annotations.update(base_.__annotations__)
for field, annotation in annotations.items():
if not field.startswith("__"):
annotations[field] = SerializeAsAny[annotation]
namespaces["__annotations__"] = annotations
return super().__new__(self, name, bases, namespaces, **kwargs)
class MyBaseModel(BaseModel, metaclass=_SerializeAsAnyMeta):
pass
class A(BaseModel):
x: int = 0
class B_old(BaseModel):
a: BaseModel
class B_new(MyBaseModel):
a: BaseModel
print(B_old(a=A()).model_dump())
print(B_new(a=A()).model_dump()) |
You can probably do something like this, even though I think its a bit slow:
|
Unfortunately both solutions appear to break if you use any custom types with specialized serialization logic. For example, I have a custom type annotation that serializes Pandas DataFrames into the Apache Parquet file format. Adding Put another way, the workarounds above are not synonymous with If there is no other option but to modify the fields of |
Initial Checks
Description
(Inspired by the problem in #6403.)
The idea is to add
serialize_as_any
as a config (or runtime) option.As a config option, the model would be serialized in a duck-typed fashion (as V1 would behave), but this would not apply to fields of the model:
As a runtime option, all fields of the model would be serialized in a duck-typed fashion, recursively:
The name
serialize_as_any
is open to bikeshedding - I've suggested it to match theSerializeAsAny
type annotation. One possibly compelling alternative name isstrict
(maybeser_strict
as the config option to separate fromstrict
validation).Context
In Pydantic V2 we changed the serialization from duck-typed to serialize exactly the model specified. That is to say, in the following model:
Then in V2 the
ListType.element_type
field will always serialize as{}
(as that's the contents ofGenericBase
), but the equivalent in V1 would serialize as the concrete subclass.Concretely:
The way to get the V1 behaviour back in V2 (duck-typed serialization) is by wrapping the annotation in
SerializeAsAny
.This will now fix serialization for
ListType
, but other uses ofGenericBase
will all need to similarly be wrapped inSerializeAsAny
.Alternatives
Some possible alternatives to the model config:
I'm unaware of an alternative strategy for the runtime option at this time.
Affected Components
.model_dump()
and.model_dump_json()
model_construct()
, pickling, private attributes, ORM modeSelected Assignee: @adriangb
The text was updated successfully, but these errors were encountered: