Datamodel-code-generator: codegen for enum with empty string

Created on 21 Mar 2021  路  11Comments  路  Source: koxudaxi/datamodel-code-generator

Is your feature request related to a problem? Please describe.

Environment

datamodel-code-generator==0.9.3

Scenario

Wanted to generate pydantic models from docker engine API.

datamodel-codegen --url "https://converter.swagger.io/api/convert?url=https://docs.docker.com/engine/api/v1.30.yaml"

Note that docker engine api uses openapi 2.0 spec. Therefore, I used converter.swagger.io to translate it into 3.0.0.

Error message

Traceback (most recent call last):
  File "<my_path>/python3.7/site-packages/datamodel_code_generator/__main__.py", line 424, in main
    strict_types=config.strict_types,
  File "<my_path>/python3.7/site-packages/datamodel_code_generator/__init__.py", line 311, in generate
    results = parser.parse()
  File "<my_path>/python3.7/site-packages/datamodel_code_generator/parser/base.py", line 386, in parse
    self.parse_raw()
  File "<my_path>/python3.7/site-packages/datamodel_code_generator/parser/openapi.py", line 34, in parse_raw
    [*path_parts, '#/components', 'schemas', obj_name],
  File "<my_path>/python3.7/site-packages/datamodel_code_generator/parser/jsonschema.py", line 997, in parse_raw_obj
    self.parse_obj(name, JsonSchemaObject.parse_obj(raw), path)
  File "<my_path>/python3.7/site-packages/datamodel_code_generator/parser/jsonschema.py", line 1002, in parse_obj
    self.parse_object(name, obj, path)
  File "<my_path>/python3.7/site-packages/datamodel_code_generator/parser/jsonschema.py", line 624, in parse_object
    fields=self.parse_object_fields(obj, path),
  File "<my_path>/python3.7/site-packages/datamodel_code_generator/parser/jsonschema.py", line 571, in parse_object_fields
    field_type = self.parse_enum(field_name, field, [*path, field_name])
  File "<my_path>/python3.7/site-packages/datamodel_code_generator/parser/jsonschema.py", line 820, in parse_enum
    name=self.model_resolver.get_valid_name(field_name),
  File "<my_path>/python3.7/site-packages/datamodel_code_generator/reference.py", line 362, in get_valid_name
    if name[0] == '#':
IndexError: string index out of range

Cause

The docker engine openapi spec defines a schema with an Enum that contains an empty string:

    RestartPolicy:
      type: object
      properties:
        Name:
          type: string
          description: ...
          enum:
          - ""   # here
          - always
          - unless-stopped
          - on-failure

It seems that get_valid_name cannot handle empty strings.

Describe the solution you'd like

I've tested the following workaround by changing the function get_valid_name as below.

def get_valid_name(self, name: str, camel: bool = False) -> str:
    if not name:    # +
        return "_"     # +
    if name.isidentifier():
        return name
    if name[0] == '#':
        name = name[1:]   # note that original error is caused here. 
    ...

The resulting enum is

class Name(Enum):
    """
        - Empty string means not to restart
    - `always` Always restart
    - `unless-stopped` Restart always except when the user has manually stopped the container
    - `on-failure` Restart only when the container exit code is non-zero

    """

    _ = ''
    always = 'always'
    unless_stopped = 'unless-stopped'
    on_failure = 'on-failure'

Describe alternatives you've considered

If we are targeting python 3.8 and above, this issue can be easily mitigated by using --enum-field-as-literal all.
Therefore this issue can be resolved by allowing --enum-field-as-literal option in python 3.7 by importing Literal from typing_extensions.

Most helpful comment

Thank you too!

All 11 comments

@yuyupopo
Thank you for creating this issue.
I want to fix it.
I think If the enum value is '' then, the field name empty is better than _.

@yuyupopo
Thank you for creating this issue.
I want to fix it.
I think If the enum value is '' then, the field name empty is better than _.

I believe it is highly unlikely, but what if enum is given as below?

enum:
          - "" 
          - empty

Also, I've tried a quick fix importing Literal from typing_extensions if target python version is lower than 3.8.
https://github.com/yuyupopo/datamodel-code-generator feel free to check it out.

I believe it is highly unlikely, but what if enum is given as below?

I just want to say the same problem now :(
OK, I will convert the field name to _.

Also, I've tried a quick fix importing Literal from typing_extensions if target python version is lower than 3.8

I feel a good workaround, But users may need enum.

Then what about, --empty-enum-field-value option that can accept an arbitrary string? The option has empty as default (or _), and users can change it if they want to.

--empty-enum-field-name is more strict ?

--empty-enum-field-name is more strict ?

Yeah, I believe that's a better name

OK, I will fix it soon. Thank you

Also, what do you think about this?

Importing Literal from typing_extensions if target python version is lower than 3.8

Do you feel it necessary? If it does, should I open a new issue, or just create a new PR for it?

Do you feel it necessary? If it does, should I open a new issue, or just create a new PR for it?

I welcome a new issue and PR!!

@yuyupopo
I have released a new version as 0.9.4
Thank you very much!!

Thank you too!

Was this page helpful?
0 / 5 - 0 ratings