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

Model class names are missing the last letter in models generated from 2020-12 JSON schema specification

Open BraedonLeonard opened this issue 1 year ago • 1 comments

Describe the bug When generating data models from the 2020-12 JSON schema specification, all direct subclasses of BaseModel are missing the last letter in their class name. For example:

class Unevaluate(BaseModel):
    unevaluatedItems: Optional[Any] = None
    unevaluatedProperties: Optional[Any] = None

This class should generate with the name Unevaluated, but it instead generates with the name Unevaluate.

To Reproduce

Example schema: https://json-schema.org/draft/2020-12/schema

Used commandline:

$ datamodel-codegen --url https://json-schema.org/draft/2020-12/schema --input-file-type jsonschema --output model.py --output-model-type pydantic_v2.BaseModel

Expected behavior

The expected behaviour is for the class names to not be missing the final letter in their names.

Version:

  • OS: macOS 14.5
  • Python version: 3.12.3
  • datamodel-code-generator version: 0.25.8

Additional context

I'm pretty sure I know how to fix this, but I don't feel like I have enough context to understand all the implications of this change.

In reference.py at line 567, we have this piece of code:

        if len(split_ref) == 1:
            original_name = Path(
                split_ref[0][:-1] if self.is_external_root_ref(path) else split_ref[0]
            ).stem
        else:
            original_name = (
                Path(split_ref[1][:-1]).stem
                if self.is_external_root_ref(path)
                else split_ref[1]
            )

The problem seems to happen in the case where ref does not have the ending #, but the path does. For example, when path is 'https://json-schema.org/draft/2020-12/meta/core#' and ref is 'meta/core'. In this case, it seems you can replace the [:1] indexing with .rstrip('#') to make it so that it will still drop the # without ever cutting off the end of the word.

        if len(split_ref) == 1:
            original_name = Path(
                split_ref[0].rstrip('#')
                if self.is_external_root_ref(path)
                else split_ref[0]
            ).stem
        else:
            original_name = (
                Path(split_ref[1].rstrip('#')).stem
                if self.is_external_root_ref(path)
                else split_ref[1]
            )

This code change does pass all of the tests, but I'm just not certain about whether this change is fixing the root cause or not. For all I know, the path having a # at the end and the ref not having one is the true root cause, I just don't feel like I have enough familiarity to say.

BraedonLeonard avatar Jul 11 '24 22:07 BraedonLeonard

I have the same problem and would love to be able to have this fixed.

sixdimensionalarray avatar Aug 07 '24 19:08 sixdimensionalarray