Skip to content

Commit 7de3a02

Browse files
committed
Add support for Unions (anyOf)
- Will now parse "anyOf" in a schema to create a Union with appropriate sub-types. - Refactored property templates. They now each contain two macros: `construct` replaces the previous constructor template `template`. `transform` replaces old Python functions name `transform`. - Add some basic error handling when parsing fails.
1 parent 703d3b4 commit 7de3a02

31 files changed

+509
-200
lines changed

.run/tests.test_end_to_end.regen_golden_master.run.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<env name="PYTHONUNBUFFERED" value="1" />
88
</envs>
99
<option name="SDK_HOME" value="" />
10-
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/../end_to_end_tests" />
10+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/end_to_end_tests" />
1111
<option name="IS_MODULE_SDK" value="true" />
1212
<option name="ADD_CONTENT_ROOTS" value="true" />
1313
<option name="ADD_SOURCE_ROOTS" value="true" />

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
- Support for binary format strings (file payloads)
1818
- Support for multipart/form bodies
1919
- Support for any supported property within a list (array), including other lists.
20+
- Support for Union types ("anyOf" in OpenAPI document)
21+
- Better error messages when failing to parse an OpenAPI document
2022

2123
### Changes
2224
- The way most imports are handled was changed which *should* lead to fewer unused imports in generated files.

end_to_end_tests/fastapi_app/__init__.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from datetime import date, datetime
44
from enum import Enum
55
from pathlib import Path
6-
from typing import List
6+
from typing import List, Union
77

88
from fastapi import APIRouter, FastAPI, File, Query, UploadFile
99
from pydantic import BaseModel
@@ -42,14 +42,12 @@ class AModel(BaseModel):
4242

4343
an_enum_value: AnEnum
4444
nested_list_of_enums: List[List[AnEnum]]
45-
aCamelDateTime: datetime
45+
aCamelDateTime: Union[datetime, date]
4646
a_date: date
4747

4848

4949
@test_router.get("/", response_model=List[AModel], operation_id="getUserList")
50-
def get_list(
51-
an_enum_value: List[AnEnum] = Query(...), some_date: date = Query(...), some_datetime: datetime = Query(...)
52-
):
50+
def get_list(an_enum_value: List[AnEnum] = Query(...), some_date: Union[date, datetime] = Query(...)):
5351
""" Get a list of things """
5452
return
5553

