OpenAPITools / OpenAPITools/openapi-generator
[BUG][python-flask] converting to and from dict with camelCase properties
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator (example)?
- What's the version of OpenAPI Generator used? --> 4.2.1
- Have you search for related issues/PRs?
- What's the actual output vs expected output?
Description
When i have a model defined in OpenAPI, which uses camelCase Properties the generator automatically converts the python props to pythonic snake_case Names. So far, so good.
When using the from_dict(dict) method of the Model class it is taking a dict with the snakeCase properties as Keys and converts them at instantiation. This is super cool and useful, as we can directly pass a dict, created from JSON payload, as is.
But, with an existing model, when I call the to_dict() method on it, i get a dict, which has the snake_case prop names as Key!
This means, that have inconsistency in converting a model to dict, and creating one from the dict again. as this will fail for all props having a camelCase name (see example). I believe this behaviour is not intended. I´d expect the to_dict() method to produce the camelCase prop names (which are available in the attribute_map anyway.
Example:
# create a new instance of MyModel
model = MyModel(demo_name="name", id=1)
# Property has snake_case Name: demoName --> demo_name
log.warn("Model is: {}".format(model))
# OUTPUT: WARNING in demo_controller: Model is: {'demo_name': 'name', 'id': 1}
# using to_dict method to get a dict from Model
model_dict = model.to_dict()
log.warn("Model.to_dict() is: {}".format(model_dict))
# OUTPUT: WARNING in demo_controller: Model.to_dict() is: {'demo_name': 'name', 'id': 1}
# now we want to convert that dict (probably fetched from DB) back to our Model
new_model = MyModel.from_dict(model_dict)
log.warn("New Created Model is: {}".format(new_model))
# OUTPUT: WARNING in demo_controller: New Created Model is: {'demo_name': None, 'id': 1}
# --> demo_name = None !!!!
openapi-generator version
4.2.1
OpenAPI declaration file content or url
openapi: 3.0.0
info:
title: DEMO for issue
version: "1.0"
servers:
- url: http://localhost:8080
tags:
- name: demo
paths:
/demo:
get:
operationId: get_demo
responses:
200:
content:
application/json:
schema:
$ref: '#/components/schemas/MyModel'
description: Demo Response
tags:
- demo
x-openapi-router-controller: openapi_server.controllers.demo_controller
components:
schemas:
MyModel:
example:
demoName: demoName
id: 0
properties:
demoName:
type: string
id:
type: integer
type: object
Command line used for generation
openapi-generator generate -g python-flask -i base_model_dict.yml -o api
Steps to reproduce
clone the demo api i build for reproducing this
git clone https://github.com/Shogoki/openapi-to_dict-demo.git
build and start the API
cd openapi-to_dict_demo && docker-compose up
in a Browser, or another terminal issue a GET call to localhost:8080/demo , e.g.
curl http://localhost:8080/demo
Watch the Log output of the API.
Related issues/PRs
don´t know...
Suggest a fix
I successfully fixed the issue in some of my projects by patching the to_dict method in base_model_.py as follows:
def to_dict(self):
"""Returns the model properties as a dict
:rtype: dict
"""
result = {}
for attr, _ in six.iteritems(self.openapi_types):
value = getattr(self, attr)
dict_attr = self.attribute_map[attr]
if isinstance(value, list):
result[dict_attr] = list(map(
lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
value
))
elif hasattr(value, "to_dict"):
result[dict_attr] = value.to_dict()
elif isinstance(value, dict):
result[dict_attr] = dict(map(
lambda item: (item[0], item[1].to_dict())
if hasattr(item[1], "to_dict") else item,
value.items()
))
else:
result[dict_attr] = value
return result
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the generated base_model_.py template and reproduce the issue using the provided OpenAPI declaration and python-flask generation command. Check the existing to_dict() and from_dict() behavior, then run the generated API or equivalent model checks; done means camelCase attribute_map keys round-trip through both methods without losing demoName.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend-api-design, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100