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.75k stars 301 forks source link

Incorrect relative imports when using Modular Schema #1600

Open Timur941 opened 1 year ago

Timur941 commented 1 year ago

Describe the bug When generating models from the openapi specification and when the names of the schemas contain dots, incorrect imports are generated inside init.py for modules that are actually located in the same directory

Only inside init.py the extra dot in the import statement is added. In other generated .py files, imports are generated correct

To Reproduce

Example schema:


{
  "openapi": "3.0.2",
  "info": {
    "title": "Swagger",
    "version": "1.0.17"
  },
  "paths": {
  },
  "components": {
    "schemas": {
      "A.B.C": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "example": 10
          },
          "reference": {
            "$ref": "#/components/schemas/A.B.D.E"
          }
        }
      },
      "A.B.D.E": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "example": 10
          }
        }
      }
    }
  }
}

Used commandline:

$ datamodel-codegen --input swagger.json --output model --input-file-type openapi

Actual behavior The following file and folder structure was created

.
└── model/
    └── A/
        ├── B/
        │   ├── D.py
        │   └── __init__.py
        └── __init__.py

Code for init.py inside B folder

# generated by datamodel-codegen:
#   filename:  swagger.json
#   timestamp: 2023-10-05T14:48:13+00:00

from __future__ import annotations

from typing import Optional

from pydantic import BaseModel, Field

from .. import D

class C(BaseModel):
    id: Optional[int] = Field(None, example=10)
    reference: Optional[D.E] = None

There are one extra '.' in 'from .. import D' statement because module D is in the same directory

Trying to use a class from that init.py and getting error

from model.A.B import C

c = C(id=10)
PS C:\Projects\model-test> python .\test.py
Traceback (most recent call last):
  File "C:\Projects\model-test\test.py", line 1, in <module>
    from model.A.B import C
  File "C:\Projects\model-test\model\A\B\__init__.py", line 11, in <module>
    from .. import D
ImportError: cannot import name 'D' from 'model.A' (C:\Projects\model-test\model\A\__init__.py)

Expected behavior Relative Import inside init.py should not contain an extra dot in situations where reference to a module in the same directory is used

For init.py code from above it expected to look like this

# generated by datamodel-codegen:
#   filename:  swagger.json
#   timestamp: 2023-10-05T14:48:13+00:00

from __future__ import annotations

from typing import Optional

from pydantic import BaseModel, Field

from . import D

class C(BaseModel):
    id: Optional[int] = Field(None, example=10)
    reference: Optional[D.E] = None

Version:

Additional context I guess such behavior is related to these lines of code in parser/base.py https://github.com/koxudaxi/datamodel-code-generator/blob/60256efafc34377e93640134bbed757e579acfb3/datamodel_code_generator/parser/base.py#L688-L690

koxudaxi commented 12 months ago

Thank you for creating the issue. I'm sorry for my late reply. I found the same issue https://github.com/koxudaxi/datamodel-code-generator/issues/1638

I guess some users use . in schema name. They want to define the schema as a module.

https://github.com/koxudaxi/datamodel-code-generator/blob/979444cdd4cbfbfab489f6f4c9bb09f8eaf8553b/tests/data/openapi/modular.yaml#L243

https://github.com/koxudaxi/datamodel-code-generator/blob/979444cdd4cbfbfab489f6f4c9bb09f8eaf8553b/tests/data/expected/main/main_modular/woo/boo.py#L14

I am considering introducing an option to exclude . from the schema name. The CLI should Introduce the option as a warning if the model name contains a ..

Timur941 commented 11 months ago

I think the option is a good solution. In my case it would be quite enough to exclude . from the title and concat its parts into one PascalCase word to generate just one output file. But what if it is necessary to maintain a modular structure with all these directories? As I understand, the imports error mentioned in this issue will persist?