Repository: koxudaxi/datamodel-code-generator

Issue:
AttributeError raised when using --collapse-root-models flag
**Describe the bug**

When using the `--collapse-root-models` flag, this error is raised:

```shell
Traceback (most recent call last):
  File ".venv/lib/python3.10/site-packages/datamodel_code_generator/__main__.py", line 767, in main
    generate(
  File ".venv/lib/python3.10/site-packages/datamodel_code_generator/__init__.py", line 431, in generate
    results = parser.parse()
  File ".venv/lib/python3.10/site-packages/datamodel_code_generator/parser/base.py", line 1083, in parse
    self.__collapse_root_models(models, unused_models)
  File ".venv/lib/python3.10/site-packages/datamodel_code_generator/parser/base.py", line 856, in __collapse_root_models
    root_type_model.reference.children = [
  File ".venv/lib/python3.10/site-packages/datamodel_code_generator/parser/base.py", line 857, in <listcomp>
    c for c in root_type_model.reference.children if c.parent
AttributeError: 'BaseModel' object has no attribute 'parent'
```

**To Reproduce**

Input schema: https://github.com/CycloneDX/specification/blob/1.5/schema/bom-1.5.schema.json

pyproject.toml config:

```toml
[tool.datamodel-codegen]
base-class = ".base.BaseModel"
collapse-root-models = true
disable-warnings = true
enum-field-as-literal = "one"
field-include-all-keys = true
input-file-type = "jsonschema"
reuse-model = true
set-default-enum-member = true
snake-case-field = true
target-python-version = "3.7"
use-annotated = true
use-default-kwarg = true
use-double-quotes = true
use-schema-description = true
use-standard-collections = true
use-subclass-enum = true
use-title-as-name = true
wrap-string-literal = true
```

Base class code:

```python
from pydantic import BaseModel as _BaseModel
from pydantic import Extra


class BaseModel(_BaseModel):
    class Config:
        allow_population_by_field_name = True
        arbitrary_types_allowed = True
        extra = Extra.allow
        use_enum_values = True

    def __hash__(self) -> int:
        return hash(repr(self))
```

**Expected behavior**

Collapse root models without raising an exception

**Version:**
 - OS: MacOS 13.4.1
 - Python version: 3.10
 - datamodel-code-generator version: 0.21.1


Discussion:
Seems to work (at least for my use case, don't know if breaks others) if that line is changed to

```python
c for c in root_type_model.reference.children if getattr(c, "parent", None)
```

Resolving patch:
diff --git a/datamodel_code_generator/parser/base.py b/datamodel_code_generator/parser/base.py
--- a/datamodel_code_generator/parser/base.py
+++ b/datamodel_code_generator/parser/base.py
@@ -868,7 +868,9 @@ def __collapse_root_models(
                     data_type.remove_reference()
 
                     root_type_model.reference.children = [
-                        c for c in root_type_model.reference.children if c.parent
+                        c
+                        for c in root_type_model.reference.children
+                        if getattr(c, 'parent', None)
                     ]
 
                     if not root_type_model.reference.children:


Test patch:
diff --git a/tests/data/expected/main/main_collapse_root_models_with_references_to_flat_types/output.py b/tests/data/expected/main/main_collapse_root_models_with_references_to_flat_types/output.py
new file mode 100644
--- /dev/null
+++ b/tests/data/expected/main/main_collapse_root_models_with_references_to_flat_types/output.py
@@ -0,0 +1,13 @@
+# generated by datamodel-codegen:
+#   filename:  flat_type.jsonschema
+#   timestamp: 2019-07-26T00:00:00+00:00
+
+from __future__ import annotations
+
+from typing import Optional
+
+from pydantic import BaseModel
+
+
+class FooModel(BaseModel):
+    foo: Optional[str] = None
diff --git a/tests/data/openapi/flat_type.jsonschema b/tests/data/openapi/flat_type.jsonschema
new file mode 100644
--- /dev/null
+++ b/tests/data/openapi/flat_type.jsonschema
@@ -0,0 +1,16 @@
+{
+  "title": "Foo",
+  "$schema": "http://json-schema.org/schema#",
+  "description": "",
+  "type": "object",
+  "properties": {
+    "foo": {
+      "$ref": "#/definitions/foo"
+    }
+  },
+  "definitions": {
+    "foo": {
+      "type": "string"
+    }
+  }
+}
diff --git a/tests/test_main.py b/tests/test_main.py
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -4339,6 +4339,31 @@ def test_main_collapse_root_models_field_constraints():
         )
 
 
+@freeze_time('2019-07-26')
+def test_main_collapse_root_models_with_references_to_flat_types():
+    with TemporaryDirectory() as output_dir:
+        output_file: Path = Path(output_dir) / 'output.py'
+        return_code: Exit = main(
+            [
+                '--input',
+                str(OPEN_API_DATA_PATH / 'flat_type.jsonschema'),
+                '--output',
+                str(output_file),
+                '--collapse-root-models',
+            ]
+        )
+
+        assert return_code == Exit.OK
+        assert (
+            output_file.read_text()
+            == (
+                EXPECTED_MAIN_PATH
+                / 'main_collapse_root_models_with_references_to_flat_types'
+                / 'output.py'
+            ).read_text()
+        )
+
+
 @freeze_time('2019-07-26')
 def test_main_openapi_max_items_enum():
     with TemporaryDirectory() as output_dir: