-
-
Notifications
You must be signed in to change notification settings - Fork 228
Fix deserialization of unions #332
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
4e30205
fda721a
10926f1
465943d
9ec7394
db33752
49185f0
b71f718
c251560
0d79ce8
3c536f7
8a72732
b5fa15d
43969ae
2c4fdf8
caea77a
da1d970
682c5ab
39faebf
55496e5
1ddd486
8bc76af
0d90970
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import datetime | ||
from typing import Any, Dict, List, Optional, Type, TypeVar, Union | ||
from typing import Any, Dict, List, Optional, Type, TypeVar, Union, cast | ||
|
||
import attr | ||
from dateutil.parser import isoparse | ||
|
@@ -10,6 +10,8 @@ | |
from ..models.a_model_nullable_model import AModelNullableModel | ||
from ..models.an_enum import AnEnum | ||
from ..models.different_enum import DifferentEnum | ||
from ..models.free_form_model import FreeFormModel | ||
from ..models.model_with_union_property import ModelWithUnionProperty | ||
from ..types import UNSET, Unset | ||
|
||
T = TypeVar("T", bound="AModel") | ||
|
@@ -23,17 +25,21 @@ class AModel: | |
a_camel_date_time: Union[datetime.datetime, datetime.date] | ||
a_date: datetime.date | ||
required_not_nullable: str | ||
one_of_models: Union[FreeFormModel, ModelWithUnionProperty] | ||
model: AModelModel | ||
a_nullable_date: Optional[datetime.date] | ||
required_nullable: Optional[str] | ||
nullable_one_of_models: Union[None, FreeFormModel, ModelWithUnionProperty] | ||
nullable_model: Optional[AModelNullableModel] | ||
nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET | ||
a_not_required_date: Union[Unset, datetime.date] = UNSET | ||
attr_1_leading_digit: Union[Unset, str] = UNSET | ||
not_required_nullable: Union[Unset, Optional[str]] = UNSET | ||
not_required_nullable: Union[Unset, None, str] = UNSET | ||
not_required_not_nullable: Union[Unset, str] = UNSET | ||
not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET | ||
not_required_nullable_model: Union[Optional[AModelNotRequiredNullableModel], Unset] = UNSET | ||
not_required_one_of_models: Union[Unset, FreeFormModel, ModelWithUnionProperty] = UNSET | ||
not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str] = UNSET | ||
not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET | ||
not_required_nullable_model: Union[Unset, None, AModelNotRequiredNullableModel] = UNSET | ||
|
||
def to_dict(self) -> Dict[str, Any]: | ||
an_enum_value = self.an_enum_value.value | ||
|
@@ -46,6 +52,12 @@ def to_dict(self) -> Dict[str, Any]: | |
|
||
a_date = self.a_date.isoformat() | ||
required_not_nullable = self.required_not_nullable | ||
if isinstance(self.one_of_models, FreeFormModel): | ||
one_of_models = self.one_of_models.to_dict() | ||
|
||
else: | ||
one_of_models = self.one_of_models.to_dict() | ||
|
||
model = self.model.to_dict() | ||
|
||
nested_list_of_enums: Union[Unset, List[Any]] = UNSET | ||
|
@@ -69,13 +81,53 @@ def to_dict(self) -> Dict[str, Any]: | |
required_nullable = self.required_nullable | ||
not_required_nullable = self.not_required_nullable | ||
not_required_not_nullable = self.not_required_not_nullable | ||
nullable_one_of_models: Union[None, Dict[str, Any]] | ||
if self.nullable_one_of_models is None: | ||
nullable_one_of_models = None | ||
elif isinstance(self.nullable_one_of_models, FreeFormModel): | ||
nullable_one_of_models = self.nullable_one_of_models.to_dict() | ||
|
||
else: | ||
nullable_one_of_models = self.nullable_one_of_models.to_dict() | ||
|
||
not_required_one_of_models: Union[Unset, Dict[str, Any]] | ||
if isinstance(self.not_required_one_of_models, Unset): | ||
not_required_one_of_models = UNSET | ||
elif isinstance(self.not_required_one_of_models, FreeFormModel): | ||
not_required_one_of_models = UNSET | ||
if not isinstance(self.not_required_one_of_models, Unset): | ||
not_required_one_of_models = self.not_required_one_of_models.to_dict() | ||
|
||
else: | ||
not_required_one_of_models = UNSET | ||
if not isinstance(self.not_required_one_of_models, Unset): | ||
not_required_one_of_models = self.not_required_one_of_models.to_dict() | ||
|
||
not_required_nullable_one_of_models: Union[Unset, None, Dict[str, Any], str] | ||
if isinstance(self.not_required_nullable_one_of_models, Unset): | ||
not_required_nullable_one_of_models = UNSET | ||
elif self.not_required_nullable_one_of_models is None: | ||
not_required_nullable_one_of_models = None | ||
elif isinstance(self.not_required_nullable_one_of_models, FreeFormModel): | ||
not_required_nullable_one_of_models = UNSET | ||
if not isinstance(self.not_required_nullable_one_of_models, Unset): | ||
not_required_nullable_one_of_models = self.not_required_nullable_one_of_models.to_dict() | ||
|
||
elif isinstance(self.not_required_nullable_one_of_models, ModelWithUnionProperty): | ||
not_required_nullable_one_of_models = UNSET | ||
if not isinstance(self.not_required_nullable_one_of_models, Unset): | ||
not_required_nullable_one_of_models = self.not_required_nullable_one_of_models.to_dict() | ||
|
||
else: | ||
not_required_nullable_one_of_models = self.not_required_nullable_one_of_models | ||
|
||
nullable_model = self.nullable_model.to_dict() if self.nullable_model else None | ||
|
||
not_required_model: Union[Unset, Dict[str, Any]] = UNSET | ||
if not isinstance(self.not_required_model, Unset): | ||
not_required_model = self.not_required_model.to_dict() | ||
|
||
not_required_nullable_model: Union[None, Unset, Dict[str, Any]] = UNSET | ||
not_required_nullable_model: Union[Unset, None, Dict[str, Any]] = UNSET | ||
if not isinstance(self.not_required_nullable_model, Unset): | ||
not_required_nullable_model = ( | ||
self.not_required_nullable_model.to_dict() if self.not_required_nullable_model else None | ||
|
@@ -88,9 +140,11 @@ def to_dict(self) -> Dict[str, Any]: | |
"aCamelDateTime": a_camel_date_time, | ||
"a_date": a_date, | ||
"required_not_nullable": required_not_nullable, | ||
"one_of_models": one_of_models, | ||
"model": model, | ||
"a_nullable_date": a_nullable_date, | ||
"required_nullable": required_nullable, | ||
"nullable_one_of_models": nullable_one_of_models, | ||
"nullable_model": nullable_model, | ||
} | ||
) | ||
|
@@ -104,6 +158,10 @@ def to_dict(self) -> Dict[str, Any]: | |
field_dict["not_required_nullable"] = not_required_nullable | ||
if not_required_not_nullable is not UNSET: | ||
field_dict["not_required_not_nullable"] = not_required_not_nullable | ||
if not_required_one_of_models is not UNSET: | ||
field_dict["not_required_one_of_models"] = not_required_one_of_models | ||
if not_required_nullable_one_of_models is not UNSET: | ||
field_dict["not_required_nullable_one_of_models"] = not_required_nullable_one_of_models | ||
if not_required_model is not UNSET: | ||
field_dict["not_required_model"] = not_required_model | ||
if not_required_nullable_model is not UNSET: | ||
|
@@ -116,15 +174,18 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: | |
d = src_dict.copy() | ||
an_enum_value = AnEnum(d.pop("an_enum_value")) | ||
|
||
def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.date]: | ||
data = None if isinstance(data, Unset) else data | ||
def _parse_a_camel_date_time(data: object) -> Union[datetime.datetime, datetime.date]: | ||
a_camel_date_time: Union[datetime.datetime, datetime.date] | ||
try: | ||
if not isinstance(data, str): | ||
raise TypeError() | ||
a_camel_date_time = isoparse(data) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think letting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I see, this is here to get the correct Union option more easily? Maybe then we need to exclude it if no Union? Not really necessary for this PR, there are plenty of things like this that need cleanup at some point. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, yeah, this is just a special case when there's a union of only 1 element. I think it's pretty unlikely to happen in actual usage. Let me try to fix it though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Turns out to be unnecessary if we're changing the input type to be |
||
|
||
return a_camel_date_time | ||
except: # noqa: E722 | ||
pass | ||
if not isinstance(data, str): | ||
raise TypeError() | ||
a_camel_date_time = isoparse(data).date() | ||
|
||
return a_camel_date_time | ||
|
@@ -135,6 +196,24 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat | |
|
||
required_not_nullable = d.pop("required_not_nullable") | ||
|
||
def _parse_one_of_models(data: object) -> Union[FreeFormModel, ModelWithUnionProperty]: | ||
one_of_models: Union[FreeFormModel, ModelWithUnionProperty] | ||
try: | ||
if not isinstance(data, dict): | ||
raise TypeError() | ||
one_of_models = FreeFormModel.from_dict(data) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here re: confusion. If we can't be confident in the data passed in, the type annotation should be I think the only reason this would be the wrong data type is if the OpenAPI spec was wrong or someone made a breaking change to the API. Either way we can't properly handle all the cases that could fail. So I think just the proper type annotation without the runtime check is probably the better approach? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's a good point. Actually initially I didn't have a runtime check, but then MyPy throws an error, because it's not type-safe. I'm starting to think that maybe the original There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good regarding |
||
|
||
return one_of_models | ||
except: # noqa: E722 | ||
pass | ||
if not isinstance(data, dict): | ||
raise TypeError() | ||
one_of_models = ModelWithUnionProperty.from_dict(data) | ||
|
||
return one_of_models | ||
|
||
one_of_models = _parse_one_of_models(d.pop("one_of_models")) | ||
|
||
model = AModelModel.from_dict(d.pop("model")) | ||
|
||
nested_list_of_enums = [] | ||
|
@@ -167,12 +246,96 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat | |
|
||
not_required_not_nullable = d.pop("not_required_not_nullable", UNSET) | ||
|
||
def _parse_nullable_one_of_models(data: object) -> Union[None, FreeFormModel, ModelWithUnionProperty]: | ||
nullable_one_of_models: Union[None, FreeFormModel, ModelWithUnionProperty] | ||
if data is None: | ||
return data | ||
try: | ||
if not isinstance(data, dict): | ||
raise TypeError() | ||
nullable_one_of_models = FreeFormModel.from_dict(data) | ||
|
||
return nullable_one_of_models | ||
except: # noqa: E722 | ||
pass | ||
if not isinstance(data, dict): | ||
raise TypeError() | ||
nullable_one_of_models = ModelWithUnionProperty.from_dict(data) | ||
|
||
return nullable_one_of_models | ||
|
||
nullable_one_of_models = _parse_nullable_one_of_models(d.pop("nullable_one_of_models")) | ||
|
||
def _parse_not_required_one_of_models(data: object) -> Union[Unset, FreeFormModel, ModelWithUnionProperty]: | ||
not_required_one_of_models: Union[Unset, FreeFormModel, ModelWithUnionProperty] | ||
if isinstance(data, Unset): | ||
return data | ||
try: | ||
if not isinstance(data, dict): | ||
raise TypeError() | ||
not_required_one_of_models = UNSET | ||
_not_required_one_of_models = data | ||
if not isinstance(_not_required_one_of_models, Unset): | ||
not_required_one_of_models = FreeFormModel.from_dict(_not_required_one_of_models) | ||
|
||
return not_required_one_of_models | ||
except: # noqa: E722 | ||
pass | ||
if not isinstance(data, dict): | ||
raise TypeError() | ||
not_required_one_of_models = UNSET | ||
_not_required_one_of_models = data | ||
if not isinstance(_not_required_one_of_models, Unset): | ||
not_required_one_of_models = ModelWithUnionProperty.from_dict(_not_required_one_of_models) | ||
|
||
return not_required_one_of_models | ||
|
||
not_required_one_of_models = _parse_not_required_one_of_models(d.pop("not_required_one_of_models", UNSET)) | ||
|
||
def _parse_not_required_nullable_one_of_models( | ||
data: object, | ||
) -> Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str]: | ||
not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str] | ||
if data is None: | ||
return data | ||
if isinstance(data, Unset): | ||
return data | ||
try: | ||
if not isinstance(data, dict): | ||
raise TypeError() | ||
not_required_nullable_one_of_models = UNSET | ||
_not_required_nullable_one_of_models = data | ||
if not isinstance(_not_required_nullable_one_of_models, Unset): | ||
not_required_nullable_one_of_models = FreeFormModel.from_dict(_not_required_nullable_one_of_models) | ||
|
||
return not_required_nullable_one_of_models | ||
except: # noqa: E722 | ||
pass | ||
try: | ||
if not isinstance(data, dict): | ||
raise TypeError() | ||
not_required_nullable_one_of_models = UNSET | ||
_not_required_nullable_one_of_models = data | ||
if not isinstance(_not_required_nullable_one_of_models, Unset): | ||
not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict( | ||
_not_required_nullable_one_of_models | ||
) | ||
|
||
return not_required_nullable_one_of_models | ||
except: # noqa: E722 | ||
pass | ||
return cast(Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str], data) | ||
|
||
not_required_nullable_one_of_models = _parse_not_required_nullable_one_of_models( | ||
d.pop("not_required_nullable_one_of_models", UNSET) | ||
) | ||
|
||
nullable_model = None | ||
_nullable_model = d.pop("nullable_model") | ||
if _nullable_model is not None: | ||
nullable_model = AModelNullableModel.from_dict(_nullable_model) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm surprised There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it's because |
||
|
||
not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET | ||
not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET | ||
_not_required_model = d.pop("not_required_model", UNSET) | ||
if not isinstance(_not_required_model, Unset): | ||
not_required_model = AModelNotRequiredModel.from_dict(_not_required_model) | ||
|
@@ -187,6 +350,7 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat | |
a_camel_date_time=a_camel_date_time, | ||
a_date=a_date, | ||
required_not_nullable=required_not_nullable, | ||
one_of_models=one_of_models, | ||
model=model, | ||
nested_list_of_enums=nested_list_of_enums, | ||
a_nullable_date=a_nullable_date, | ||
|
@@ -195,6 +359,9 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat | |
required_nullable=required_nullable, | ||
not_required_nullable=not_required_nullable, | ||
not_required_not_nullable=not_required_not_nullable, | ||
nullable_one_of_models=nullable_one_of_models, | ||
not_required_one_of_models=not_required_one_of_models, | ||
not_required_nullable_one_of_models=not_required_nullable_one_of_models, | ||
nullable_model=nullable_model, | ||
not_required_model=not_required_model, | ||
not_required_nullable_model=not_required_nullable_model, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will have to check later why this is the case. I assume there's some difficulty with handling the type in the template which is why we're checking multiple isinstances here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the OpenAPI:
My guess is that the inner properties are not required? Kind of confusing what the semantics should be...