-
Notifications
You must be signed in to change notification settings - Fork 243
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
Fix serialize_as_any with recursive ref #1359
Fix serialize_as_any with recursive ref #1359
Conversation
CodSpeed Performance ReportMerging #1359 will not alter performanceComparing Summary
|
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 comment
The 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 schema
for the test here ?
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 comment
The 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
@@ -93,8 +94,12 @@ impl TypeSerializer for DefinitionRefSerializer { | |||
) -> PyResult<PyObject> { | |||
self.definition.read(|comb_serializer| { | |||
let comb_serializer = comb_serializer.unwrap(); | |||
let mut guard = extra.recursion_guard(value, self.definition.id())?; | |||
comb_serializer.to_python(value, include, exclude, guard.state()) | |||
if extra.duck_typing_ser_mode != DuckTypingSerMode::Inferred { |
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 to rescursive serializer
but also put the self.definition.id()
in the stack already. So when the rescursive serializer
start to eval, the root model of it have the same self.definition.id()
result in raise duplicated id error.
Checking for DuckTypingSerMode::Inferred
is because that what I saw as a flag when the rescursive 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!
@NeevCohen, I'm finally back, and can review this either this evening or tomorrow morning! |
@sydney-runkle Welcome back! I think you meant to tag @nix010 😅 |
@NeevCohen ah yes, oops! Thanks! Meant to tag @nix010 :) |
…nix010/pydantic-core into fix-serialize-as-any-with-recursive-ref
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1359 +/- ##
==========================================
- Coverage 90.21% 89.21% -1.00%
==========================================
Files 106 112 +6
Lines 16339 17818 +1479
Branches 36 41 +5
==========================================
+ Hits 14740 15897 +1157
- Misses 1592 1901 +309
- Partials 7 20 +13
... and 49 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
Closing in favor of #1478 |
BaseModel.model_dump[_xxx](serialize_as_any = True) breaks with models with recursive attribute types (not values)
pydantic/pydantic#9670
Related issue number
fix pydantic/pydantic#9670
Checklist
pydantic-core
(except for expected changes)