Skip to content

Commit 8300674

Browse files
mtovtmaz808dbanty
authored
feat: Support for recursive and circular references using lazy imports [#670, #338, #466]. Thanks @mtovt!
Co-authored-by: maz808 <[email protected]> Co-authored-by: Dylan Anthony <[email protected]>
1 parent 47e576c commit 8300674

38 files changed

+2477
-363
lines changed

Diff for: end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ def _get_kwargs(
2424
union_prop: Union[float, str] = "not a float",
2525
union_prop_with_ref: Union[AnEnum, None, Unset, float] = 0.6,
2626
enum_prop: AnEnum,
27-
model_prop: ModelWithUnionProperty,
28-
required_model_prop: ModelWithUnionProperty,
27+
model_prop: "ModelWithUnionProperty",
28+
required_model_prop: "ModelWithUnionProperty",
2929
) -> Dict[str, Any]:
3030
url = "{}/tests/defaults".format(client.base_url)
3131

@@ -130,8 +130,8 @@ def sync_detailed(
130130
union_prop: Union[float, str] = "not a float",
131131
union_prop_with_ref: Union[AnEnum, None, Unset, float] = 0.6,
132132
enum_prop: AnEnum,
133-
model_prop: ModelWithUnionProperty,
134-
required_model_prop: ModelWithUnionProperty,
133+
model_prop: "ModelWithUnionProperty",
134+
required_model_prop: "ModelWithUnionProperty",
135135
) -> Response[Union[Any, HTTPValidationError]]:
136136
"""Defaults
137137
@@ -187,8 +187,8 @@ def sync(
187187
union_prop: Union[float, str] = "not a float",
188188
union_prop_with_ref: Union[AnEnum, None, Unset, float] = 0.6,
189189
enum_prop: AnEnum,
190-
model_prop: ModelWithUnionProperty,
191-
required_model_prop: ModelWithUnionProperty,
190+
model_prop: "ModelWithUnionProperty",
191+
required_model_prop: "ModelWithUnionProperty",
192192
) -> Optional[Union[Any, HTTPValidationError]]:
193193
"""Defaults
194194
@@ -237,8 +237,8 @@ async def asyncio_detailed(
237237
union_prop: Union[float, str] = "not a float",
238238
union_prop_with_ref: Union[AnEnum, None, Unset, float] = 0.6,
239239
enum_prop: AnEnum,
240-
model_prop: ModelWithUnionProperty,
241-
required_model_prop: ModelWithUnionProperty,
240+
model_prop: "ModelWithUnionProperty",
241+
required_model_prop: "ModelWithUnionProperty",
242242
) -> Response[Union[Any, HTTPValidationError]]:
243243
"""Defaults
244244
@@ -292,8 +292,8 @@ async def asyncio(
292292
union_prop: Union[float, str] = "not a float",
293293
union_prop_with_ref: Union[AnEnum, None, Unset, float] = 0.6,
294294
enum_prop: AnEnum,
295-
model_prop: ModelWithUnionProperty,
296-
required_model_prop: ModelWithUnionProperty,
295+
model_prop: "ModelWithUnionProperty",
296+
required_model_prop: "ModelWithUnionProperty",
297297
) -> Optional[Union[Any, HTTPValidationError]]:
298298
"""Defaults
299299

Diff for: end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def _get_kwargs(
6969
}
7070

7171

72-
def _parse_response(*, response: httpx.Response) -> Optional[Union[HTTPValidationError, List[AModel]]]:
72+
def _parse_response(*, response: httpx.Response) -> Optional[Union[HTTPValidationError, List["AModel"]]]:
7373
if response.status_code == HTTPStatus.OK:
7474
response_200 = []
7575
_response_200 = response.json()
@@ -90,7 +90,7 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[HTTPValidatio
9090
return None
9191

9292

93-
def _build_response(*, response: httpx.Response) -> Response[Union[HTTPValidationError, List[AModel]]]:
93+
def _build_response(*, response: httpx.Response) -> Response[Union[HTTPValidationError, List["AModel"]]]:
9494
return Response(
9595
status_code=HTTPStatus(response.status_code),
9696
content=response.content,
@@ -106,7 +106,7 @@ def sync_detailed(
106106
an_enum_value_with_null: List[Optional[AnEnumWithNull]],
107107
an_enum_value_with_only_null: List[None],
108108
some_date: Union[datetime.date, datetime.datetime],
109-
) -> Response[Union[HTTPValidationError, List[AModel]]]:
109+
) -> Response[Union[HTTPValidationError, List["AModel"]]]:
110110
"""Get List
111111
112112
Get a list of things
@@ -118,7 +118,7 @@ def sync_detailed(
118118
some_date (Union[datetime.date, datetime.datetime]):
119119
120120
Returns:
121-
Response[Union[HTTPValidationError, List[AModel]]]
121+
Response[Union[HTTPValidationError, List['AModel']]]
122122
"""
123123

124124
kwargs = _get_kwargs(
@@ -144,7 +144,7 @@ def sync(
144144
an_enum_value_with_null: List[Optional[AnEnumWithNull]],
145145
an_enum_value_with_only_null: List[None],
146146
some_date: Union[datetime.date, datetime.datetime],
147-
) -> Optional[Union[HTTPValidationError, List[AModel]]]:
147+
) -> Optional[Union[HTTPValidationError, List["AModel"]]]:
148148
"""Get List
149149
150150
Get a list of things
@@ -156,7 +156,7 @@ def sync(
156156
some_date (Union[datetime.date, datetime.datetime]):
157157
158158
Returns:
159-
Response[Union[HTTPValidationError, List[AModel]]]
159+
Response[Union[HTTPValidationError, List['AModel']]]
160160
"""
161161

162162
return sync_detailed(
@@ -175,7 +175,7 @@ async def asyncio_detailed(
175175
an_enum_value_with_null: List[Optional[AnEnumWithNull]],
176176
an_enum_value_with_only_null: List[None],
177177
some_date: Union[datetime.date, datetime.datetime],
178-
) -> Response[Union[HTTPValidationError, List[AModel]]]:
178+
) -> Response[Union[HTTPValidationError, List["AModel"]]]:
179179
"""Get List
180180
181181
Get a list of things
@@ -187,7 +187,7 @@ async def asyncio_detailed(
187187
some_date (Union[datetime.date, datetime.datetime]):
188188
189189
Returns:
190-
Response[Union[HTTPValidationError, List[AModel]]]
190+
Response[Union[HTTPValidationError, List['AModel']]]
191191
"""
192192

193193
kwargs = _get_kwargs(
@@ -211,7 +211,7 @@ async def asyncio(
211211
an_enum_value_with_null: List[Optional[AnEnumWithNull]],
212212
an_enum_value_with_only_null: List[None],
213213
some_date: Union[datetime.date, datetime.datetime],
214-
) -> Optional[Union[HTTPValidationError, List[AModel]]]:
214+
) -> Optional[Union[HTTPValidationError, List["AModel"]]]:
215215
"""Get List
216216
217217
Get a list of things
@@ -223,7 +223,7 @@ async def asyncio(
223223
some_date (Union[datetime.date, datetime.datetime]):
224224
225225
Returns:
226-
Response[Union[HTTPValidationError, List[AModel]]]
226+
Response[Union[HTTPValidationError, List['AModel']]]
227227
"""
228228

229229
return (

Diff for: end_to_end_tests/golden-record/my_test_api_client/models/__init__.py

+30
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@
66
from .all_of_sub_model import AllOfSubModel
77
from .all_of_sub_model_type_enum import AllOfSubModelTypeEnum
88
from .an_all_of_enum import AnAllOfEnum
9+
from .an_array_with_a_circular_ref_in_items_object_a_item import AnArrayWithACircularRefInItemsObjectAItem
10+
from .an_array_with_a_circular_ref_in_items_object_additional_properties_a_item import (
11+
AnArrayWithACircularRefInItemsObjectAdditionalPropertiesAItem,
12+
)
13+
from .an_array_with_a_circular_ref_in_items_object_additional_properties_b_item import (
14+
AnArrayWithACircularRefInItemsObjectAdditionalPropertiesBItem,
15+
)
16+
from .an_array_with_a_circular_ref_in_items_object_b_item import AnArrayWithACircularRefInItemsObjectBItem
17+
from .an_array_with_a_recursive_ref_in_items_object_additional_properties_item import (
18+
AnArrayWithARecursiveRefInItemsObjectAdditionalPropertiesItem,
19+
)
20+
from .an_array_with_a_recursive_ref_in_items_object_item import AnArrayWithARecursiveRefInItemsObjectItem
921
from .an_enum import AnEnum
1022
from .an_enum_with_null import AnEnumWithNull
1123
from .an_int_enum import AnIntEnum
@@ -33,10 +45,16 @@
3345
from .model_with_additional_properties_refed import ModelWithAdditionalPropertiesRefed
3446
from .model_with_any_json_properties import ModelWithAnyJsonProperties
3547
from .model_with_any_json_properties_additional_property_type_0 import ModelWithAnyJsonPropertiesAdditionalPropertyType0
48+
from .model_with_circular_ref_a import ModelWithCircularRefA
49+
from .model_with_circular_ref_b import ModelWithCircularRefB
50+
from .model_with_circular_ref_in_additional_properties_a import ModelWithCircularRefInAdditionalPropertiesA
51+
from .model_with_circular_ref_in_additional_properties_b import ModelWithCircularRefInAdditionalPropertiesB
3652
from .model_with_date_time_property import ModelWithDateTimeProperty
3753
from .model_with_primitive_additional_properties import ModelWithPrimitiveAdditionalProperties
3854
from .model_with_primitive_additional_properties_a_date_holder import ModelWithPrimitiveAdditionalPropertiesADateHolder
3955
from .model_with_property_ref import ModelWithPropertyRef
56+
from .model_with_recursive_ref import ModelWithRecursiveRef
57+
from .model_with_recursive_ref_in_additional_properties import ModelWithRecursiveRefInAdditionalProperties
4058
from .model_with_union_property import ModelWithUnionProperty
4159
from .model_with_union_property_inlined import ModelWithUnionPropertyInlined
4260
from .model_with_union_property_inlined_fruit_type_0 import ModelWithUnionPropertyInlinedFruitType0
@@ -58,6 +76,12 @@
5876
"AModel",
5977
"AModelWithPropertiesReferenceThatAreNotObject",
6078
"AnAllOfEnum",
79+
"AnArrayWithACircularRefInItemsObjectAdditionalPropertiesAItem",
80+
"AnArrayWithACircularRefInItemsObjectAdditionalPropertiesBItem",
81+
"AnArrayWithACircularRefInItemsObjectAItem",
82+
"AnArrayWithACircularRefInItemsObjectBItem",
83+
"AnArrayWithARecursiveRefInItemsObjectAdditionalPropertiesItem",
84+
"AnArrayWithARecursiveRefInItemsObjectItem",
6185
"AnEnum",
6286
"AnEnumWithNull",
6387
"AnIntEnum",
@@ -83,10 +107,16 @@
83107
"ModelWithAdditionalPropertiesRefed",
84108
"ModelWithAnyJsonProperties",
85109
"ModelWithAnyJsonPropertiesAdditionalPropertyType0",
110+
"ModelWithCircularRefA",
111+
"ModelWithCircularRefB",
112+
"ModelWithCircularRefInAdditionalPropertiesA",
113+
"ModelWithCircularRefInAdditionalPropertiesB",
86114
"ModelWithDateTimeProperty",
87115
"ModelWithPrimitiveAdditionalProperties",
88116
"ModelWithPrimitiveAdditionalPropertiesADateHolder",
89117
"ModelWithPropertyRef",
118+
"ModelWithRecursiveRef",
119+
"ModelWithRecursiveRefInAdditionalProperties",
90120
"ModelWithUnionProperty",
91121
"ModelWithUnionPropertyInlined",
92122
"ModelWithUnionPropertyInlinedFruitType0",

Diff for: end_to_end_tests/golden-record/my_test_api_client/models/a_model.py

+30-21
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import datetime
2-
from typing import Any, Dict, List, Optional, Type, TypeVar, Union, cast
2+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, TypeVar, Union, cast
33

44
import attr
55
from dateutil.parser import isoparse
66

77
from ..models.an_all_of_enum import AnAllOfEnum
88
from ..models.an_enum import AnEnum
99
from ..models.different_enum import DifferentEnum
10-
from ..models.free_form_model import FreeFormModel
11-
from ..models.model_with_union_property import ModelWithUnionProperty
1210
from ..types import UNSET, Unset
1311

12+
if TYPE_CHECKING:
13+
from ..models.free_form_model import FreeFormModel
14+
from ..models.model_with_union_property import ModelWithUnionProperty
15+
16+
1417
T = TypeVar("T", bound="AModel")
1518

1619

@@ -24,7 +27,7 @@ class AModel:
2427
a_camel_date_time (Union[datetime.date, datetime.datetime]):
2528
a_date (datetime.date):
2629
required_not_nullable (str):
27-
one_of_models (Union[Any, FreeFormModel, ModelWithUnionProperty]):
30+
one_of_models (Union['FreeFormModel', 'ModelWithUnionProperty', Any]):
2831
model (ModelWithUnionProperty):
2932
any_value (Union[Unset, Any]):
3033
an_optional_allof_enum (Union[Unset, AnAllOfEnum]):
@@ -35,9 +38,9 @@ class AModel:
3538
required_nullable (Optional[str]):
3639
not_required_nullable (Union[Unset, None, str]):
3740
not_required_not_nullable (Union[Unset, str]):
38-
nullable_one_of_models (Union[FreeFormModel, ModelWithUnionProperty, None]):
39-
not_required_one_of_models (Union[FreeFormModel, ModelWithUnionProperty, Unset]):
40-
not_required_nullable_one_of_models (Union[FreeFormModel, ModelWithUnionProperty, None, Unset, str]):
41+
nullable_one_of_models (Union['FreeFormModel', 'ModelWithUnionProperty', None]):
42+
not_required_one_of_models (Union['FreeFormModel', 'ModelWithUnionProperty', Unset]):
43+
not_required_nullable_one_of_models (Union['FreeFormModel', 'ModelWithUnionProperty', None, Unset, str]):
4144
nullable_model (Optional[ModelWithUnionProperty]):
4245
not_required_model (Union[Unset, ModelWithUnionProperty]):
4346
not_required_nullable_model (Union[Unset, None, ModelWithUnionProperty]):
@@ -47,12 +50,12 @@ class AModel:
4750
a_camel_date_time: Union[datetime.date, datetime.datetime]
4851
a_date: datetime.date
4952
required_not_nullable: str
50-
one_of_models: Union[Any, FreeFormModel, ModelWithUnionProperty]
51-
model: ModelWithUnionProperty
53+
one_of_models: Union["FreeFormModel", "ModelWithUnionProperty", Any]
54+
model: "ModelWithUnionProperty"
5255
a_nullable_date: Optional[datetime.date]
5356
required_nullable: Optional[str]
54-
nullable_one_of_models: Union[FreeFormModel, ModelWithUnionProperty, None]
55-
nullable_model: Optional[ModelWithUnionProperty]
57+
nullable_one_of_models: Union["FreeFormModel", "ModelWithUnionProperty", None]
58+
nullable_model: Optional["ModelWithUnionProperty"]
5659
an_allof_enum_with_overridden_default: AnAllOfEnum = AnAllOfEnum.OVERRIDDEN_DEFAULT
5760
any_value: Union[Unset, Any] = UNSET
5861
an_optional_allof_enum: Union[Unset, AnAllOfEnum] = UNSET
@@ -61,12 +64,15 @@ class AModel:
6164
attr_1_leading_digit: Union[Unset, str] = UNSET
6265
not_required_nullable: Union[Unset, None, str] = UNSET
6366
not_required_not_nullable: Union[Unset, str] = UNSET
64-
not_required_one_of_models: Union[FreeFormModel, ModelWithUnionProperty, Unset] = UNSET
65-
not_required_nullable_one_of_models: Union[FreeFormModel, ModelWithUnionProperty, None, Unset, str] = UNSET
66-
not_required_model: Union[Unset, ModelWithUnionProperty] = UNSET
67-
not_required_nullable_model: Union[Unset, None, ModelWithUnionProperty] = UNSET
67+
not_required_one_of_models: Union["FreeFormModel", "ModelWithUnionProperty", Unset] = UNSET
68+
not_required_nullable_one_of_models: Union["FreeFormModel", "ModelWithUnionProperty", None, Unset, str] = UNSET
69+
not_required_model: Union[Unset, "ModelWithUnionProperty"] = UNSET
70+
not_required_nullable_model: Union[Unset, None, "ModelWithUnionProperty"] = UNSET
6871

6972
def to_dict(self) -> Dict[str, Any]:
73+
from ..models.free_form_model import FreeFormModel
74+
from ..models.model_with_union_property import ModelWithUnionProperty
75+
7076
an_enum_value = self.an_enum_value.value
7177

7278
an_allof_enum_with_overridden_default = self.an_allof_enum_with_overridden_default.value
@@ -218,6 +224,9 @@ def to_dict(self) -> Dict[str, Any]:
218224

219225
@classmethod
220226
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
227+
from ..models.free_form_model import FreeFormModel
228+
from ..models.model_with_union_property import ModelWithUnionProperty
229+
221230
d = src_dict.copy()
222231
an_enum_value = AnEnum(d.pop("an_enum_value"))
223232

@@ -244,7 +253,7 @@ def _parse_a_camel_date_time(data: object) -> Union[datetime.date, datetime.date
244253

245254
required_not_nullable = d.pop("required_not_nullable")
246255

247-
def _parse_one_of_models(data: object) -> Union[Any, FreeFormModel, ModelWithUnionProperty]:
256+
def _parse_one_of_models(data: object) -> Union["FreeFormModel", "ModelWithUnionProperty", Any]:
248257
try:
249258
if not isinstance(data, dict):
250259
raise TypeError()
@@ -261,7 +270,7 @@ def _parse_one_of_models(data: object) -> Union[Any, FreeFormModel, ModelWithUni
261270
return one_of_models_type_1
262271
except: # noqa: E722
263272
pass
264-
return cast(Union[Any, FreeFormModel, ModelWithUnionProperty], data)
273+
return cast(Union["FreeFormModel", "ModelWithUnionProperty", Any], data)
265274

266275
one_of_models = _parse_one_of_models(d.pop("one_of_models"))
267276

@@ -310,7 +319,7 @@ def _parse_one_of_models(data: object) -> Union[Any, FreeFormModel, ModelWithUni
310319

311320
not_required_not_nullable = d.pop("not_required_not_nullable", UNSET)
312321

313-
def _parse_nullable_one_of_models(data: object) -> Union[FreeFormModel, ModelWithUnionProperty, None]:
322+
def _parse_nullable_one_of_models(data: object) -> Union["FreeFormModel", "ModelWithUnionProperty", None]:
314323
if data is None:
315324
return data
316325
try:
@@ -329,7 +338,7 @@ def _parse_nullable_one_of_models(data: object) -> Union[FreeFormModel, ModelWit
329338

330339
nullable_one_of_models = _parse_nullable_one_of_models(d.pop("nullable_one_of_models"))
331340

332-
def _parse_not_required_one_of_models(data: object) -> Union[FreeFormModel, ModelWithUnionProperty, Unset]:
341+
def _parse_not_required_one_of_models(data: object) -> Union["FreeFormModel", "ModelWithUnionProperty", Unset]:
333342
if isinstance(data, Unset):
334343
return data
335344
try:
@@ -360,7 +369,7 @@ def _parse_not_required_one_of_models(data: object) -> Union[FreeFormModel, Mode
360369

361370
def _parse_not_required_nullable_one_of_models(
362371
data: object,
363-
) -> Union[FreeFormModel, ModelWithUnionProperty, None, Unset, str]:
372+
) -> Union["FreeFormModel", "ModelWithUnionProperty", None, Unset, str]:
364373
if data is None:
365374
return data
366375
if isinstance(data, Unset):
@@ -395,7 +404,7 @@ def _parse_not_required_nullable_one_of_models(
395404
return not_required_nullable_one_of_models_type_1
396405
except: # noqa: E722
397406
pass
398-
return cast(Union[FreeFormModel, ModelWithUnionProperty, None, Unset, str], data)
407+
return cast(Union["FreeFormModel", "ModelWithUnionProperty", None, Unset, str], data)
399408

400409
not_required_nullable_one_of_models = _parse_not_required_nullable_one_of_models(
401410
d.pop("not_required_nullable_one_of_models", UNSET)

0 commit comments

Comments
 (0)