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

AttributeError: 'NoneType' object has no attribute 'is_list'

Open comic31 opened this issue 1 year ago • 3 comments

Describe the bug

Fail to generate python code with an array of $ref from an allof, an AttributeError has been raised by the lib.

If this is not a bug, please let me know if I'm doing something wrong.

To Reproduce

Example schema:

    PetOpts:
      type: string
    ProjectedPet:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
        tag:
          type: string
        opts:
          type: array
          items:
            $ref: "#/components/schemas/PetOpts"
    Pet:
      allOf:
        - $ref: "#/components/schemas/ProjectedPet"
      required:
          - id
          - name
          - opts

Used commandline:

datamodel-codegen --input api.yaml --output model.py --input-file-type openapi --use-annotated --collapse-root-models  --use-standard-collections --capitalize-enum-members  --target-python-version 3.10 --output-model-type pydantic_v2.BaseModel

Actual behavior

AttributeError: 'NoneType' object has no attribute 'is_list'

Expected behavior

class ProjectedPet(BaseModel):
    id: Optional[int] = None
    name: Optional[str] = None
    tag: Optional[str] = None
    opts: Optional[list[str]] = None


class Pet(ProjectedPet):
    id: int
    name: str
    opts: list[str]

Version:

  • OS: MacOS 14.6.1
  • Python version: 3.11
  • datamodel-code-generator version: 0.25.9

Additional context

The traceback

Traceback (most recent call last):
  File "/Users/user/work/issue-datamodel-code-generator/.venv/lib/python3.11/site-packages/datamodel_code_generator/__main__.py", line 445, in main
    generate(
  File "/Users/user/work/issue-datamodel-code-generator/.venv/lib/python3.11/site-packages/datamodel_code_generator/__init__.py", line 473, in generate
    results = parser.parse()
              ^^^^^^^^^^^^^^
  File "/Users/user/work/issue-datamodel-code-generator/.venv/lib/python3.11/site-packages/datamodel_code_generator/parser/base.py", line 1366, in parse
    self.__collapse_root_models(
  File "/Users/user/work/issue-datamodel-code-generator/.venv/lib/python3.11/site-packages/datamodel_code_generator/parser/base.py", line 1015, in __collapse_root_models
    elif data_type.parent.is_list:
         ^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'is_list'

comic31 avatar Aug 12 '24 17:08 comic31

    Pet:
      allOf:
        - $ref: "#/components/schemas/ProjectedPet"
        - type: object
          required:
            - id
            - name
            - opts

zaphod72 avatar Oct 17 '24 22:10 zaphod72

I'm getting the same error with version 0.26.5 and openapi spec https://docs.shipstation.com/_spec/openapi.json?download

$ datamodel-codegen --input ./api_model/openapi-v2-20250131.json --output-model-type pydantic_v2.BaseModel --snake-case-field --allow-extra-fields --use-standard-collections --use-union-operator --force-optional --allow-population-by-field-name --target-python-version=3.11 --collapse-root-models --use-schema-description --capitalise-enum-members --enable-version-header --use-annotated --output-datetime-class datetime

The input file type was determined to be: openapi
This can be specified explicitly with the `--input-file-type` option.
/home/vscode/.local/share/virtualenvs/virtualenv-S6O_fdF0/lib/python3.12/site-packages/datamodel_code_generator/parser/jsonschema.py:341: UserWarning: format of 'url' not understood for 'string' - using default
  warn(f'format of {format__!r} not understood for {type_!r} - using default')
Traceback (most recent call last):
  File "/home/vscode/.local/share/virtualenvs/virtualenv-S6O_fdF0/lib/python3.12/site-packages/datamodel_code_generator/__main__.py", line 494, in main
    generate(
  File "/home/vscode/.local/share/virtualenvs/virtualenv-S6O_fdF0/lib/python3.12/site-packages/datamodel_code_generator/__init__.py", line 507, in generate
    results = parser.parse()
              ^^^^^^^^^^^^^^
  File "/home/vscode/.local/share/virtualenvs/virtualenv-S6O_fdF0/lib/python3.12/site-packages/datamodel_code_generator/parser/base.py", line 1415, in parse
    self.__collapse_root_models(
  File "/home/vscode/.local/share/virtualenvs/virtualenv-S6O_fdF0/lib/python3.12/site-packages/datamodel_code_generator/parser/base.py", line 1064, in __collapse_root_models
    elif data_type.parent.is_list:
         ^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'is_list'

As a quick "hack", I edited file datamodel_code_generator/parser/base.py

I changed line 1065 from

elif data_type.parent.is_list:

to

elif data_type.parent and data_type.parent.is_list:

The openapi file now gets converted without an error, it seems correct but I won't know for certain until try to use it.

...

ok, it didn't quite work. There's a custom type that's used in multiple places in this openapi spec file as a list

e.g.

    label_ids: Annotated[
        list[SeId],
        Field(description="An array of the label ids used in this manifest."),
    ]

My code change causes the type SeId to not render. My workaround for that was to run datamodel-codegen again, without --collapse-root-models, then copy the definition of SeId from that generated python file into the 'broken' file.

class SeId(RootModel[str | None]):
    model_config = ConfigDict(
        populate_by_name=True,
    )
    root: Annotated[
        str | None,
        Field(
            description='A string that uniquely identifies a ShipStation resource, such as a carrier, label, shipment, etc.',
            examples=['se-28529731'],
            max_length=25,
            min_length=1,
            pattern='^se(-[a-z0-9]+)+$',
            title='se_id',
        ),
    ] = None

Now pylint pretty much only complains about Unnecessary pass statement, e.g.

class ShippingAddressTo(Address, PartialShippingAddressTo):
    pass
    model_config = ConfigDict(
        extra='allow',
        populate_by_name=True,
    )

This also occurs with the unmodified base.py .

bkcsfi avatar Jan 31 '25 20:01 bkcsfi

PR welcome.

gaborbernat avatar Feb 06 '25 20:02 gaborbernat