Skip to content

Commit 1512225

Browse files
Refactor out logic for JSON types and fix enum value bug
1 parent fa92f9a commit 1512225

File tree

18 files changed

+65
-37
lines changed

18 files changed

+65
-37
lines changed

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -96,22 +96,22 @@ def httpx_request(
9696
else:
9797
json_union_prop = union_prop
9898

99-
json_union_prop_with_ref: Union[Unset, None, float, AnEnum]
99+
json_union_prop_with_ref: Union[Unset, None, float, int]
100100
if isinstance(union_prop_with_ref, Unset):
101101
json_union_prop_with_ref = UNSET
102102
elif union_prop_with_ref is None:
103103
json_union_prop_with_ref = None
104104
elif isinstance(union_prop_with_ref, AnEnum):
105105
json_union_prop_with_ref = UNSET
106106
if not isinstance(union_prop_with_ref, Unset):
107-
json_union_prop_with_ref = union_prop_with_ref
107+
json_union_prop_with_ref = union_prop_with_ref.value
108108

109109
else:
110110
json_union_prop_with_ref = union_prop_with_ref
111111

112-
json_enum_prop: Union[Unset, None, AnEnum] = UNSET
112+
json_enum_prop: Union[Unset, None, int] = UNSET
113113
if not isinstance(enum_prop, Unset):
114-
json_enum_prop = enum_prop if enum_prop else None
114+
json_enum_prop = enum_prop.value if enum_prop else None
115115

116116
params: Dict[str, Any] = {
117117
"required_not_nullable_datetime_prop": json_required_not_nullable_datetime_prop,

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ class ModelWithUnionProperty:
1616
a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET
1717

1818
def to_dict(self) -> Dict[str, Any]:
19-
a_property: Union[Unset, AnEnum, AnIntEnum]
19+
a_property: Union[Unset, int]
2020
if isinstance(self.a_property, Unset):
2121
a_property = UNSET
2222
elif isinstance(self.a_property, AnEnum):
2323
a_property = UNSET
2424
if not isinstance(self.a_property, Unset):
25-
a_property = self.a_property
25+
a_property = self.a_property.value
2626

2727
else:
2828
a_property = UNSET
2929
if not isinstance(self.a_property, Unset):
30-
a_property = self.a_property
30+
a_property = self.a_property.value
3131

3232
field_dict: Dict[str, Any] = {}
3333
field_dict.update({})

end_to_end_tests/golden-record-custom/custom_e2e/types.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ def __bool__(self) -> bool:
1111

1212
UNSET: Unset = Unset()
1313

14+
# Used as `FileProperty._json_type_string`
15+
FileJsonType = Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]
16+
1417

1518
@attr.s(auto_attribs=True)
1619
class File:
@@ -20,7 +23,7 @@ class File:
2023
file_name: Optional[str] = None
2124
mime_type: Optional[str] = None
2225

23-
def to_tuple(self) -> Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]:
26+
def to_tuple(self) -> FileJsonType:
2427
""" Return a tuple representation that httpx will accept for multipart/form-data """
2528
return self.file_name, self.payload, self.mime_type
2629

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -72,22 +72,22 @@ def _get_kwargs(
7272
else:
7373
json_union_prop = union_prop
7474

75-
json_union_prop_with_ref: Union[Unset, None, float, AnEnum]
75+
json_union_prop_with_ref: Union[Unset, None, float, int]
7676
if isinstance(union_prop_with_ref, Unset):
7777
json_union_prop_with_ref = UNSET
7878
elif union_prop_with_ref is None:
7979
json_union_prop_with_ref = None
8080
elif isinstance(union_prop_with_ref, AnEnum):
8181
json_union_prop_with_ref = UNSET
8282
if not isinstance(union_prop_with_ref, Unset):
83-
json_union_prop_with_ref = union_prop_with_ref
83+
json_union_prop_with_ref = union_prop_with_ref.value
8484

8585
else:
8686
json_union_prop_with_ref = union_prop_with_ref
8787

88-
json_enum_prop: Union[Unset, None, AnEnum] = UNSET
88+
json_enum_prop: Union[Unset, None, int] = UNSET
8989
if not isinstance(enum_prop, Unset):
90-
json_enum_prop = enum_prop if enum_prop else None
90+
json_enum_prop = enum_prop.value if enum_prop else None
9191

9292
params: Dict[str, Any] = {
9393
"required_not_nullable_datetime_prop": json_required_not_nullable_datetime_prop,

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ class ModelWithUnionProperty:
1616
a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET
1717

1818
def to_dict(self) -> Dict[str, Any]:
19-
a_property: Union[Unset, AnEnum, AnIntEnum]
19+
a_property: Union[Unset, int]
2020
if isinstance(self.a_property, Unset):
2121
a_property = UNSET
2222
elif isinstance(self.a_property, AnEnum):
2323
a_property = UNSET
2424
if not isinstance(self.a_property, Unset):
25-
a_property = self.a_property
25+
a_property = self.a_property.value
2626

2727
else:
2828
a_property = UNSET
2929
if not isinstance(self.a_property, Unset):
30-
a_property = self.a_property
30+
a_property = self.a_property.value
3131

3232
field_dict: Dict[str, Any] = {}
3333
field_dict.update({})

end_to_end_tests/golden-record/my_test_api_client/types.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ def __bool__(self) -> bool:
1111

1212
UNSET: Unset = Unset()
1313

14+
# Used as `FileProperty._json_type_string`
15+
FileJsonType = Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]
16+
1417

1518
@attr.s(auto_attribs=True)
1619
class File:
@@ -20,7 +23,7 @@ class File:
2023
file_name: Optional[str] = None
2124
mime_type: Optional[str] = None
2225

23-
def to_tuple(self) -> Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]:
26+
def to_tuple(self) -> FileJsonType:
2427
""" Return a tuple representation that httpx will accept for multipart/form-data """
2528
return self.file_name, self.payload, self.mime_type
2629

openapi_python_client/parser/properties/__init__.py

+20-9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class NoneProperty(Property):
1919
""" A property that is always None (used for empty schemas) """
2020

2121
_type_string: ClassVar[str] = "None"
22+
_json_type_string: ClassVar[str] = "None"
2223
template: ClassVar[Optional[str]] = "none_property.pyi"
2324

2425

@@ -29,6 +30,7 @@ class StringProperty(Property):
2930
max_length: Optional[int] = None
3031
pattern: Optional[str] = None
3132
_type_string: ClassVar[str] = "str"
33+
_json_type_string: ClassVar[str] = "str"
3234

3335

3436
@attr.s(auto_attribs=True, frozen=True)
@@ -38,6 +40,7 @@ class DateTimeProperty(Property):
3840
"""
3941

4042
_type_string: ClassVar[str] = "datetime.datetime"
43+
_json_type_string: ClassVar[str] = "str"
4144
template: ClassVar[str] = "datetime_property.pyi"
4245

4346
def get_imports(self, *, prefix: str) -> Set[str]:
@@ -58,6 +61,7 @@ class DateProperty(Property):
5861
""" A property of type datetime.date """
5962

6063
_type_string: ClassVar[str] = "datetime.date"
64+
_json_type_string: ClassVar[str] = "str"
6165
template: ClassVar[str] = "date_property.pyi"
6266

6367
def get_imports(self, *, prefix: str) -> Set[str]:
@@ -78,6 +82,8 @@ class FileProperty(Property):
7882
""" A property used for uploading files """
7983

8084
_type_string: ClassVar[str] = "File"
85+
# Return type of File.to_tuple()
86+
_json_type_string: ClassVar[str] = "Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]"
8187
template: ClassVar[str] = "file_property.pyi"
8288

8389
def get_imports(self, *, prefix: str) -> Set[str]:
@@ -98,20 +104,23 @@ class FloatProperty(Property):
98104
""" A property of type float """
99105

100106
_type_string: ClassVar[str] = "float"
107+
_json_type_string: ClassVar[str] = "float"
101108

102109

103110
@attr.s(auto_attribs=True, frozen=True)
104111
class IntProperty(Property):
105112
""" A property of type int """
106113

107114
_type_string: ClassVar[str] = "int"
115+
_json_type_string: ClassVar[str] = "int"
108116

109117

110118
@attr.s(auto_attribs=True, frozen=True)
111119
class BooleanProperty(Property):
112120
""" Property for bool """
113121

114122
_type_string: ClassVar[str] = "bool"
123+
_json_type_string: ClassVar[str] = "bool"
115124

116125

117126
InnerProp = TypeVar("InnerProp", bound=Property)
@@ -122,6 +131,7 @@ class ListProperty(Property, Generic[InnerProp]):
122131
""" A property representing a list (array) of other properties """
123132

124133
inner_property: InnerProp
134+
_json_type_string: ClassVar[str] = "List[Any]"
125135
template: ClassVar[str] = "list_property.pyi"
126136

127137
def get_base_type_string(self) -> str:
@@ -159,37 +169,38 @@ def __attrs_post_init__(self) -> None:
159169
self, "has_properties_without_templates", any(prop.template is None for prop in self.inner_properties)
160170
)
161171

162-
def _get_inner_prop_string(self) -> str:
163-
inner_types = [p.get_type_string(no_optional=True) for p in self.inner_properties]
164-
return ", ".join(inner_types)
172+
def _get_inner_prop_string(self, json: bool = False) -> str:
173+
inner_types = [p.get_type_string(no_optional=True, json=json) for p in self.inner_properties]
174+
unique_inner_types = list(dict.fromkeys(inner_types))
175+
return ", ".join(unique_inner_types)
165176

166177
def get_base_type_string(self) -> str:
167178
return f"Union[{self._get_inner_prop_string()}]"
168179

169-
def get_type_string(self, no_optional: bool = False, query_parameter: bool = False) -> str:
180+
def get_type_string(self, no_optional: bool = False, query_parameter: bool = False, json: bool = False) -> str:
170181
"""
171182
Get a string representation of type that should be used when declaring this property.
172183
173184
This implementation differs slightly from `Property.get_type_string` in order to collapse
174185
nested union types.
175186
"""
176-
type_string = self.get_base_type_string()
187+
type_string = f"Union[{self._get_inner_prop_string(json=json)}]"
177188
if no_optional:
178189
return type_string
179190
if self.required:
180191
if self.nullable:
181-
return f"Union[None, {self._get_inner_prop_string()}]"
192+
return f"Union[None, {self._get_inner_prop_string(json=json)}]"
182193
else:
183194
return type_string
184195
else:
185196
if self.nullable:
186-
return f"Union[Unset, None, {self._get_inner_prop_string()}]"
197+
return f"Union[Unset, None, {self._get_inner_prop_string(json=json)}]"
187198
else:
188199
if query_parameter:
189200
# For query parameters, None has the same meaning as Unset
190-
return f"Union[Unset, None, {self._get_inner_prop_string()}]"
201+
return f"Union[Unset, None, {self._get_inner_prop_string(json=json)}]"
191202
else:
192-
return f"Union[Unset, {self._get_inner_prop_string()}]"
203+
return f"Union[Unset, {self._get_inner_prop_string(json=json)}]"
193204

194205
def get_imports(self, *, prefix: str) -> Set[str]:
195206
"""

openapi_python_client/parser/properties/enum_property.py

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class EnumProperty(Property):
1818
values: Dict[str, ValueType]
1919
reference: Reference
2020
value_type: Type[ValueType]
21+
_json_type_string: ClassVar[str] = "int"
2122
default: Optional[Any] = attr.ib()
2223

2324
template: ClassVar[str] = "enum_property.pyi"

openapi_python_client/parser/properties/model_property.py

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class ModelProperty(Property):
1717
description: str
1818
relative_imports: Set[str]
1919
additional_properties: Union[bool, Property]
20+
_json_type_string: ClassVar[str] = "Dict[str, Any]"
2021

2122
template: ClassVar[str] = "model_property.pyi"
2223

openapi_python_client/parser/properties/property.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class Property:
2424
required: bool
2525
nullable: bool
2626
_type_string: ClassVar[str] = ""
27+
_json_type_string: ClassVar[str] = "" # Type of the property after JSON serialization
2728
default: Optional[str] = attr.ib()
2829
python_name: str = attr.ib(init=False)
2930

@@ -35,15 +36,20 @@ def __attrs_post_init__(self) -> None:
3536
def get_base_type_string(self) -> str:
3637
return self._type_string
3738

38-
def get_type_string(self, no_optional: bool = False, query_parameter: bool = False) -> str:
39+
def get_type_string(self, no_optional: bool = False, query_parameter: bool = False, json: bool = False) -> str:
3940
"""
4041
Get a string representation of type that should be used when declaring this property
4142
4243
Args:
4344
no_optional: Do not include Optional or Unset even if the value is optional (needed for isinstance checks)
4445
query_parameter: True if the property's type is being used for a query parameter
46+
json: True if the type refers to the property after JSON serialization
4547
"""
46-
type_string = self.get_base_type_string()
48+
if json:
49+
type_string = self._json_type_string
50+
else:
51+
type_string = self.get_base_type_string()
52+
4753
if no_optional:
4854
return type_string
4955
if self.required:

