code generated for `date-time` fromat can not parse null response data
rihkddd opened this issue · 2 comments
Describe the bug
code generated for date-time fromat in models file like this for now:
_update_time = d.pop("updateTime", UNSET)
update_time: Union[Unset, datetime.datetime]
if isinstance(_update_time, Unset):
update_time = UNSET
else:
update_time = isoparse(_update_time)if response data of updateTime field is null, the _update_time variable will be set to None, so isoparse function will rasie TypeError except.
self = <dateutil.parser.isoparser.isoparser object at 0x7f94bf7ae950>, dt_str = None
def _parse_isodate_common(self, dt_str):
> len_str = len(dt_str)
E TypeError: object of type 'NoneType' has no len()
../../../../.local/lib/python3.10/site-packages/dateutil/parser/isoparser.py:213: TypeErrorOpenAPI Spec File
{
"updateTime": {
"type": "string",
"description": "updateTime",
"format": "date-time"
}
}Desktop (please complete the following information):
- OS: windows wsl ubuntu 22.0
- Python Version: 3.10.0
- openapi-python-client version 0.17.2
Additional context
my suggestion is, adding branch check value is None before call isoparse function, generate code like this:
_update_time = d.pop("updateTime", UNSET)
update_time: Union[Unset, datetime.datetime]
if isinstance(_update_time, Unset):
update_time = UNSET
elif _update_time is None:
update_time = None
else:
update_time = isoparse(_update_time)I also have this problem, but the issue lies in the spec.
The spec needs to define that response is nullable, otherwise your spec declares that you will always get a valid date-time string.
To do this, you can adjust your spec for openapi 3.0.x as such:
{
"updateTime": {
"type": "string",
"description": "updateTime",
"format": "date-time",
"nullable": true
}
}which will generate code similar to this:
def _parse_update_time(data: object) -> Union[None, Unset, datetime.datetime]:
if data is None:
return data
if isinstance(data, Unset):
return data
try:
if not isinstance(data, str):
raise TypeError()
update_time_type_0 = isoparse(data)
return update_time_type_0
except: # noqa: E722
pass
return cast(Union[None, Unset, datetime.datetime], data)
update_time = _parse_update_time(d.pop("updateTime", UNSET))OpenAPI 3.1 removed the nullable field in favor of just supplying more types via list:
{
"updateTime": {
"type": "string",
"description": "updateTime",
"format": ["date-time", "null"]
}
}For this I haven't tested generation and can't really speak about it.
My situation is sadly that I'm using external provider's OpenAPI specification, which is not likely to be updated any time soon.
@dbanty If it is an option to generally support implicit null values in date-time and maybe others, where parsing will break unexpectedly, I'm happy to take a look at implementing this.
@texhnolyze Thanks for the spec you pointing out, also your situation is very common that OpenAPI specification user cannot expect provider keep it fully compliant specifications.
Fortunately, I found a proper way to solve this issue, using custom templates by modify this line
to, hope this solution also can help you.
if {{ source }} and not isinstance({{ source }}, Unset):