Skip to content

Commit 0882e49

Browse files
authored
Merge branch 'main' into dev
2 parents 1a33411 + d535bd0 commit 0882e49

38 files changed

+365
-165
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## 0.8.0 - Unreleased
99

10+
### Breaking Changes
11+
12+
- Generated clients will no longer pass through `None` to query parameters. Previously, any query params set to `None` would surface as empty strings (per the default behavior of `httpx`). This is contrary to the defaults indicated by the OpenAPI 3.0.3 spec. Ommitting these parameters makes us more compliant. If you require a style of `null` to be passed to your query parameters, please request support for the OpenAPI "style" attribute. Thank you to @forest-benchling and @bowenwr for a ton of input on this.
13+
1014
### Additions
1115

1216
- New `--meta` command line option for specifying what type of metadata should be generated:
@@ -17,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1721
- Attempt to detect and alert users if they are using an unsupported version of OpenAPI (#281).
1822
- Fixes `Enum` deserialization when the value is `UNSET`.
1923
- Add handling of application/vnd.api+json media type.
24+
- Support passing models into query parameters (#316). Thanks @forest-benchling!
2025

2126
### Changes
2227

@@ -26,7 +31,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2631

2732
### Fixes
2833

34+
- Endpoint tags are now sanitized during parsing to fix an issue where `My Tag` and `MyTag` are seen as two different tags but are then later unified, causing errors when creating directories. Thanks @p1-ra! (#328)
35+
- Parser will softly ignore value error during schema responses' status code convertion from string to integer (not a number). Errors will be reported to the end user and parsing will continue to proceed (#327).
2936
- The generated `from_dict` and `to_dict` methods of models will now properly handle `nullable` and `not required` properties that are themselves generated models (#315). Thanks @forest-benchling!
37+
- Fix deserialization of `None` and `Unset` properties for all types by unifying the checks (#334). Thanks @forest-benchling!
38+
- If duplicate model names are detected during generation, you'll now get an error message instead of broken code (#336). Thanks @forest-benchling!
3039

3140
## 0.7.3 - 2020-12-21
3241

end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from ...models.an_enum import AnEnum
1515
from ...models.http_validation_error import HTTPValidationError
16+
from ...models.model_with_union_property import ModelWithUnionProperty
1617
from ...types import UNSET, Unset
1718

1819

@@ -50,6 +51,8 @@ def httpx_request(
5051
union_prop: Union[Unset, float, str] = "not a float",
5152
union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6,
5253
enum_prop: Union[Unset, AnEnum] = UNSET,
54+
model_prop: Union[ModelWithUnionProperty, Unset] = UNSET,
55+
required_model_prop: ModelWithUnionProperty,
5356
) -> Response[Union[None, HTTPValidationError]]:
5457

5558
json_datetime_prop: Union[Unset, str] = UNSET
@@ -89,27 +92,28 @@ def httpx_request(
8992
if not isinstance(enum_prop, Unset):
9093
json_enum_prop = enum_prop
9194

92-
params: Dict[str, Any] = {}
93-
if string_prop is not UNSET:
94-
params["string_prop"] = string_prop
95-
if datetime_prop is not UNSET:
96-
params["datetime_prop"] = json_datetime_prop
97-
if date_prop is not UNSET:
98-
params["date_prop"] = json_date_prop
99-
if float_prop is not UNSET:
100-
params["float_prop"] = float_prop
101-
if int_prop is not UNSET:
102-
params["int_prop"] = int_prop
103-
if boolean_prop is not UNSET:
104-
params["boolean_prop"] = boolean_prop
105-
if list_prop is not UNSET:
106-
params["list_prop"] = json_list_prop
107-
if union_prop is not UNSET:
108-
params["union_prop"] = json_union_prop
109-
if union_prop_with_ref is not UNSET:
110-
params["union_prop_with_ref"] = json_union_prop_with_ref
111-
if enum_prop is not UNSET:
112-
params["enum_prop"] = json_enum_prop
95+
json_model_prop: Union[Unset, Dict[str, Any]] = UNSET
96+
if not isinstance(model_prop, Unset):
97+
json_model_prop = model_prop.to_dict()
98+
99+
json_required_model_prop = required_model_prop.to_dict()
100+
101+
params: Dict[str, Any] = {
102+
"string_prop": string_prop,
103+
"datetime_prop": json_datetime_prop,
104+
"date_prop": json_date_prop,
105+
"float_prop": float_prop,
106+
"int_prop": int_prop,
107+
"boolean_prop": boolean_prop,
108+
"list_prop": json_list_prop,
109+
"union_prop": json_union_prop,
110+
"union_prop_with_ref": json_union_prop_with_ref,
111+
"enum_prop": json_enum_prop,
112+
}
113+
if not isinstance(json_model_prop, Unset):
114+
params.update(json_model_prop)
115+
params.update(json_required_model_prop)
116+
params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
113117

114118
response = client.request(
115119
"post",

end_to_end_tests/golden-record-custom/custom_e2e/api/tests/get_user_list.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def httpx_request(
6262
"an_enum_value": json_an_enum_value,
6363
"some_date": json_some_date,
6464
}
65+
params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
6566

6667
response = client.request(
6768
"get",

end_to_end_tests/golden-record-custom/custom_e2e/api/tests/int_enum_tests_int_enum_post.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def httpx_request(
4444
params: Dict[str, Any] = {
4545
"int_enum": json_int_enum,
4646
}
47+
params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
4748

4849
response = client.request(
4950
"post",

end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ def httpx_request(
4343
if not isinstance(query_param, Unset):
4444
json_query_param = query_param
4545

46-
params: Dict[str, Any] = {}
47-
if query_param is not UNSET:
48-
params["query_param"] = json_query_param
46+
params: Dict[str, Any] = {
47+
"query_param": json_query_param,
48+
}
49+
params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
4950

5051
response = client.request(
5152
"get",

end_to_end_tests/golden-record-custom/custom_e2e/api/tests/upload_file_tests_upload_post.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[
2424
if response.status_code == 422:
2525
response_422 = HTTPValidationError.from_dict(response.json())
2626

27+
28+
2729
return response_422
2830
return None
2931

end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import datetime
2-
from typing import Any, Dict, List, Optional, Type, TypeVar, Union, cast
2+
from typing import Any, Dict, List, Optional, Type, TypeVar, Union
33

44
import attr
55
from dateutil.parser import isoparse
@@ -28,6 +28,7 @@ class AModel:
2828
required_nullable: Optional[str]
2929
nullable_model: Optional[AModelNullableModel]
3030
nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET
31+
a_not_required_date: Union[Unset, datetime.date] = UNSET
3132
attr_1_leading_digit: Union[Unset, str] = UNSET
3233
not_required_nullable: Union[Unset, Optional[str]] = UNSET
3334
not_required_not_nullable: Union[Unset, str] = UNSET
@@ -60,6 +61,10 @@ def to_dict(self) -> Dict[str, Any]:
6061
nested_list_of_enums.append(nested_list_of_enums_item)
6162

6263
a_nullable_date = self.a_nullable_date.isoformat() if self.a_nullable_date else None
64+
a_not_required_date: Union[Unset, str] = UNSET
65+
if not isinstance(self.a_not_required_date, Unset):
66+
a_not_required_date = self.a_not_required_date.isoformat()
67+
6368
attr_1_leading_digit = self.attr_1_leading_digit
6469
required_nullable = self.required_nullable
6570
not_required_nullable = self.not_required_nullable
@@ -91,6 +96,8 @@ def to_dict(self) -> Dict[str, Any]:
9196
)
9297
if nested_list_of_enums is not UNSET:
9398
field_dict["nested_list_of_enums"] = nested_list_of_enums
99+
if a_not_required_date is not UNSET:
100+
field_dict["a_not_required_date"] = a_not_required_date
94101
if attr_1_leading_digit is not UNSET:
95102
field_dict["1_leading_digit"] = attr_1_leading_digit
96103
if not_required_nullable is not UNSET:
@@ -145,7 +152,12 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat
145152
a_nullable_date = None
146153
_a_nullable_date = d.pop("a_nullable_date")
147154
if _a_nullable_date is not None:
148-
a_nullable_date = isoparse(cast(str, _a_nullable_date)).date()
155+
a_nullable_date = isoparse(_a_nullable_date).date()
156+
157+
a_not_required_date: Union[Unset, datetime.date] = UNSET
158+
_a_not_required_date = d.pop("a_not_required_date", UNSET)
159+
if not isinstance(_a_not_required_date, Unset):
160+
a_not_required_date = isoparse(_a_not_required_date).date()
149161

150162
attr_1_leading_digit = d.pop("1_leading_digit", UNSET)
151163

@@ -158,19 +170,17 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat
158170
nullable_model = None
159171
_nullable_model = d.pop("nullable_model")
160172
if _nullable_model is not None:
161-
nullable_model = AModelNullableModel.from_dict(cast(Dict[str, Any], _nullable_model))
173+
nullable_model = AModelNullableModel.from_dict(_nullable_model)
162174

163175
not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET
164176
_not_required_model = d.pop("not_required_model", UNSET)
165177
if not isinstance(_not_required_model, Unset):
166-
not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model))
178+
not_required_model = AModelNotRequiredModel.from_dict(_not_required_model)
167179

168180
not_required_nullable_model = None
169181
_not_required_nullable_model = d.pop("not_required_nullable_model", UNSET)
170182
if _not_required_nullable_model is not None and not isinstance(_not_required_nullable_model, Unset):
171-
not_required_nullable_model = AModelNotRequiredNullableModel.from_dict(
172-
cast(Dict[str, Any], _not_required_nullable_model)
173-
)
183+
not_required_nullable_model = AModelNotRequiredNullableModel.from_dict(_not_required_nullable_model)
174184

175185
a_model = cls(
176186
an_enum_value=an_enum_value,
@@ -180,6 +190,7 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat
180190
model=model,
181191
nested_list_of_enums=nested_list_of_enums,
182192
a_nullable_date=a_nullable_date,
193+
a_not_required_date=a_not_required_date,
183194
attr_1_leading_digit=attr_1_leading_digit,
184195
required_nullable=required_nullable,
185196
not_required_nullable=not_required_nullable,

end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Dict, List, Type, TypeVar, Union, cast
1+
from typing import Any, Dict, List, Type, TypeVar, Union
22

33
import attr
44

@@ -36,9 +36,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
3636
a_date_holder: Union[ModelWithPrimitiveAdditionalPropertiesADateHolder, Unset] = UNSET
3737
_a_date_holder = d.pop("a_date_holder", UNSET)
3838
if not isinstance(_a_date_holder, Unset):
39-
a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict(
40-
cast(Dict[str, Any], _a_date_holder)
41-
)
39+
a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict(_a_date_holder)
4240

4341
model_with_primitive_additional_properties = cls(
4442
a_date_holder=a_date_holder,

end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@ def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]:
4646
try:
4747
a_property = UNSET
4848
_a_property = data
49-
if _a_property is not None and _a_property is not UNSET:
49+
if not isinstance(_a_property, Unset):
5050
a_property = AnEnum(_a_property)
5151

5252
return a_property
5353
except: # noqa: E722
5454
pass
5555
a_property = UNSET
5656
_a_property = data
57-
if _a_property is not None and _a_property is not UNSET:
57+
if not isinstance(_a_property, Unset):
5858
a_property = AnIntEnum(_a_property)
5959

6060
return a_property

end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from ...client import Client
88
from ...models.an_enum import AnEnum
99
from ...models.http_validation_error import HTTPValidationError
10+
from ...models.model_with_union_property import ModelWithUnionProperty
1011
from ...types import UNSET, Response, Unset
1112

1213

@@ -23,6 +24,8 @@ def _get_kwargs(
2324
union_prop: Union[Unset, float, str] = "not a float",
2425
union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6,
2526
enum_prop: Union[Unset, AnEnum] = UNSET,
27+
model_prop: Union[ModelWithUnionProperty, Unset] = UNSET,
28+
required_model_prop: ModelWithUnionProperty,
2629
) -> Dict[str, Any]:
2730
url = "{}/tests/defaults".format(client.base_url)
2831

@@ -66,27 +69,28 @@ def _get_kwargs(
6669
if not isinstance(enum_prop, Unset):
6770
json_enum_prop = enum_prop
6871

69-
params: Dict[str, Any] = {}
70-
if string_prop is not UNSET:
71-
params["string_prop"] = string_prop
72-
if datetime_prop is not UNSET:
73-
params["datetime_prop"] = json_datetime_prop
74-
if date_prop is not UNSET:
75-
params["date_prop"] = json_date_prop
76-
if float_prop is not UNSET:
77-
params["float_prop"] = float_prop
78-
if int_prop is not UNSET:
79-
params["int_prop"] = int_prop
80-
if boolean_prop is not UNSET:
81-
params["boolean_prop"] = boolean_prop
82-
if list_prop is not UNSET:
83-
params["list_prop"] = json_list_prop
84-
if union_prop is not UNSET:
85-
params["union_prop"] = json_union_prop
86-
if union_prop_with_ref is not UNSET:
87-
params["union_prop_with_ref"] = json_union_prop_with_ref
88-
if enum_prop is not UNSET:
89-
params["enum_prop"] = json_enum_prop
72+
json_model_prop: Union[Unset, Dict[str, Any]] = UNSET
73+
if not isinstance(model_prop, Unset):
74+
json_model_prop = model_prop.to_dict()
75+
76+
json_required_model_prop = required_model_prop.to_dict()
77+
78+
params: Dict[str, Any] = {
79+
"string_prop": string_prop,
80+
"datetime_prop": json_datetime_prop,
81+
"date_prop": json_date_prop,
82+
"float_prop": float_prop,
83+
"int_prop": int_prop,
84+
"boolean_prop": boolean_prop,
85+
"list_prop": json_list_prop,
86+
"union_prop": json_union_prop,
87+
"union_prop_with_ref": json_union_prop_with_ref,
88+
"enum_prop": json_enum_prop,
89+
}
90+
if not isinstance(json_model_prop, Unset):
91+
params.update(json_model_prop)
92+
params.update(json_required_model_prop)
93+
params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
9094

9195
return {
9296
"url": url,
@@ -131,6 +135,8 @@ def sync_detailed(
131135
union_prop: Union[Unset, float, str] = "not a float",
132136
union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6,
133137
enum_prop: Union[Unset, AnEnum] = UNSET,
138+
model_prop: Union[ModelWithUnionProperty, Unset] = UNSET,
139+
required_model_prop: ModelWithUnionProperty,
134140
) -> Response[Union[None, HTTPValidationError]]:
135141
kwargs = _get_kwargs(
136142
client=client,
@@ -144,6 +150,8 @@ def sync_detailed(
144150
union_prop=union_prop,
145151
union_prop_with_ref=union_prop_with_ref,
146152
enum_prop=enum_prop,
153+
model_prop=model_prop,
154+
required_model_prop=required_model_prop,
147155
)
148156

149157
response = httpx.post(
@@ -166,6 +174,8 @@ def sync(
166174
union_prop: Union[Unset, float, str] = "not a float",
167175
union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6,
168176
enum_prop: Union[Unset, AnEnum] = UNSET,
177+
model_prop: Union[ModelWithUnionProperty, Unset] = UNSET,
178+
required_model_prop: ModelWithUnionProperty,
169179
) -> Optional[Union[None, HTTPValidationError]]:
170180
""" """
171181

@@ -181,6 +191,8 @@ def sync(
181191
union_prop=union_prop,
182192
union_prop_with_ref=union_prop_with_ref,
183193
enum_prop=enum_prop,
194+
model_prop=model_prop,
195+
required_model_prop=required_model_prop,
184196
).parsed
185197

186198

@@ -197,6 +209,8 @@ async def asyncio_detailed(
197209
union_prop: Union[Unset, float, str] = "not a float",
198210
union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6,
199211
enum_prop: Union[Unset, AnEnum] = UNSET,
212+
model_prop: Union[ModelWithUnionProperty, Unset] = UNSET,
213+
required_model_prop: ModelWithUnionProperty,
200214
) -> Response[Union[None, HTTPValidationError]]:
201215
kwargs = _get_kwargs(
202216
client=client,
@@ -210,6 +224,8 @@ async def asyncio_detailed(
210224
union_prop=union_prop,
211225
union_prop_with_ref=union_prop_with_ref,
212226
enum_prop=enum_prop,
227+
model_prop=model_prop,
228+
required_model_prop=required_model_prop,
213229
)
214230

215231
async with httpx.AsyncClient() as _client:
@@ -231,6 +247,8 @@ async def asyncio(
231247
union_prop: Union[Unset, float, str] = "not a float",
232248
union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6,
233249
enum_prop: Union[Unset, AnEnum] = UNSET,
250+
model_prop: Union[ModelWithUnionProperty, Unset] = UNSET,
251+
required_model_prop: ModelWithUnionProperty,
234252
) -> Optional[Union[None, HTTPValidationError]]:
235253
""" """
236254

@@ -247,5 +265,7 @@ async def asyncio(
247265
union_prop=union_prop,
248266
union_prop_with_ref=union_prop_with_ref,
249267
enum_prop=enum_prop,
268+
model_prop=model_prop,
269+
required_model_prop=required_model_prop,
250270
)
251271
).parsed

0 commit comments

Comments
 (0)