Skip to content

Commit 9056e92

Browse files
committed
fix bug in type generation for nullable props BNCH-111776
1 parent 847d5a6 commit 9056e92

File tree

14 files changed

+155
-84
lines changed

14 files changed

+155
-84
lines changed

end_to_end_tests/functional_tests/generated_code_execution/test_enums_and_consts.py

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,28 +152,70 @@ def test_invalid_values(self, MyModel):
152152
""")
153153
@with_generated_code_imports(
154154
".models.MyEnum",
155-
".models.MyEnumIncludingNullType1", # see comment in test_nullable_enum_prop
155+
".models.MyEnumIncludingNull",
156156
".models.MyModel",
157157
".types.Unset",
158158
)
159159
class TestNullableEnums:
160-
def test_nullable_enum_prop(self, MyModel, MyEnum, MyEnumIncludingNullType1):
161-
# Note, MyEnumIncludingNullType1 should be named just MyEnumIncludingNull -
162-
# known bug: https://github.com/openapi-generators/openapi-python-client/issues/1120
160+
def test_nullable_enum_prop(self, MyModel, MyEnum, MyEnumIncludingNull):
163161
assert_model_decode_encode(MyModel, {"nullableEnumProp": "b"}, MyModel(nullable_enum_prop=MyEnum.B))
164162
assert_model_decode_encode(MyModel, {"nullableEnumProp": None}, MyModel(nullable_enum_prop=None))
165163
assert_model_decode_encode(
166164
MyModel,
167165
{"enumIncludingNullProp": "a"},
168-
MyModel(enum_including_null_prop=MyEnumIncludingNullType1.A),
166+
MyModel(enum_including_null_prop=MyEnumIncludingNull.A),
169167
)
170168
assert_model_decode_encode( MyModel, {"enumIncludingNullProp": None}, MyModel(enum_including_null_prop=None))
171169
assert_model_decode_encode(MyModel, {"nullOnlyEnumProp": None}, MyModel(null_only_enum_prop=None))
172170

173-
def test_type_hints(self, MyModel, MyEnum, Unset):
174-
expected_type = Union[MyEnum, None, Unset]
175-
assert_model_property_type_hint(MyModel, "nullable_enum_prop", expected_type)
171+
def test_type_hints(self, MyModel, MyEnum, MyEnumIncludingNull, Unset):
172+
assert_model_property_type_hint(MyModel, "nullable_enum_prop", Union[MyEnum, None, Unset])
173+
assert_model_property_type_hint(MyModel, "enum_including_null_prop", Union[MyEnumIncludingNull, None, Unset])
174+
assert_model_property_type_hint(MyModel, "null_only_enum_prop", Union[None, Unset])
175+
176+
177+
@with_generated_client_fixture(
178+
"""
179+
openapi: 3.0.0
180+
181+
components:
182+
schemas:
183+
MyEnum:
184+
type: string
185+
enum: ["a", "b"]
186+
MyEnumIncludingNull:
187+
type: string
188+
nullable: true
189+
enum: ["a", "b", null]
190+
MyModel:
191+
properties:
192+
nullableEnumProp:
193+
allOf:
194+
- {"$ref": "#/components/schemas/MyEnum"}
195+
nullable: true
196+
enumIncludingNullProp: {"$ref": "#/components/schemas/MyEnumIncludingNull"}
197+
""")
198+
@with_generated_code_imports(
199+
".models.MyEnum",
200+
".models.MyEnumIncludingNull",
201+
".models.MyModel",
202+
".types.Unset",
203+
)
204+
class TestNullableEnumsInOpenAPI30:
205+
def test_nullable_enum_prop(self, MyModel, MyEnum, MyEnumIncludingNull):
206+
assert_model_decode_encode(MyModel, {"nullableEnumProp": "b"}, MyModel(nullable_enum_prop=MyEnum.B))
207+
assert_model_decode_encode(MyModel, {"nullableEnumProp": None}, MyModel(nullable_enum_prop=None))
208+
assert_model_decode_encode(
209+
MyModel,
210+
{"enumIncludingNullProp": "a"},
211+
MyModel(enum_including_null_prop=MyEnumIncludingNull.A),
212+
)
213+
assert_model_decode_encode( MyModel, {"enumIncludingNullProp": None}, MyModel(enum_including_null_prop=None))
176214

215+
def test_type_hints(self, MyModel, MyEnum, MyEnumIncludingNull, Unset):
216+
assert_model_property_type_hint(MyModel, "nullable_enum_prop", Union[MyEnum, None, Unset])
217+
assert_model_property_type_hint(MyModel, "enum_including_null_prop", Union[MyEnumIncludingNull, None, Unset])
218+
177219

178220
@with_generated_client_fixture(
179221
"""

