-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
RecursionError when building model and parsing data in a loop #5108
Comments
@radiand I see what is going on here: every time you call From the perspective of getting a quick solution in place in v1 and moving on (to focus on v2), I'm inclined to either do nothing (but maybe update the docs), or do the following:
|
One possible case I wasn't considering above -- re-applying the pydantic decorator to subclasses of a base dataclass. This feels much more likely to both be on purpose, and not be warning-worthy. Given that, I'm a bit more nervous to make the changes suggested above, though I think I may have a way to check if the decorator was called on the specific class provided and not a subclass.. I'll look into it. |
Here is an approach that I think we could take to handling the error looking for re-application of the decorator even with subclassing. Right after the first line in this snippet: pydantic/pydantic/dataclasses.py Lines 190 to 199 in 314abca
We could insert something like: existing_model = getattr(cls, '__pydantic_model__', None)
if existing_model:
for base in cls.__bases__:
if getattr(base, '__pydantic_model__', None) is existing_model:
break # the value of the `__pydantic_model__` attribute is coming from a baseclass
else:
# Decorator has been re-applied specifically to this class.
warnings.warn(
f'The pydantic.dataclasses.dataclass decorator has been reapplied to {cls.__name__}; '
'this will not have any effect.',
UserWarning
)
return cls With that change, in the code below, a warning is only emitted on the final line: import pydantic
@pydantic.dataclasses.dataclass
class Message:
content: str
@pydantic.dataclasses.dataclass
class MessageWithMore(Message):
more: str
MessageWithMore = pydantic.dataclasses.dataclass(MessageWithMore) (And no recursion error is generated in @radiand's example code.) I'm not sure if there might be other implications here, but I wanted to at least comment with it for future reference. |
Thanks so much for the explanation @dmontagu, makes sense. I'm very very unwilling to mess with dataclasses again on v1 unless absolutely necessary. Every change we've made has broken something else. |
First of all - thanks for the analysis and the response. I tried your solution with refusing to re-apply the wrapper when it has been applied before - it works, also in the actual application where I'm building pydantic models during both serialization and deserialization for each incoming/outcoming message in the system. But well, my dataclasses are purposely simple, they mostly consist of primitive types, they do not subclass each other nor they nest other dataclasses. Therefore, probably my example won't help in spotting what else could be wrong. I didn't have enough time to dive deeply into pydantic code to help you more, at least for now, I'm sorry. When I was posting this issue I was hesitant to do it, because I had the "solution" anyway, and I also had a feeling that I'm exploiting pydantic in some way. But since this code was working before, I decided to at least let you know. Since V2 is the priority now, I'm totally fine with staying at pydantic==1.9.2 and eventually rework my application to stop doing silly things and switch to 1.10.x release. Thank you for your excellent work. |
Great response, thanks so much for understanding. |
Keeping this open to check on v2. |
In v2, much of the code in the original snippet needs changing. However, after making the appropriate changes, I'm able to run it without error. One caveat, I wasn't able to create a frozen pydantic dataclass by wrapping an unfrozen one. Also, I think the pydantic dataclass ends up being a different type, so the equality check fails, but that too can be worked around. The other thing to keep in mind is that we have added If you notice new issues in v2 we very much appreciate reports, but I'm going to close this for now since it seems to be mostly linked to v1 misbehavior. |
Initial Checks
Description
I'm getting a
RecursionError
when I'm doing both dataclass model creation and parsing data in each iteration of afor
loop. Solution for this is to move creating the model before the loop, and in a loop leave only parsing, but it is surprising to seeRecursionError
with simple model without recursion at all.Obviously, recreating the model over and over does not seem to be efficient, however when I started working on my code it was (and still is) good enough.
This code is working on
pydantic==1.9.2
and stopped with>=1.10
. The1.9.x
version also required usingfrozen
argument topydantic.dataclasses.dataclass
to make it work.I am aware of: #4949 and related
RecursionError
issues, but seems to be a bit different.Context in which this was found: my application uses
pydantic
to (de-)serialize and validate messages coming from remote places of my application. Messages are defined as standard python@dataclass
es and I have access to their definitions, so I can usepydantic_encoder
to convert them to JSONs in one place and somewhere else createpydantic
dataclasses ad hoc to recreate the original dataclass.Commentary to the code example: below example code is very simple and one may ask:
The answer is:
pydantic
helps me with more complex cases, e.g. when timestamp comes as a string and it has to be converted back todatetime
.Example Code
Python, Pydantic & OS Version
Affected Components
.model_dump()
and.model_dump_json()
model_construct()
, pickling, private attributes, ORM modeThe text was updated successfully, but these errors were encountered: