koxudaxi / datamodel-code-generator

Pydantic model and dataclasses.dataclass generator for easy conversion of JSON, OpenAPI, JSON Schema, and YAML data sources.
https://koxudaxi.github.io/datamodel-code-generator/
MIT License
2.66k stars 296 forks source link

the generated class (apeared in jsonschema) doesn't keep the same name as jsonschema, when it refers other jsonschema file(s). #1300

Open itaru2622 opened 1 year ago

itaru2622 commented 1 year ago

Describe the bug my assumed usecase is shown in figure. in this use-case, the same definition name('Target' in this report) appears in lots of places within multiple jsonschema files, but it is normal condition.

I have three jsonschema, 3def.json is the input to datamodel-code-generator. 1def.json, 2def.json are refered from above 3def.json

assumed-usecase

To Reproduce

Example schema:

3def.json(input to datamodel-code-generator)

{
  "definitions": {
    "Target": {
      "allOf": [
        {
          "anyOf": [
            {
              "$ref": "1def.json#/definitions/Target"
            },
            {
              "$ref": "2def.json#/definitions/Target"
            }
          ]
        },
        {
          "properties": {
            "final_model_to_be_used": {
              "type": "string"
            }
          },
          "required": [
            "final_model_to_be_used"
          ]
        }
      ]
    }
  }
}

1def.json (refered from 3def.json)

{
  "definitions": {
    "First": {
      "properties": {
        "first": {
          "type": "string"
        }
      },
      "required": [
        "first"
      ]
    },
    "Target": {
      "allOf": [
        {
          "$ref": "#/definitions/First"
        },
        {
          "properties": {
            "attrOrigin": {
              "type": "integer"
            }
          },
          "required": [
            "attrOrigin"
          ]
        }
      ]
    }
  }
}

2def.json(refered from 3def.json):

{
  "definitions": {
    "Target": {
      "allOf": [
        {
          "$ref": "1def.json#/definitions/First"
        },
        {
          "properties": {
            "attr_changed_in_2def": {
              "type": "array",
              "items": {
                "type": "number"
              }
            }
          },
          "required": [
            "attr_changed_in_2def"
          ]
        }
      ]
    }
  }
}

produced classes at current:

# generated by datamodel-codegen:
#   filename:  3def.json

from typing import Any, List, Union
from pydantic import BaseModel

class Target2(BaseModel):
    final_model_to_be_used: str

class First(BaseModel):
    first: str

class Target(First):                               # the name 'Target' is used by other place than expected. 
    attr_changed_in_2def: List[float]

class Target4(Target, Target2):
    pass

class TargetModel(First):
    attrOrigin: int

class Target3(TargetModel, Target2):
    pass

class Target1(BaseModel):        # this class should have the name 'Target' to keep the same as input jsonschema(3def.json)
    __root__: Union[Target3, Target4] 

Used commandline:

$ ls # make sure all schema exists in the local machine.
   1def.json 2def.json 3def.json
$ datamodel-codegen --input-file-type jsonschema      --input 3def.json

Expected behavior The below classes expected to be genrated:

:
class Target2(BaseModel):
    final_model_to_be_used: str

class First(BaseModel):
    first: str

class TargetX(First):                            # the class generated by refering has suffix in its name.
    attr_changed_in_2def: List[float]

class Target4(TargetX, Target2):
    pass

class TargetModel(First):
    attrOrigin: int

class Target3(TargetModel, Target2):
    pass

class Target(BaseModel): # generated class  keeps the same name as input  jsonschema(3def.json)
    __root__: Union[Target3, Target4]

Version:

Additional context none.

koxudaxi commented 1 year ago

@itaru2622 Thank you for creating the issue.

class Target(BaseModel): # generated class keeps the same name as input jsonschema(3def.json)

make sense. But, it isn't easy to decide the name priority. Because Allof may not need to be a model. :sweat_smile:

https://github.com/koxudaxi/datamodel-code-generator/blob/d34d2816de032021a57e0fce8c634a0be971a726/datamodel_code_generator/parser/jsonschema.py#L742-L749

reference = self.model_resolver.add(path, name, class_name=True, loaded=True)

After checking the result of parsing child nodes, the method reserves the model name with path and name. We need a new method to change the reserved name.

itaru2622 commented 1 year ago

@koxudaxi Thank you for your response and hint.

Please consider this issue when fixing #796. I guess, if the path has the jsonschema file name besides parent schema name, then both of this issue and #796 may be fixed at once.