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
KeyError during model_rebuild/recursive schemas #5730
Comments
@adriangb for context @commonism I think it would be helpful if there was any way you could get us a code sample that could reproduce this issue. |
Let's hope this allows to reproduce:
It'll use https://github.com/commonism/aiopenapi3/blob/master/tests/fixtures/schema-recursion.yaml For me - it works when using a different file …
smallest dd to reproduce:
I never had it fail when using only two of the properties, sometimes it works with all three of them. |
Do not waste time on this yet, I think this may be unrelated to pydantic itself but misuse of it. |
I managed to reduce this example to something which may be acceptable.
import random
from typing import List, ForwardRef
from pydantic import BaseModel
def test():
class Expressions_(BaseModel):
model_config = dict(undefined_types_warning=False)
items: List["__types['Expression']"]
class Expression_(BaseModel):
model_config = dict(undefined_types_warning=False)
Or: ForwardRef("__types['allOfExpressions']")
And: ForwardRef("__types['allOfExpressions']")
Not: ForwardRef("__types['allOfExpression']")
class allOfExpression_(BaseModel):
model_config = dict(undefined_types_warning=False)
Or: ForwardRef("__types['Expressions']")
And: ForwardRef("__types['Expressions']")
Not: ForwardRef("__types['Expression']")
class allOfExpressions_(BaseModel):
model_config = dict(undefined_types_warning=False)
items: List["__types['Expression']"]
types = {"__types":{"Expression": Expression_, "Expressions": Expressions_, "allOfExpression": allOfExpression_, "allOfExpressions": allOfExpressions_}}
l = [allOfExpressions_, Expressions_]#, allOfExpression_, Expression_]
# l = list(types["__types"].values())
# random.shuffle(l)
# print(l)
for i in l:
i.model_rebuild(_types_namespace=types)
#for i in range(100):
# test()
test() If it works for you, use the commented lines to have it shuffle. My understanding of the walker is limited, but I think this is related to L453 which ignores pydantic/pydantic/_internal/_core_utils.py Lines 445 to 456 in 5e81582
|
This is a +1 on a nested model from me. Not sure what I'm doing wrong. |
@chriszs could you share your code? |
Reduced it down to: from pydantic import BaseModel, ConfigDict
CONFIG = ConfigDict(undefined_types_warning=False)
class Division(BaseModel):
model_config = CONFIG
division_level: "DivisionLevel"
class DivisionLevel(BaseModel):
model_config = CONFIG
divisions: list["Division"]
geometries: list["Geometry"]
class Geometry(BaseModel):
model_config = CONFIG
division_level: "DivisionLevel"
points: list["Point"]
class Point(BaseModel):
model_config = CONFIG
geometry: "Geometry"
Point.model_rebuild()
DivisionLevel.model_rebuild()
Division.model_rebuild()
Geometry.model_rebuild() Was getting:
I can fix it by flipping DivisionLevel.model_rebuild()
Division.model_rebuild() That works, but I wouldn't have expected that to be the error. |
I can confirm. from pydantic import BaseModel, ConfigDict
CONFIG = ConfigDict(undefined_types_warning=False)
class Division(BaseModel):
model_config = CONFIG
division_level: "DivisionLevel"
class DivisionLevel(BaseModel):
model_config = CONFIG
division_level: "DivisionLevel"
points: list["Point"]
class Point(BaseModel):
model_config = CONFIG
DivisionLevel.model_rebuild()
Division.model_rebuild() Any chance to have this addressed for beta #5919 ? |
I definitely want to get this resolved ASAP, but I wasn't able to with a quick investigation. Hoping to find time to look into this more this week. Either way we'll definitely release a new release as soon as it is fixed |
it changed and started working from typing import ForwardRef
from pydantic import BaseModel, ConfigDict
CONFIG = ConfigDict(undefined_types_warning=False)
class Division(BaseModel):
model_config = CONFIG
division_level: "DivisionLevel"
class DivisionLevel(BaseModel):
model_config = CONFIG
division_level: "DivisionLevel"
points: list[ForwardRef("Point")] # difference is here
class Point(BaseModel):
model_config = CONFIG
DivisionLevel.model_rebuild()
Division.model_rebuild() works when using ForwardRef explicit my example u works |
current MRE from typing import List, ForwardRef
from pydantic import BaseModel
def test():
class Expressions_(BaseModel):
model_config = dict(undefined_types_warning=False)
items: List["__types['Expression']"]
class Expression_(BaseModel):
model_config = dict(undefined_types_warning=False)
Or: ForwardRef("__types['allOfExpressions']")
Not: ForwardRef("__types['allOfExpression']")
class allOfExpression_(BaseModel):
model_config = dict(undefined_types_warning=False)
Not: ForwardRef("__types['Expression']")
class allOfExpressions_(BaseModel):
model_config = dict(undefined_types_warning=False)
items: List["__types['Expression']"]
types = {"__types":{"Expression": Expression_, "Expressions": Expressions_, "allOfExpression": allOfExpression_, "allOfExpressions": allOfExpressions_}}
l = [allOfExpressions_, Expressions_]
for i in l:
i.model_rebuild(_types_namespace=types)
test() |
It looks like the issue doesn't reproduce on the latest Pydantic Here is a PR with the test added #6159 The test passes in on all supported Python versions. @commonism does it works for you as well now? |
I can confirm that all the example snippets in this issue currently don't error on main. I'm a bit concerned that since none of them attempt validation, the issue has been pushed off, but at the same time we (and by "we" I mostly mean @adriangb) have made many improvements so 🤞 it might just be fixed. |
works for me |
Initial Checks
main
branch, or equivalentDescription
Defining a recursive model via model_rebuild sometimes fails with:
So far I can not reproduce easily, but I saw
recent changes
to _simplify_schema_references so … maybe … this is enough already?Example Code
No response
Python, Pydantic & OS Version
The text was updated successfully, but these errors were encountered: