diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py index 18772a156..36b27dc73 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py @@ -77,7 +77,7 @@ def httpx_request( json_enum_prop: Union[Unset, AnEnum] = UNSET if not isinstance(enum_prop, Unset): - json_enum_prop = enum_prop.value + json_enum_prop = enum_prop params: Dict[str, Any] = {} if string_prop is not UNSET: diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py index 5ae4c16b7..f99051cf8 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py @@ -6,6 +6,7 @@ from .body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost from .different_enum import DifferentEnum from .http_validation_error import HTTPValidationError +from .model_with_union_property import ModelWithUnionProperty from .test_inline_objectsjson_body import TestInlineObjectsjsonBody from .test_inline_objectsresponse_200 import TestInlineObjectsresponse_200 from .validation_error import ValidationError diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py index 87175124c..f523e36f6 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py @@ -74,15 +74,16 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(d: Dict[str, Any]) -> "AModel": an_enum_value = AnEnum(d["an_enum_value"]) - def _parse_a_camel_date_time(data: Dict[str, Any]) -> Union[datetime.datetime, datetime.date]: + def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.date]: + data = None if isinstance(data, Unset) else data a_camel_date_time: Union[datetime.datetime, datetime.date] try: - a_camel_date_time = isoparse(d["aCamelDateTime"]) + a_camel_date_time = isoparse(data) return a_camel_date_time except: # noqa: E722 pass - a_camel_date_time = isoparse(d["aCamelDateTime"]).date() + a_camel_date_time = isoparse(data).date() return a_camel_date_time diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py new file mode 100644 index 000000000..2ca963e01 --- /dev/null +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py @@ -0,0 +1,59 @@ +from typing import Any, Dict, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class ModelWithUnionProperty: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + field_dict = {} + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ModelWithUnionProperty": + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + if data is not None: + a_property = AnEnum(data) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + if data is not None: + a_property = AnIntEnum(data) + + return a_property + + a_property = _parse_a_property(d.get("a_property", UNSET)) + + return ModelWithUnionProperty( + a_property=a_property, + ) diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py index b289fafed..1b2b1c12e 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py @@ -53,7 +53,7 @@ def _get_kwargs( json_enum_prop: Union[Unset, AnEnum] = UNSET if not isinstance(enum_prop, Unset): - json_enum_prop = enum_prop.value + json_enum_prop = enum_prop params: Dict[str, Any] = {} if string_prop is not UNSET: diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py index 5ae4c16b7..f99051cf8 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py @@ -6,6 +6,7 @@ from .body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost from .different_enum import DifferentEnum from .http_validation_error import HTTPValidationError +from .model_with_union_property import ModelWithUnionProperty from .test_inline_objectsjson_body import TestInlineObjectsjsonBody from .test_inline_objectsresponse_200 import TestInlineObjectsresponse_200 from .validation_error import ValidationError diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index 87175124c..f523e36f6 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -74,15 +74,16 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(d: Dict[str, Any]) -> "AModel": an_enum_value = AnEnum(d["an_enum_value"]) - def _parse_a_camel_date_time(data: Dict[str, Any]) -> Union[datetime.datetime, datetime.date]: + def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.date]: + data = None if isinstance(data, Unset) else data a_camel_date_time: Union[datetime.datetime, datetime.date] try: - a_camel_date_time = isoparse(d["aCamelDateTime"]) + a_camel_date_time = isoparse(data) return a_camel_date_time except: # noqa: E722 pass - a_camel_date_time = isoparse(d["aCamelDateTime"]).date() + a_camel_date_time = isoparse(data).date() return a_camel_date_time diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py new file mode 100644 index 000000000..2ca963e01 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py @@ -0,0 +1,59 @@ +from typing import Any, Dict, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class ModelWithUnionProperty: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + field_dict = {} + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ModelWithUnionProperty": + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + if data is not None: + a_property = AnEnum(data) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + if data is not None: + a_property = AnIntEnum(data) + + return a_property + + a_property = _parse_a_property(d.get("a_property", UNSET)) + + return ModelWithUnionProperty( + a_property=a_property, + ) diff --git a/end_to_end_tests/openapi.json b/end_to_end_tests/openapi.json index f3e1a26ae..7087a0631 100644 --- a/end_to_end_tests/openapi.json +++ b/end_to_end_tests/openapi.json @@ -727,6 +727,18 @@ "type": "string" } } + }, + "ModelWithUnionProperty": { + "title": "ModelWithUnionProperty", + "type": "object", + "properties": { + "a_property": { + "oneOf": [ + {"$ref": "#/components/schemas/AnEnum"}, + {"$ref": "#/components/schemas/AnIntEnum"} + ] + } + } } } } diff --git a/openapi_python_client/templates/property_templates/date_property.pyi b/openapi_python_client/templates/property_templates/date_property.pyi index 39985f1eb..b8b12ce57 100644 --- a/openapi_python_client/templates/property_templates/date_property.pyi +++ b/openapi_python_client/templates/property_templates/date_property.pyi @@ -1,14 +1,14 @@ -{% macro construct(property, source) %} +{% macro construct(property, source, initial_value="None") %} {% if property.required %} {{ property.python_name }} = isoparse({{ source }}).date() {% else %} -{{ property.python_name }} = None +{{ property.python_name }} = {{ initial_value }} if {{ source }} is not None: {{ property.python_name }} = isoparse(cast(str, {{ source }})).date() {% endif %} {% endmacro %} -{% macro transform(property, source, destination) %} +{% macro transform(property, source, destination, declare_type=True) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.isoformat() if {{ source }} else None @@ -16,7 +16,7 @@ if {{ source }} is not None: {{ destination }} = {{ source }}.isoformat() {% endif %} {% else %} -{{ destination }}: Union[Unset, str] = UNSET +{{ destination }}{% if declare_type %}: Union[Unset, str]{% endif %} = UNSET if not isinstance({{ source }}, Unset): {% if property.nullable %} {{ destination }} = {{ source }}.isoformat() if {{ source }} else None diff --git a/openapi_python_client/templates/property_templates/datetime_property.pyi b/openapi_python_client/templates/property_templates/datetime_property.pyi index 6eb772c54..b7c822a62 100644 --- a/openapi_python_client/templates/property_templates/datetime_property.pyi +++ b/openapi_python_client/templates/property_templates/datetime_property.pyi @@ -1,14 +1,14 @@ -{% macro construct(property, source) %} +{% macro construct(property, source, initial_value="None") %} {% if property.required %} {{ property.python_name }} = isoparse({{ source }}) {% else %} -{{ property.python_name }} = None +{{ property.python_name }} = {{ initial_value }} if {{ source }} is not None: {{ property.python_name }} = isoparse(cast(str, {{ source }})) {% endif %} {% endmacro %} -{% macro transform(property, source, destination) %} +{% macro transform(property, source, destination, declare_type=True) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.isoformat() if {{ source }} else None @@ -16,7 +16,7 @@ if {{ source }} is not None: {{ destination }} = {{ source }}.isoformat() {% endif %} {% else %} -{{ destination }}: Union[Unset, str] = UNSET +{{ destination }}{% if declare_type %}: Union[Unset, str]{% endif %} = UNSET if not isinstance({{ source }}, Unset): {% if property.nullable %} {{ destination }} = {{ source }}.isoformat() if {{ source }} else None diff --git a/openapi_python_client/templates/property_templates/dict_property.pyi b/openapi_python_client/templates/property_templates/dict_property.pyi index 62440ebeb..b55191f20 100644 --- a/openapi_python_client/templates/property_templates/dict_property.pyi +++ b/openapi_python_client/templates/property_templates/dict_property.pyi @@ -1,14 +1,14 @@ -{% macro construct(property, source) %} +{% macro construct(property, source, initial_value="None") %} {% if property.required %} {{ property.python_name }} = {{ source }} {% else %} -{{ property.python_name }} = None +{{ property.python_name }} = {{ initial_value }} if {{ source }} is not None: {{ property.python_name }} = {{ source }} {% endif %} {% endmacro %} -{% macro transform(property, source, destination) %} +{% macro transform(property, source, destination, declare_type=True) %} {% if property.nullable %} {{ destination }} = {{ source }} if {{ source }} else None {% else %} diff --git a/openapi_python_client/templates/property_templates/enum_property.pyi b/openapi_python_client/templates/property_templates/enum_property.pyi index f5a1f6aba..d098bb471 100644 --- a/openapi_python_client/templates/property_templates/enum_property.pyi +++ b/openapi_python_client/templates/property_templates/enum_property.pyi @@ -1,14 +1,14 @@ -{% macro construct(property, source) %} +{% macro construct(property, source, initial_value="None") %} {% if property.required %} {{ property.python_name }} = {{ property.reference.class_name }}({{ source }}) {% else %} -{{ property.python_name }} = None +{{ property.python_name }} = {{ initial_value }} if {{ source }} is not None: {{ property.python_name }} = {{ property.reference.class_name }}({{ source }}) {% endif %} {% endmacro %} -{% macro transform(property, source, destination) %} +{% macro transform(property, source, destination, declare_type=True) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.value if {{ source }} else None @@ -16,12 +16,12 @@ if {{ source }} is not None: {{ destination }} = {{ source }}.value {% endif %} {% else %} -{{ destination }}: {{ property.get_type_string() }} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): {% if property.nullable %} - {{ destination }} = {{ source }}.value if {{ source }} else None + {{ destination }} = {{ source }} if {{ source }} else None {% else %} - {{ destination }} = {{ source }}.value + {{ destination }} = {{ source }} {% endif %} {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/file_property.pyi b/openapi_python_client/templates/property_templates/file_property.pyi index f759de4a6..ffa3c20d9 100644 --- a/openapi_python_client/templates/property_templates/file_property.pyi +++ b/openapi_python_client/templates/property_templates/file_property.pyi @@ -1,10 +1,10 @@ -{% macro construct(property, source) %} +{% macro construct(property, source, initial_value=None) %} {{ property.python_name }} = File( payload = BytesIO({{ source }}) ) {% endmacro %} -{% macro transform(property, source, destination) %} +{% macro transform(property, source, destination, declare_type=True) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.to_tuple() if {{ source }} else None @@ -12,7 +12,7 @@ {{ destination }} = {{ source }}.to_tuple() {% endif %} {% else %} -{{ destination }}: {{ property.get_type_string() }} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): {% if property.nullable %} {{ destination }} = {{ source }}.to_tuple() if {{ source }} else None diff --git a/openapi_python_client/templates/property_templates/list_property.pyi b/openapi_python_client/templates/property_templates/list_property.pyi index 91d29c37a..f06f0429d 100644 --- a/openapi_python_client/templates/property_templates/list_property.pyi +++ b/openapi_python_client/templates/property_templates/list_property.pyi @@ -1,8 +1,8 @@ -{% macro construct(property, source) %} +{% macro construct(property, source, initial_value="[]") %} {% set inner_property = property.inner_property %} {% if inner_property.template %} {% set inner_source = inner_property.python_name + "_data" %} -{{ property.python_name }} = [] +{{ property.python_name }} = {{ initial_value }} {% if property.required %} for {{ inner_source }} in ({{ source }}): {% else %} @@ -31,7 +31,7 @@ for {{ inner_source }} in {{ source }}: {% endmacro %} -{% macro transform(property, source, destination) %} +{% macro transform(property, source, destination, declare_type=True) %} {% set inner_property = property.inner_property %} {% if property.required %} {% if property.nullable %} @@ -43,7 +43,7 @@ else: {{ _transform(property, source, destination) }} {% endif %} {% else %} -{{ destination }}: Union[Unset, List[Any]] = UNSET +{{ destination }}{% if declare_type %}: Union[Unset, List[Any]]{% endif %} = UNSET if not isinstance({{ source }}, Unset): {% if property.nullable %} if {{ source }} is None: diff --git a/openapi_python_client/templates/property_templates/model_property.pyi b/openapi_python_client/templates/property_templates/model_property.pyi index c1fa0a3bb..eedb22235 100644 --- a/openapi_python_client/templates/property_templates/model_property.pyi +++ b/openapi_python_client/templates/property_templates/model_property.pyi @@ -1,14 +1,14 @@ -{% macro construct(property, source) %} +{% macro construct(property, source, initial_value=None) %} {% if property.required %} {{ property.python_name }} = {{ property.reference.class_name }}.from_dict({{ source }}) {% else %} -{{ property.python_name }} = None +{{ property.python_name }} = {{ initial_value }} if {{ source }} is not None: {{ property.python_name }} = {{ property.reference.class_name }}.from_dict(cast(Dict[str, Any], {{ source }})) {% endif %} {% endmacro %} -{% macro transform(property, source, destination) %} +{% macro transform(property, source, destination, declare_type=True) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.to_dict() if {{ source }} else None @@ -16,7 +16,7 @@ if {{ source }} is not None: {{ destination }} = {{ source }}.to_dict() {% endif %} {% else %} -{{ destination }}: {{ property.get_type_string() }} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): {% if property.nullable %} {{ destination }} = {{ source }}.to_dict() if {{ source }} else None diff --git a/openapi_python_client/templates/property_templates/none_property.pyi b/openapi_python_client/templates/property_templates/none_property.pyi index 300632e3c..b3178780a 100644 --- a/openapi_python_client/templates/property_templates/none_property.pyi +++ b/openapi_python_client/templates/property_templates/none_property.pyi @@ -1,7 +1,7 @@ -{% macro construct(property, source) %} -{{ property.python_name }} = None +{% macro construct(property, source, initial_value="None") %} +{{ property.python_name }} = {{ initial_value }} {% endmacro %} -{% macro transform(property, source, destination) %} +{% macro transform(property, source, destination, declare_type=True) %} {{ destination }} = None {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/union_property.pyi b/openapi_python_client/templates/property_templates/union_property.pyi index ba53528d6..114838b1c 100644 --- a/openapi_python_client/templates/property_templates/union_property.pyi +++ b/openapi_python_client/templates/property_templates/union_property.pyi @@ -1,17 +1,18 @@ -{% macro construct(property, source) %} -def _parse_{{ property.python_name }}(data: Dict[str, Any]) -> {{ property.get_type_string() }}: +{% macro construct(property, source, initial_value=None) %} +def _parse_{{ property.python_name }}(data: Any) -> {{ property.get_type_string() }}: + data = None if isinstance(data, Unset) else data {{ property.python_name }}: {{ property.get_type_string() }} {% for inner_property in property.inner_properties %} {% if inner_property.template and not loop.last %} try: {% from "property_templates/" + inner_property.template import construct %} - {{ construct(inner_property, source) | indent(8) }} + {{ construct(inner_property, "data", initial_value="UNSET") | indent(8) }} return {{ property.python_name }} except: # noqa: E722 pass {% elif inner_property.template and loop.last %}{# Don't do try/except for the last one #} {% from "property_templates/" + inner_property.template import construct %} - {{ construct(inner_property, source) | indent(4) }} + {{ construct(inner_property, "data", initial_value="UNSET") | indent(4) }} return {{ property.python_name }} {% else %} return {{ source }} @@ -21,9 +22,10 @@ def _parse_{{ property.python_name }}(data: Dict[str, Any]) -> {{ property.get_t {{ property.python_name }} = _parse_{{ property.python_name }}({{ source }}) {% endmacro %} -{% macro transform(property, source, destination) %} +{% macro transform(property, source, destination, declare_type=True) %} {% if not property.required %} -{{ destination }}: {{ property.get_type_string() }} +{{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} + if isinstance({{ source }}, Unset): {{ destination }} = UNSET {% endif %} @@ -33,7 +35,7 @@ if {{ source }} is None: {% else %}{# There's an if UNSET statement before this #} elif {{ source }} is None: {% endif %} - {{ destination }}: {{ property.get_type_string() }} = None + {{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} = None {% endif %} {% for inner_property in property.inner_properties %} {% if loop.first and property.required and not property.nullable %}{# No if UNSET or if None statement before this #} @@ -45,7 +47,7 @@ else: {% endif %} {% if inner_property.template %} {% from "property_templates/" + inner_property.template import transform %} - {{ transform(inner_property, source, destination) | indent(8) }} + {{ transform(inner_property, source, destination, declare_type=False) | indent(4) }} {% else %} {{ destination }} = {{ source }} {% endif %}