-
Notifications
You must be signed in to change notification settings - Fork 280
Fix serialize_as_any with recursive ref #1359
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
Changes from 1 commit
7b5c8ce
6093291
1976e36
14b895b
f51a195
d6fbaab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
from dataclasses import dataclass | ||
from typing import Optional | ||
|
||
from typing_extensions import TypedDict | ||
|
||
|
@@ -155,3 +156,38 @@ class Other: | |
'x': 1, | ||
'y': 'hopefully not a secret', | ||
} | ||
|
||
|
||
def test_serialize_with_recursive_models() -> None: | ||
|
||
class Node: | ||
next: Optional['Node'] = None | ||
value: int = 42 | ||
|
||
schema = core_schema.definitions_schema( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sydney-runkle I tested the python code and all good but how do I make an equivalent from __future__ import annotations
import traceback
import pydantic
class Model1(pydantic.BaseModel):
recursive: Model1 | None
class Model2(pydantic.BaseModel):
recursive: pydantic.SerializeAsAny[Model2] | None
print(Model1(recursive=None).model_dump())
print(Model1(recursive=None).model_dump_json())
print(Model2(recursive=None).model_dump())
print(Model2(recursive=None).model_dump_json())
# All fail:
try:
print(Model1(recursive=None).model_dump(serialize_as_any=True))
except:
traceback.print_exc()
try:
print(Model1(recursive=None).model_dump_json(serialize_as_any=True))
except:
traceback.print_exc()
try:
print(Model2(recursive=None).model_dump(serialize_as_any=True))
except:
traceback.print_exc()
try:
print(Model2(recursive=None).model_dump_json(serialize_as_any=True))
except:
traceback.print_exc() There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question - I normally just do from pydantic._internal._core_utils import pretty_print_core_schema
from pydantic import BaseModel
class SomeModel(BaseModel): ...
pretty_print_core_schema(SomeModel.__pydantic_core_schema__) And then go from that representation in order to build up an equivalent core schema |
||
core_schema.definition_reference_schema('Node'), | ||
[ | ||
core_schema.model_schema( | ||
Node, | ||
core_schema.model_fields_schema( | ||
{ | ||
'value': core_schema.model_field(core_schema.with_default_schema(core_schema.int_schema(), default=42)), | ||
'next': core_schema.model_field( | ||
core_schema.with_default_schema( | ||
core_schema.nullable_schema( | ||
core_schema.definition_reference_schema('Node') | ||
), | ||
default=None, | ||
) | ||
), | ||
} | ||
), | ||
ref='Node', | ||
) | ||
], | ||
) | ||
|
||
s = SchemaSerializer(schema) | ||
v = SchemaValidator(schema) | ||
|
||
obj = v.validate_python({'value': 2, 'asdas': 1}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so what I found is that the
outer serializer
call torescursive serializer
but also put theself.definition.id()
in the stack already. So when therescursive serializer
start to eval, the root model of it have the sameself.definition.id()
result in raise duplicated id error.Checking for
DuckTypingSerMode::Inferred
is because that what I saw as a flag when therescursive serializer
started. I could be wrong so very open for suggestions !There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, seems like a clever find. I think I'd like to have @davidhewitt take a look at this as well before we merge, he should be back soon :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change (to not introduce recursion guards) is the cause of the segfaults in the tests in CI. (The tests now have unbounded recursion and blow the stack.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have fixed the issue!