end_to_end_tests/fastapi_app/openapi.json

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,19 @@
5353
"required": true,
5454
"schema": {
5555
"title": "Some Date",
56-
"type": "string",
57-
"format": "date"
56+
"anyOf": [
57+
{
58+
"type": "string",
59+
"format": "date"
60+
},
61+
{
62+
"type": "string",
63+
"format": "date-time"
64+
}
65+
]
5866
},
5967
"name": "some_date",
6068
"in": "query"
61-
},
62-
{
63-
"required": true,
64-
"schema": {
65-
"title": "Some Datetime",
66-
"type": "string",
67-
"format": "date-time"
68-
},
69-
"name": "some_datetime",
70-
"in": "query"
7169
}
7270
],
7371
"responses": {
@@ -173,8 +171,16 @@
173171
},
174172
"aCamelDateTime": {
175173
"title": "Acameldatetime",
176-
"type": "string",
177-
"format": "date-time"
174+
"anyOf": [
175+
{
176+
"type": "string",
177+
"format": "date-time"
178+
},
179+
{
180+
"type": "string",
181+
"format": "date"
182+
}
183+
]
178184
},
179185
"a_date": {
180186
"title": "A Date",

end_to_end_tests/golden-master/my_test_api_client/api/users.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,28 @@
1313

1414

1515
def get_user_list(
16-
*, client: Client, an_enum_value: List[AnEnumValueItem], some_date: date, some_datetime: datetime,
16+
*, client: Client, an_enum_value: List[AnEnumValueItem], some_date: Union[date, datetime],
1717
) -> Union[
1818
List[AModel], HTTPValidationError,
1919
]:
2020
""" Get a list of things """
2121
url = "{}/tests/".format(client.base_url)
2222

23+
json_an_enum_value = []
24+
for an_enum_value_item_data in an_enum_value:
25+
an_enum_value_item = an_enum_value_item_data.value
26+
27+
json_an_enum_value.append(an_enum_value_item)
28+
29+
if isinstance(some_date, date):
30+
json_some_date = some_date.isoformat()
31+
32+
else:
33+
json_some_date = some_date.isoformat()
34+
2335
params = {
24-
"an_enum_value": an_enum_value,
25-
"some_date": some_date.isoformat(),
26-
"some_datetime": some_datetime.isoformat(),
36+
"an_enum_value": json_an_enum_value,
37+
"some_date": json_some_date,
2738
}
2839

2940
response = httpx.get(url=url, headers=client.get_headers(), params=params,)

end_to_end_tests/golden-master/my_test_api_client/async_api/users.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,28 @@
1313

1414

1515
async def get_user_list(
16-
*, client: Client, an_enum_value: List[AnEnumValueItem], some_date: date, some_datetime: datetime,
16+
*, client: Client, an_enum_value: List[AnEnumValueItem], some_date: Union[date, datetime],
1717
) -> Union[
1818
List[AModel], HTTPValidationError,
1919
]:
2020
""" Get a list of things """
2121
url = "{}/tests/".format(client.base_url)
2222

23+
json_an_enum_value = []
24+
for an_enum_value_item_data in an_enum_value:
25+
an_enum_value_item = an_enum_value_item_data.value
26+
27+
json_an_enum_value.append(an_enum_value_item)
28+
29+
if isinstance(some_date, date):
30+
json_some_date = some_date.isoformat()
31+
32+
else:
33+
json_some_date = some_date.isoformat()
34+
2335
params = {
24-
"an_enum_value": an_enum_value,
25-
"some_date": some_date.isoformat(),
26-
"some_datetime": some_datetime.isoformat(),
36+
"an_enum_value": json_an_enum_value,
37+
"some_date": json_some_date,
2738
}
2839

2940
async with httpx.AsyncClient() as _client:

end_to_end_tests/golden-master/my_test_api_client/models/a_model.py

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from dataclasses import dataclass
44
from datetime import date, datetime
5-
from typing import Any, Dict, List, cast
5+
from typing import Any, Dict, List, Union, cast
66

77
from .an_enum_value import AnEnumValue
88
from .nested_list_of_enums_item_item import NestedListOfEnumsItemItem
@@ -14,15 +14,35 @@ class AModel:
1414

1515
an_enum_value: AnEnumValue
1616
nested_list_of_enums: List[List[NestedListOfEnumsItemItem]]
17-
a_camel_date_time: datetime
17+
a_camel_date_time: Union[datetime, date]
1818
a_date: date
1919

2020
def to_dict(self) -> Dict[str, Any]:
21+
an_enum_value = self.an_enum_value.value
22+
23+
nested_list_of_enums = []
24+
for nested_list_of_enums_item_data in self.nested_list_of_enums:
25+
nested_list_of_enums_item = []
26+
for nested_list_of_enums_item_item_data in nested_list_of_enums_item_data:
27+
nested_list_of_enums_item_item = nested_list_of_enums_item_item_data.value
28+
29+
nested_list_of_enums_item.append(nested_list_of_enums_item_item)
30+
31+
nested_list_of_enums.append(nested_list_of_enums_item)
32+
33+
if isinstance(self.a_camel_date_time, datetime):
34+
a_camel_date_time = self.a_camel_date_time.isoformat()
35+
36+
else:
37+
a_camel_date_time = self.a_camel_date_time.isoformat()
38+
39+
a_date = self.a_date.isoformat()
40+
2141
return {
22-
"an_enum_value": self.an_enum_value.value,
23-
"nested_list_of_enums": self.nested_list_of_enums,
24-
"aCamelDateTime": self.a_camel_date_time.isoformat(),
25-
"a_date": self.a_date.isoformat(),
42+
"an_enum_value": an_enum_value,
43+
"nested_list_of_enums": nested_list_of_enums,
44+
"aCamelDateTime": a_camel_date_time,
45+
"a_date": a_date,
2646
}
2747

2848
@staticmethod
@@ -39,7 +59,19 @@ def from_dict(d: Dict[str, Any]) -> AModel:
3959

4060
nested_list_of_enums.append(nested_list_of_enums_item)
4161

42-
a_camel_date_time = datetime.fromisoformat(d["aCamelDateTime"])
62+
def _parse_a_camel_date_time(data: Dict[str, Any]) -> Union[datetime, date]:
63+
a_camel_date_time: Union[datetime, date]
64+
try:
65+
a_camel_date_time = datetime.fromisoformat(d["aCamelDateTime"])
66+
67+
return a_camel_date_time
68+
except:
69+
pass
70+
a_camel_date_time = date.fromisoformat(d["aCamelDateTime"])
71+
72+
return a_camel_date_time
73+
74+
a_camel_date_time = _parse_a_camel_date_time(d["aCamelDateTime"])
4375

4476
a_date = date.fromisoformat(d["a_date"])
4577

end_to_end_tests/golden-master/my_test_api_client/models/abc_response.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ class ABCResponse:
1111
success: bool
1212

1313
def to_dict(self) -> Dict[str, Any]:
14+
success = self.success
15+
1416
return {
15-
"success": self.success,
17+
"success": success,
1618
}
1719

1820
@staticmethod

end_to_end_tests/golden-master/my_test_api_client/models/body_upload_file_tests_upload_post.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ class BodyUploadFileTestsUploadPost:
1313
some_file: File
1414

1515
def to_dict(self) -> Dict[str, Any]:
16+
some_file = self.some_file.to_tuple()
17+
1618
return {
17-
"some_file": self.some_file.to_tuple(),
19+
"some_file": some_file,
1820
}
1921

2022
@staticmethod

end_to_end_tests/golden-master/my_test_api_client/models/http_validation_error.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,17 @@ class HTTPValidationError:
1313
detail: Optional[List[ValidationError]] = None
1414

1515
def to_dict(self) -> Dict[str, Any]:
16+
if self.detail is None:
17+
detail = None
18+
else:
19+
detail = []
20+
for detail_item_data in self.detail:
21+
detail_item = detail_item_data.to_dict()
22+
23+
detail.append(detail_item)
24+
1625
return {
17-
"detail": self.detail if self.detail is not None else None,
26+
"detail": detail,
1827
}
1928

2029
@staticmethod

0 commit comments

Comments
 (0)