swagger-api / swagger-api/swagger-codegen

[PYTHON] Maps of Lists are not converted to Dictionaries

Open
#9,847 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Mustache
Stars
17.8k
Forks
6k
PR merge metrics
No merged PRs in 30d

Description

Description

Per this documentation (https://swagger.io/docs/specification/data-models/dictionaries/)
the following is a valid swagger definition for a map with a string key and a value type of a list Of other objects...

someName:
  description: string map of lists example.
  type: object
  additionalProperties:
    type: array
    items:
      $ref: '#/definitions/SomeOtherObject'

However when an object with the property someName is converted to a dictionary using the generated to_dict method, someName will still contain a dictionary of a list of objects rather than a dictionary of a list of dictionaries i.e. the conversion does not recurse into the list.

Swagger-codegen version

bug seems to be in latest version of source

Steps to reproduce
  1. Create Yaml definition with above syntax
  2. Generate python library
  3. Create an instance of an object with affected property
  4. call to_dict on the instance
  5. verify that the type() of the list items is still an Object, not a dict.
Related issues/PRs

this PR came close to fixing things but not quite..
https://github.com/swagger-api/swagger-codegen/pull/2063/files

Suggest a fix/enhancement

It's a bit of a brain twister but I think to_dict should look more like this:-

    def to_dict(self):
        """Returns the model properties as a dict"""
        def val_to_dict(val):
            if hasattr(val, "to_dict"):
                return val.to_dict()
            elif isinstance(val, list):
                return list(map(
                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
                    val
                ))
            else:
                return val        
        
        result = {}

        for attr, _ in six.iteritems(self.swagger_types):
            value = getattr(self, attr)
            if isinstance(value, list):
                result[attr] = list(map(
                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
                    value
                ))
            elif hasattr(value, "to_dict"):
                result[attr] = value.to_dict()
            elif isinstance(value, dict):
                result[attr] = dict(map(
                    lambda item: (item[0], val_to_dict(item[1])),
                    value.items()
                ))
            else:
                result[attr] = value

        return result

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by generating a Python library from the Swagger definition in the reproduction steps and inspect the generated model's to_dict method. Reproduce the map-of-lists case, then compare the resulting value types with the expected nested dictionaries. Done means list items inside dictionary values are recursively converted without leaving generated objects in the result.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.