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

Support subclasses in lists in Union of List types #1039

Merged
merged 1 commit into from Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/serializers/type_serializers/list.rs
Expand Up @@ -116,4 +116,8 @@ impl TypeSerializer for ListSerializer {
fn get_name(&self) -> &str {
&self.name
}

fn retry_with_lax_check(&self) -> bool {
self.item_serializer.retry_with_lax_check()
}
}
3 changes: 2 additions & 1 deletion src/serializers/type_serializers/union.rs
Expand Up @@ -75,9 +75,10 @@ impl TypeSerializer for UnionSerializer {
exclude: Option<&PyAny>,
extra: &Extra,
) -> PyResult<PyObject> {
// try the serializers in with error_on fallback=true
// try the serializers in left to right order with error_on fallback=true
let mut new_extra = extra.clone();
new_extra.check = SerCheck::Strict;

for comb_serializer in &self.choices {
match comb_serializer.to_python(value, include, exclude, &new_extra) {
Ok(v) => return Ok(v),
Expand Down
56 changes: 56 additions & 0 deletions tests/serializers/test_union.py
Expand Up @@ -454,3 +454,59 @@ class Item(BaseModel):
)

assert s.to_python(DBUser(name='John', password='secret')) == {'name': 'John'}


def test_union_serializes_list_of_model_subclass_from_definition() -> None:
class BaseModel:
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'

def __init__(self, **kwargs: Any):
for key, value in kwargs.items():
setattr(self, key, value)

class User(BaseModel):
name: str

class DBUser(User):
password: str
__pydantic_serializer__: ClassVar[SchemaSerializer]

DBUser.__pydantic_serializer__ = SchemaSerializer(
core_schema.model_schema(
DBUser,
core_schema.model_fields_schema(
{
'name': core_schema.model_field(core_schema.str_schema()),
'password': core_schema.model_field(core_schema.str_schema()),
}
),
)
)

class Item(BaseModel):
price: float

s = SchemaSerializer(
core_schema.definitions_schema(
core_schema.union_schema(
[
core_schema.list_schema(core_schema.definition_reference_schema('User'), strict=False),
core_schema.list_schema(core_schema.definition_reference_schema('Item'), strict=False),
]
),
[
core_schema.model_schema(
User,
core_schema.model_fields_schema({'name': core_schema.model_field(core_schema.str_schema())}),
ref='User',
),
core_schema.model_schema(
Item,
core_schema.model_fields_schema({'price': core_schema.model_field(core_schema.float_schema())}),
ref='Item',
),
],
)
)

assert s.to_python([DBUser(name='John', password='secret')]) == [{'name': 'John'}]