datamodel-code-generator icon indicating copy to clipboard operation
datamodel-code-generator copied to clipboard

Incorrect relative imports when using Modular Schema

Open Timur941 opened this issue 2 years ago • 3 comments

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:

  • OS: Windows 10
  • Python version: 3.10.6
  • datamodel-code-generator version: 0.22.0

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

Timur941 avatar Oct 05 '23 16:10 Timur941

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 ..

koxudaxi avatar Nov 08 '23 16:11 koxudaxi

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?

Timur941 avatar Nov 15 '23 13:11 Timur941