Skip to content

Commit 9f75014

Browse files
committed
Properly rebuild Pydantic models if necessary
1 parent 861ef56 commit 9f75014

File tree

13 files changed

+49
-27
lines changed

13 files changed

+49
-27
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
default: CHANGE_TYPE
3+
---
4+
5+
# Properly rebuild Pydantic models if necessary
6+
7+
#1176 by @Viicos
8+
9+
Set `defer_build` to models that we know will fail to build, and call `model_rebuild`
10+
in the `__init__.py` file.

openapi_python_client/schema/openapi_schema_pydantic/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,14 @@
7070
from .server_variable import ServerVariable
7171
from .tag import Tag
7272
from .xml import XML
73+
74+
PathItem.model_rebuild()
75+
Operation.model_rebuild()
76+
Components.model_rebuild()
77+
Encoding.model_rebuild()
78+
MediaType.model_rebuild()
79+
OpenAPI.model_rebuild()
80+
Parameter.model_rebuild()
81+
Header.model_rebuild()
82+
RequestBody.model_rebuild()
83+
Response.model_rebuild()

openapi_python_client/schema/openapi_schema_pydantic/components.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class Components(BaseModel):
3535
links: Optional[dict[str, Union[Link, Reference]]] = None
3636
callbacks: Optional[dict[str, Union[Callback, Reference]]] = None
3737
model_config = ConfigDict(
38+
# `Callback` contains an unresolvable forward reference, will rebuild in `__init__.py`:
39+
defer_build=True,
3840
extra="allow",
3941
json_schema_extra={
4042
"examples": [

openapi_python_client/schema/openapi_schema_pydantic/encoding.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
if TYPE_CHECKING: # pragma: no cover
88
from .header import Header
9-
else:
10-
Header = "Header"
119

1210

1311
class Encoding(BaseModel):
@@ -19,11 +17,13 @@ class Encoding(BaseModel):
1917
"""
2018

2119
contentType: Optional[str] = None
22-
headers: Optional[dict[str, Union[Header, Reference]]] = None
20+
headers: Optional[dict[str, Union["Header", Reference]]] = None
2321
style: Optional[str] = None
2422
explode: bool = False
2523
allowReserved: bool = False
2624
model_config = ConfigDict(
25+
# `Header` is an unresolvable forward reference, will rebuild in `__init__.py`:
26+
defer_build=True,
2727
extra="allow",
2828
json_schema_extra={
2929
"examples": [

openapi_python_client/schema/openapi_schema_pydantic/header.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ class Header(Parameter):
2121
name: str = Field(default="")
2222
param_in: ParameterLocation = Field(default=ParameterLocation.HEADER, alias="in")
2323
model_config = ConfigDict(
24+
# `Parameter` is not build yet, will rebuild in `__init__.py`:
25+
defer_build=True,
2426
extra="allow",
2527
populate_by_name=True,
2628
json_schema_extra={

openapi_python_client/schema/openapi_schema_pydantic/media_type.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ class MediaType(BaseModel):
2121
examples: Optional[dict[str, Union[Example, Reference]]] = None
2222
encoding: Optional[dict[str, Encoding]] = None
2323
model_config = ConfigDict(
24+
# `Encoding` is not build yet, will rebuild in `__init__.py`:
25+
defer_build=True,
2426
extra="allow",
2527
populate_by_name=True,
2628
json_schema_extra={

openapi_python_client/schema/openapi_schema_pydantic/open_api.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
from .components import Components
66
from .external_documentation import ExternalDocumentation
77
from .info import Info
8-
9-
# Required to update forward ref after object creation
10-
from .path_item import PathItem # noqa: F401
118
from .paths import Paths
129
from .security_requirement import SecurityRequirement
1310
from .server import Server
@@ -32,7 +29,11 @@ class OpenAPI(BaseModel):
3229
tags: Optional[list[Tag]] = None
3330
externalDocs: Optional[ExternalDocumentation] = None
3431
openapi: str
35-
model_config = ConfigDict(extra="allow")
32+
model_config = ConfigDict(
33+
# `Components` is not build yet, will rebuild in `__init__.py`:
34+
defer_build=True,
35+
extra="allow"
36+
)
3637

3738
@field_validator("openapi")
3839
@classmethod
@@ -46,6 +47,3 @@ def check_openapi_version(cls, value: str) -> str:
4647
if int(parts[1]) > 1:
4748
raise ValueError(f"Only OpenAPI versions 3.1.* are supported, got {value}")
4849
return value
49-
50-
51-
OpenAPI.model_rebuild()

openapi_python_client/schema/openapi_schema_pydantic/operation.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@
44

55
from .callback import Callback
66
from .external_documentation import ExternalDocumentation
7-
from .header import Header # noqa: F401
87
from .parameter import Parameter
98

10-
# Required to update forward ref after object creation, as this is not imported yet
11-
from .path_item import PathItem # noqa: F401
9+
1210
from .reference import Reference
1311
from .request_body import RequestBody
1412
from .responses import Responses
@@ -38,6 +36,8 @@ class Operation(BaseModel):
3836
security: Optional[list[SecurityRequirement]] = None
3937
servers: Optional[list[Server]] = None
4038
model_config = ConfigDict(
39+
# `Callback` contains an unresolvable forward reference, will rebuild in `__init__.py`:
40+
defer_build=True,
4141
extra="allow",
4242
json_schema_extra={
4343
"examples": [
@@ -89,7 +89,3 @@ class Operation(BaseModel):
8989
]
9090
},
9191
)
92-
93-
94-
# PathItem in Callback uses Operation, so we need to update forward refs due to circular dependency
95-
Operation.model_rebuild()

openapi_python_client/schema/openapi_schema_pydantic/parameter.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class Parameter(BaseModel):
3535
examples: Optional[dict[str, Union[Example, Reference]]] = None
3636
content: Optional[dict[str, MediaType]] = None
3737
model_config = ConfigDict(
38+
# `MediaType` is not build yet, will rebuild in `__init__.py`:
39+
defer_build=True,
3840
extra="allow",
3941
populate_by_name=True,
4042
json_schema_extra={

openapi_python_client/schema/openapi_schema_pydantic/path_item.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
from typing import Optional, Union
1+
from typing import TYPE_CHECKING, Optional, Union
22

33
from pydantic import BaseModel, ConfigDict, Field
44

55
from .parameter import Parameter
66
from .reference import Reference
77
from .server import Server
88

9+
if TYPE_CHECKING:
10+
from .operation import Operation
911

1012
class PathItem(BaseModel):
1113
"""
@@ -33,6 +35,8 @@ class PathItem(BaseModel):
3335
servers: Optional[list[Server]] = None
3436
parameters: Optional[list[Union[Parameter, Reference]]] = None
3537
model_config = ConfigDict(
38+
# `Operation` is an unresolvable forward reference, will rebuild in `__init__.py`:
39+
defer_build=True,
3640
extra="allow",
3741
populate_by_name=True,
3842
json_schema_extra={
@@ -69,9 +73,3 @@ class PathItem(BaseModel):
6973
]
7074
},
7175
)
72-
73-
74-
# Operation uses PathItem via Callback, so we need late import and to update forward refs due to circular dependency
75-
from .operation import Operation # noqa: E402
76-
77-
PathItem.model_rebuild()

0 commit comments

Comments
 (0)