-
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
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
Fix openapi_types generation error in Python Flask's models #1256
Conversation
@lspvic thanks for the PR. What issue did you run into when having the value as string? I believe |
Look at the deserialization functions in the file def deserialize_model(data, klass):
"""Deserializes list or dict to model.
:param data: dict, list.
:type data: dict | list
:param klass: class literal.
:return: model object.
"""
instance = klass() # kclass must not be a str, it should be a type
if not instance.openapi_types:
return data
for attr, attr_type in six.iteritems(instance.openapi_types):
# attr_type is from openapi_types
if data is not None \
and instance.attribute_map[attr] in data \
and isinstance(data, (list, dict)):
value = data[instance.attribute_map[attr]]
setattr(instance, attr, _deserialize(value, attr_type))
# attr_type passes to _deserialize
return instance
def _deserialize(data, klass):
"""Deserializes dict, list, str into an object.
:param data: dict, list or str.
:param klass: class literal, or string of class name.
:return: object.
"""
if data is None:
return None
# if kclass is a str, none of the conditions satisfied and it finally goes to else block
if klass in six.integer_types or klass in (float, str, bool):
return _deserialize_primitive(data, klass)
elif klass == object:
return _deserialize_object(data)
elif klass == datetime.date:
return deserialize_date(data)
elif klass == datetime.datetime:
return deserialize_datetime(data)
elif type(klass) == typing.GenericMeta:
if klass.__extra__ == list:
return _deserialize_list(data, klass.__args__[0])
if klass.__extra__ == dict:
return _deserialize_dict(data, klass.__args__[1])
else:
return deserialize_model(data, klass) |
@lspvic what error message did you get? we do have tests to cover the deserialization, e.g. https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/python/tests/test_pet_api.py#L186 |
@wing328 The error is for generated server code, flaskConnexion , The test in the generated server code doesn't have called any deserialization, It just called the controller method only returned 'do some magic', e.g, I am really quite sure that's an error. |
@lspvic ah ok. Sorry I misunderstood it's an issue with the Python client. Let me review your change again. |
FYI, this change was introduced by #946 . I think it has been done to prevent circular imports but if because of this deserialization doesn't work, it means the fix was bad... |
I ran into this issue today so I can give an example of the error. Using openapi-generator 3.3.2, I have the generated Model class InlineObject1(Model):
"""NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
Do not edit the class manually.
"""
def __init__(self, name=None): # noqa: E501
"""InlineObject1 - a model defined in OpenAPI
:param name: The name of this InlineObject1. # noqa: E501
:type name: str
"""
self.openapi_types = {
'name': 'str'
}
self.attribute_map = {
'name': 'name'
}
self._name = name and in def data_post(inline_object1=None): # noqa: E501
"""
:param inline_object1:
:type inline_object1: dict | bytes
:rtype: str
"""
if connexion.request.is_json:
inline_object1 = InlineObject1.from_dict(connexion.request.get_json()) # noqa: E501
return 200 Then in my tests I have def test_data_post(self):
"""Test case for data_post
"""
inline_object1 = InlineObject1(name='testName')
response = self.client.open(
'/v0/data',
method='POST',
data=json.dumps(inline_object1),
content_type='application/json')
self.assert200(response, 'Response body is : ' + response.data.decode('utf-8')) While getting the response during the test I get the error
Which, as @lspvic describes, is because self.openapi_types = {
'name': str
} |
Yes, but now, don't you have missing imports for nested models ? |
Eg: self.openapi_types = {
'foo': Foo
} You would need to import models.Foo |
And if you import yourself, you get the circular import issue which resulted in the wrong fix in the beginning |
@cbornet please open an issue to track it. I think I can come up with a solution to fix the circular import. |
@lspvic thanks for the PR, which has been included in the v3.3.4 release: https://twitter.com/oas_generator/status/1068772409795207168 |
Running into the missing imports issue in 3.3.4. Is this tracked in an issue? Resolved? |
@ericraymond please open an issue for tracking. |
FYI. #1758 has been merged into master to avoid self-reference import. |
PR checklist
./bin/
to update Petstore sample so that CIs can verify the change. (For instance, only need to run./bin/{LANG}-petstore.sh
and./bin/security/{LANG}-petstore.sh
if updating the {LANG} (e.g. php, ruby, python, etc) code generator or {LANG} client's mustache templates). Windows batch files can be found in.\bin\windows\
.master
,3.4.x
,4.0.x
. Default:master
.Description of the PR
The generate model attribute
openapi_types
should be a dict map to data type(str
,int
) ortyping
List[str]
, not the string of them ('str'
,'int'
or'List[str]'
)Currently, generated codes are like those:
@taxpon (2017/07) @frol (2017/07) @mbohlool (2017/07) @cbornet (2017/09) @kenjones-cisco (2017/11)