openapi_python_client/templates/property_templates/date_property.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ if _{{ property.python_name }} is not None:
1313
{% if property.required %}
1414
{{ destination }} = {{ source }}.isoformat() {% if property.nullable %}if {{ source }} else None {%endif%}
1515
{% else %}
16-
{{ destination }}{% if declare_type %}: Union[Unset, {% if property.nullable or query_parameter %}None, {% endif %}str]{% endif %} = UNSET
16+
{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET
1717
if not isinstance({{ source }}, Unset):
1818
{% if property.nullable or query_parameter %}
1919
{{ destination }} = {{ source }}.isoformat() if {{ source }} else None

openapi_python_client/templates/property_templates/datetime_property.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ if _{{ property.python_name }} is not None:
2222
{{ destination }} = {{ source }}.isoformat()
2323
{% endif %}
2424
{% else %}
25-
{{ destination }}{% if declare_type %}: Union[Unset, {% if property.nullable or query_parameter %}None, {% endif %}str]{% endif %} = UNSET
25+
{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET
2626
if not isinstance({{ source }}, Unset):
2727
{% if property.nullable or query_parameter %}
2828
{{ destination }} = {{ source }}.isoformat() if {{ source }} else None

openapi_python_client/templates/property_templates/enum_property.pyi

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ if _{{ property.python_name }} is not None:
1717
{{ destination }} = {{ source }}.value
1818
{% endif %}
1919
{% else %}
20-
{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter) }}{% endif %} = UNSET
20+
{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET
2121
if not isinstance({{ source }}, Unset):
2222
{% if property.nullable or query_parameter %}
23-
{{ destination }} = {{ source }} if {{ source }} else None
23+
{{ destination }} = {{ source }}.value if {{ source }} else None
2424
{% else %}
25-
{{ destination }} = {{ source }}
25+
{{ destination }} = {{ source }}.value
2626
{% endif %}
2727
{% endif %}
2828
{% endmacro %}

openapi_python_client/templates/property_templates/file_property.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
{{ destination }} = {{ source }}.to_tuple()
1313
{% endif %}
1414
{% else %}
15-
{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter) }}{% endif %} = UNSET
15+
{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET
1616
if not isinstance({{ source }}, Unset):
1717
{% if property.nullable or query_parameter %}
1818
{{ destination }} = {{ source }}.to_tuple() if {{ source }} else None

openapi_python_client/templates/property_templates/list_property.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ else:
4444
{{ _transform(property, source, destination) }}
4545
{% endif %}
4646
{% else %}
47-
{{ destination }}{% if declare_type %}: Union[Unset, {% if property.nullable or query_parameter %}None, {% endif %}List[Any]]{% endif %} = UNSET
47+
{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET
4848
if not isinstance({{ source }}, Unset):
4949
{% if property.nullable or query_parameter %}
5050
if {{ source }} is None:

openapi_python_client/templates/property_templates/model_property.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ if _{{ property.python_name }} is not None and not isinstance(_{{ property.pytho
2323
{{ destination }} = {{ source }}.to_dict()
2424
{% endif %}
2525
{% else %}
26-
{{ destination }}{% if declare_type %}: Union[{% if property.nullable or query_parameter %}None, {% endif %}Unset, Dict[str, Any]]{% endif %} = UNSET
26+
{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET
2727
if not isinstance({{ source }}, Unset):
2828
{% if property.nullable or query_parameter %}
2929
{{ destination }} = {{ source }}.to_dict() if {{ source }} else None

openapi_python_client/templates/property_templates/union_property.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def _parse_{{ property.python_name }}(data: Any) -> {{ property.get_type_string(
2626

2727
{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %}
2828
{% if not property.required or property.nullable %}
29-
{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter) }}{% endif %}
29+
{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %}
3030

3131
if isinstance({{ source }}, Unset):
3232
{{ destination }} = UNSET

openapi_python_client/templates/types.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ def __bool__(self) -> bool:
1111

1212
UNSET: Unset = Unset()
1313

14+
# Used as `FileProperty._json_type_string`
15+
FileJsonType = Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]
16+
1417

1518
@attr.s(auto_attribs=True)
1619
class File:
@@ -20,7 +23,7 @@ class File:
2023
file_name: Optional[str] = None
2124
mime_type: Optional[str] = None
2225

23-
def to_tuple(self) -> Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]:
26+
def to_tuple(self) -> FileJsonType:
2427
""" Return a tuple representation that httpx will accept for multipart/form-data """
2528
return self.file_name, self.payload, self.mime_type
2629

0 commit comments

Comments
 (0)