Skip to content

Commit dea30a0

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

File tree

13 files changed

+49
-28
lines changed

13 files changed

+49
-28
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: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@
44

55
from .callback import Callback
66
from .external_documentation import ExternalDocumentation
7-
from .header import Header # noqa: F401
87
from .parameter import Parameter
9-
10-
# Required to update forward ref after object creation, as this is not imported yet
11-
from .path_item import PathItem # noqa: F401
128
from .reference import Reference
139
from .request_body import RequestBody
1410
from .responses import Responses
@@ -38,6 +34,8 @@ class Operation(BaseModel):
3834
security: Optional[list[SecurityRequirement]] = None
3935
servers: Optional[list[Server]] = None
4036
model_config = ConfigDict(
37+
# `Callback` contains an unresolvable forward reference, will rebuild in `__init__.py`:
38+
defer_build=True,
4139
extra="allow",
4240
json_schema_extra={
4341
"examples": [
@@ -89,7 +87,3 @@ class Operation(BaseModel):
8987
]
9088
},
9189
)
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: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
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
11+
912

1013
class PathItem(BaseModel):
1114
"""
@@ -33,6 +36,8 @@ class PathItem(BaseModel):
3336
servers: Optional[list[Server]] = None
3437
parameters: Optional[list[Union[Parameter, Reference]]] = None
3538
model_config = ConfigDict(
39+
# `Operation` is an unresolvable forward reference, will rebuild in `__init__.py`:
40+
defer_build=True,
3641
extra="allow",
3742
populate_by_name=True,
3843
json_schema_extra={
@@ -69,9 +74,3 @@ class PathItem(BaseModel):
6974
]
7075
},
7176
)
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()

openapi_python_client/schema/openapi_schema_pydantic/request_body.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ class RequestBody(BaseModel):
1717
content: dict[str, MediaType]
1818
required: bool = False
1919
model_config = ConfigDict(
20+
# `MediaType` is not build yet, will rebuild in `__init__.py`:
21+
defer_build=True,
2022
extra="allow",
2123
json_schema_extra={
2224
"examples": [

openapi_python_client/schema/openapi_schema_pydantic/response.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class Response(BaseModel):
2323
content: Optional[dict[str, MediaType]] = None
2424
links: Optional[dict[str, Union[Link, Reference]]] = None
2525
model_config = ConfigDict(
26+
# `MediaType` is not build yet, will rebuild in `__init__.py`:
27+
defer_build=True,
2628
extra="allow",
2729
json_schema_extra={
2830
"examples": [

openapi_python_client/schema/openapi_schema_pydantic/schema.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,3 @@ def handle_nullable(self) -> "Schema":
206206
self.oneOf = [Schema(type=DataType.NULL), Schema(allOf=self.allOf)]
207207
self.allOf = []
208208
return self
209-
210-
211-
Schema.model_rebuild()

0 commit comments

Comments
 (0)