end_to_end_tests/golden-record/my_test_api_client/models/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
)
5353
from .model_with_additional_properties_refed import ModelWithAdditionalPropertiesRefed
5454
from .model_with_any_json_properties import ModelWithAnyJsonProperties
55-
from .model_with_any_json_properties_additional_property_type_0 import ModelWithAnyJsonPropertiesAdditionalPropertyType0
55+
from .model_with_any_json_properties_additional_property import ModelWithAnyJsonPropertiesAdditionalProperty
5656
from .model_with_backslash_in_description import ModelWithBackslashInDescription
5757
from .model_with_circular_ref_a import ModelWithCircularRefA
5858
from .model_with_circular_ref_b import ModelWithCircularRefB
@@ -79,8 +79,8 @@
7979
from .post_naming_property_conflict_with_import_body import PostNamingPropertyConflictWithImportBody
8080
from .post_naming_property_conflict_with_import_response_200 import PostNamingPropertyConflictWithImportResponse200
8181
from .post_responses_unions_simple_before_complex_response_200 import PostResponsesUnionsSimpleBeforeComplexResponse200
82-
from .post_responses_unions_simple_before_complex_response_200a_type_1 import (
83-
PostResponsesUnionsSimpleBeforeComplexResponse200AType1,
82+
from .post_responses_unions_simple_before_complex_response_200a import (
83+
PostResponsesUnionsSimpleBeforeComplexResponse200A,
8484
)
8585
from .test_inline_objects_body import TestInlineObjectsBody
8686
from .test_inline_objects_response_200 import TestInlineObjectsResponse200
@@ -131,7 +131,7 @@
131131
"ModelWithAdditionalPropertiesInlinedAdditionalProperty",
132132
"ModelWithAdditionalPropertiesRefed",
133133
"ModelWithAnyJsonProperties",
134-
"ModelWithAnyJsonPropertiesAdditionalPropertyType0",
134+
"ModelWithAnyJsonPropertiesAdditionalProperty",
135135
"ModelWithBackslashInDescription",
136136
"ModelWithCircularRefA",
137137
"ModelWithCircularRefB",
@@ -158,7 +158,7 @@
158158
"PostNamingPropertyConflictWithImportBody",
159159
"PostNamingPropertyConflictWithImportResponse200",
160160
"PostResponsesUnionsSimpleBeforeComplexResponse200",
161-
"PostResponsesUnionsSimpleBeforeComplexResponse200AType1",
161+
"PostResponsesUnionsSimpleBeforeComplexResponse200A",
162162
"TestInlineObjectsBody",
163163
"TestInlineObjectsResponse200",
164164
"ValidationError",

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -373,9 +373,9 @@ def _parse_nullable_model(data: object) -> Union["ModelWithUnionProperty", None]
373373
try:
374374
if not isinstance(data, dict):
375375
raise TypeError()
376-
nullable_model_type_1 = ModelWithUnionProperty.from_dict(data)
376+
nullable_model = ModelWithUnionProperty.from_dict(data)
377377

378-
return nullable_model_type_1
378+
return nullable_model
379379
except: # noqa: E722
380380
pass
381381
return cast(Union["ModelWithUnionProperty", None], data)
@@ -495,9 +495,9 @@ def _parse_not_required_nullable_model(data: object) -> Union["ModelWithUnionPro
495495
try:
496496
if not isinstance(data, dict):
497497
raise TypeError()
498-
not_required_nullable_model_type_1 = ModelWithUnionProperty.from_dict(data)
498+
not_required_nullable_model = ModelWithUnionProperty.from_dict(data)
499499

500-
return not_required_nullable_model_type_1
500+
return not_required_nullable_model
501501
except: # noqa: E722
502502
pass
503503
return cast(Union["ModelWithUnionProperty", None, Unset], data)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,9 @@ def _parse_some_nullable_object(data: object) -> Union["BodyUploadFileTestsUploa
304304
try:
305305
if not isinstance(data, dict):
306306
raise TypeError()
307-
some_nullable_object_type_0 = BodyUploadFileTestsUploadPostSomeNullableObject.from_dict(data)
307+
some_nullable_object = BodyUploadFileTestsUploadPostSomeNullableObject.from_dict(data)
308308

309-
return some_nullable_object_type_0
309+
return some_nullable_object
310310
except: # noqa: E722
311311
pass
312312
return cast(Union["BodyUploadFileTestsUploadPostSomeNullableObject", None], data)

end_to_end_tests/golden-record/my_test_api_client/models/extended.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,9 +381,9 @@ def _parse_nullable_model(data: object) -> Union["ModelWithUnionProperty", None]
381381
try:
382382
if not isinstance(data, dict):
383383
raise TypeError()
384-
nullable_model_type_1 = ModelWithUnionProperty.from_dict(data)
384+
nullable_model = ModelWithUnionProperty.from_dict(data)
385385

386-
return nullable_model_type_1
386+
return nullable_model
387387
except: # noqa: E722
388388
pass
389389
return cast(Union["ModelWithUnionProperty", None], data)
@@ -503,9 +503,9 @@ def _parse_not_required_nullable_model(data: object) -> Union["ModelWithUnionPro
503503
try:
504504
if not isinstance(data, dict):
505505
raise TypeError()
506-
not_required_nullable_model_type_1 = ModelWithUnionProperty.from_dict(data)
506+
not_required_nullable_model = ModelWithUnionProperty.from_dict(data)
507507

508-
return not_required_nullable_model_type_1
508+
return not_required_nullable_model
509509
except: # noqa: E722
510510
pass
511511
return cast(Union["ModelWithUnionProperty", None, Unset], data)

end_to_end_tests/golden-record/my_test_api_client/models/model_with_any_json_properties.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
from attrs import field as _attrs_field
55

66
if TYPE_CHECKING:
7-
from ..models.model_with_any_json_properties_additional_property_type_0 import (
8-
ModelWithAnyJsonPropertiesAdditionalPropertyType0,
9-
)
7+
from ..models.model_with_any_json_properties_additional_property import ModelWithAnyJsonPropertiesAdditionalProperty
108

119

1210
T = TypeVar("T", bound="ModelWithAnyJsonProperties")
@@ -17,17 +15,17 @@ class ModelWithAnyJsonProperties:
1715
""" """
1816

1917
additional_properties: Dict[
20-
str, Union["ModelWithAnyJsonPropertiesAdditionalPropertyType0", List[str], bool, float, int, str]
18+
str, Union["ModelWithAnyJsonPropertiesAdditionalProperty", List[str], bool, float, int, str]
2119
] = _attrs_field(init=False, factory=dict)
2220

2321
def to_dict(self) -> Dict[str, Any]:
24-
from ..models.model_with_any_json_properties_additional_property_type_0 import (
25-
ModelWithAnyJsonPropertiesAdditionalPropertyType0,
22+
from ..models.model_with_any_json_properties_additional_property import (
23+
ModelWithAnyJsonPropertiesAdditionalProperty,
2624
)
2725

2826
field_dict: Dict[str, Any] = {}
2927
for prop_name, prop in self.additional_properties.items():
30-
if isinstance(prop, ModelWithAnyJsonPropertiesAdditionalPropertyType0):
28+
if isinstance(prop, ModelWithAnyJsonPropertiesAdditionalProperty):
3129
field_dict[prop_name] = prop.to_dict()
3230
elif isinstance(prop, list):
3331
field_dict[prop_name] = prop
@@ -39,8 +37,8 @@ def to_dict(self) -> Dict[str, Any]:
3937

4038
@classmethod
4139
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
42-
from ..models.model_with_any_json_properties_additional_property_type_0 import (
43-
ModelWithAnyJsonPropertiesAdditionalPropertyType0,
40+
from ..models.model_with_any_json_properties_additional_property import (
41+
ModelWithAnyJsonPropertiesAdditionalProperty,
4442
)
4543

4644
d = src_dict.copy()
@@ -51,13 +49,13 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
5149

5250
def _parse_additional_property(
5351
data: object,
54-
) -> Union["ModelWithAnyJsonPropertiesAdditionalPropertyType0", List[str], bool, float, int, str]:
52+
) -> Union["ModelWithAnyJsonPropertiesAdditionalProperty", List[str], bool, float, int, str]:
5553
try:
5654
if not isinstance(data, dict):
5755
raise TypeError()
58-
additional_property_type_0 = ModelWithAnyJsonPropertiesAdditionalPropertyType0.from_dict(data)
56+
additional_property = ModelWithAnyJsonPropertiesAdditionalProperty.from_dict(data)
5957

60-
return additional_property_type_0
58+
return additional_property
6159
except: # noqa: E722
6260
pass
6361
try:
@@ -69,7 +67,7 @@ def _parse_additional_property(
6967
except: # noqa: E722
7068
pass
7169
return cast(
72-
Union["ModelWithAnyJsonPropertiesAdditionalPropertyType0", List[str], bool, float, int, str], data
70+
Union["ModelWithAnyJsonPropertiesAdditionalProperty", List[str], bool, float, int, str], data
7371
)
7472

7573
additional_property = _parse_additional_property(prop_dict)
@@ -85,13 +83,11 @@ def additional_keys(self) -> List[str]:
8583

8684
def __getitem__(
8785
self, key: str
88-
) -> Union["ModelWithAnyJsonPropertiesAdditionalPropertyType0", List[str], bool, float, int, str]:
86+
) -> Union["ModelWithAnyJsonPropertiesAdditionalProperty", List[str], bool, float, int, str]:
8987
return self.additional_properties[key]
9088

9189
def __setitem__(
92-
self,
93-
key: str,
94-
value: Union["ModelWithAnyJsonPropertiesAdditionalPropertyType0", List[str], bool, float, int, str],
90+
self, key: str, value: Union["ModelWithAnyJsonPropertiesAdditionalProperty", List[str], bool, float, int, str]
9591
) -> None:
9692
self.additional_properties[key] = value
9793

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
from attrs import define as _attrs_define
44
from attrs import field as _attrs_field
55

6-
T = TypeVar("T", bound="ModelWithAnyJsonPropertiesAdditionalPropertyType0")
6+
T = TypeVar("T", bound="ModelWithAnyJsonPropertiesAdditionalProperty")
77

88

99
@_attrs_define
10-
class ModelWithAnyJsonPropertiesAdditionalPropertyType0:
10+
class ModelWithAnyJsonPropertiesAdditionalProperty:
1111
""" """
1212

1313
additional_properties: Dict[str, str] = _attrs_field(init=False, factory=dict)
@@ -21,10 +21,10 @@ def to_dict(self) -> Dict[str, Any]:
2121
@classmethod
2222
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
2323
d = src_dict.copy()
24-
model_with_any_json_properties_additional_property_type_0 = cls()
24+
model_with_any_json_properties_additional_property = cls()
2525

26-
model_with_any_json_properties_additional_property_type_0.additional_properties = d
27-
return model_with_any_json_properties_additional_property_type_0
26+
model_with_any_json_properties_additional_property.additional_properties = d
27+
return model_with_any_json_properties_additional_property
2828

2929
@property
3030
def additional_keys(self) -> List[str]:

end_to_end_tests/golden-record/my_test_api_client/models/post_responses_unions_simple_before_complex_response_200.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from attrs import field as _attrs_field
55

66
if TYPE_CHECKING:
7-
from ..models.post_responses_unions_simple_before_complex_response_200a_type_1 import (
8-
PostResponsesUnionsSimpleBeforeComplexResponse200AType1,
7+
from ..models.post_responses_unions_simple_before_complex_response_200a import (
8+
PostResponsesUnionsSimpleBeforeComplexResponse200A,
99
)
1010

1111

@@ -16,19 +16,19 @@
1616
class PostResponsesUnionsSimpleBeforeComplexResponse200:
1717
"""
1818
Attributes:
19-
a (Union['PostResponsesUnionsSimpleBeforeComplexResponse200AType1', str]):
19+
a (Union['PostResponsesUnionsSimpleBeforeComplexResponse200A', str]):
2020
"""
2121

22-
a: Union["PostResponsesUnionsSimpleBeforeComplexResponse200AType1", str]
22+
a: Union["PostResponsesUnionsSimpleBeforeComplexResponse200A", str]
2323
additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
2424

2525
def to_dict(self) -> Dict[str, Any]:
26-
from ..models.post_responses_unions_simple_before_complex_response_200a_type_1 import (
27-
PostResponsesUnionsSimpleBeforeComplexResponse200AType1,
26+
from ..models.post_responses_unions_simple_before_complex_response_200a import (
27+
PostResponsesUnionsSimpleBeforeComplexResponse200A,
2828
)
2929

3030
a: Union[Dict[str, Any], str]
31-
if isinstance(self.a, PostResponsesUnionsSimpleBeforeComplexResponse200AType1):
31+
if isinstance(self.a, PostResponsesUnionsSimpleBeforeComplexResponse200A):
3232
a = self.a.to_dict()
3333
else:
3434
a = self.a
@@ -45,22 +45,22 @@ def to_dict(self) -> Dict[str, Any]:
4545

4646
@classmethod
4747
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
48-
from ..models.post_responses_unions_simple_before_complex_response_200a_type_1 import (
49-
PostResponsesUnionsSimpleBeforeComplexResponse200AType1,
48+
from ..models.post_responses_unions_simple_before_complex_response_200a import (
49+
PostResponsesUnionsSimpleBeforeComplexResponse200A,
5050
)
5151

5252
d = src_dict.copy()
5353

54-
def _parse_a(data: object) -> Union["PostResponsesUnionsSimpleBeforeComplexResponse200AType1", str]:
54+
def _parse_a(data: object) -> Union["PostResponsesUnionsSimpleBeforeComplexResponse200A", str]:
5555
try:
5656
if not isinstance(data, dict):
5757
raise TypeError()
58-
a_type_1 = PostResponsesUnionsSimpleBeforeComplexResponse200AType1.from_dict(data)
58+
a = PostResponsesUnionsSimpleBeforeComplexResponse200A.from_dict(data)
5959

60-
return a_type_1
60+
return a
6161
except: # noqa: E722
6262
pass
63-
return cast(Union["PostResponsesUnionsSimpleBeforeComplexResponse200AType1", str], data)
63+
return cast(Union["PostResponsesUnionsSimpleBeforeComplexResponse200A", str], data)
6464

6565
a = _parse_a(d.pop("a"))
6666

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
from attrs import define as _attrs_define
44
from attrs import field as _attrs_field
55

6-
T = TypeVar("T", bound="PostResponsesUnionsSimpleBeforeComplexResponse200AType1")
6+
T = TypeVar("T", bound="PostResponsesUnionsSimpleBeforeComplexResponse200A")
77

88

99
@_attrs_define
10-
class PostResponsesUnionsSimpleBeforeComplexResponse200AType1:
10+
class PostResponsesUnionsSimpleBeforeComplexResponse200A:
1111
""" """
1212

1313
additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -21,10 +21,10 @@ def to_dict(self) -> Dict[str, Any]:
2121
@classmethod
2222
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
2323
d = src_dict.copy()
24-
post_responses_unions_simple_before_complex_response_200a_type_1 = cls()
24+
post_responses_unions_simple_before_complex_response_200a = cls()
2525

26-
post_responses_unions_simple_before_complex_response_200a_type_1.additional_properties = d
27-
return post_responses_unions_simple_before_complex_response_200a_type_1
26+
post_responses_unions_simple_before_complex_response_200a.additional_properties = d
27+
return post_responses_unions_simple_before_complex_response_200a
2828

2929
@property
3030
def additional_keys(self) -> List[str]:

end_to_end_tests/literal-enums-golden-record/my_enum_api_client/models/post_user_list_body.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,9 @@ def _parse_an_enum_value_with_null_item(data: object) -> Union[AnEnumWithNull, N
187187
try:
188188
if not isinstance(data, str):
189189
raise TypeError()
190-
componentsschemas_an_enum_with_null_type_1 = check_an_enum_with_null(data)
190+
componentsschemas_an_enum_with_null = check_an_enum_with_null(data)
191191

192-
return componentsschemas_an_enum_with_null_type_1
192+
return componentsschemas_an_enum_with_null
193193
except: # noqa: E722
194194
pass
195195
return cast(Union[AnEnumWithNull, None], data)

0 commit comments

Comments
 (0)