feat(classgen): add support for unknown types

This commit is contained in:
Johannes Kirschbauer
2025-05-20 15:49:56 +02:00
parent 7a0665da6d
commit 9eeae6e229
3 changed files with 32 additions and 0 deletions

View File

@@ -30,6 +30,7 @@ Note: This module assumes the presence of other modules and classes such as `Cla
""" """
import dataclasses import dataclasses
import inspect
from dataclasses import dataclass, fields, is_dataclass from dataclasses import dataclass, fields, is_dataclass
from enum import Enum from enum import Enum
from pathlib import Path from pathlib import Path
@@ -261,6 +262,10 @@ def construct_value(
return t(field_value) # type: ignore return t(field_value) # type: ignore
if inspect.isclass(t) and t.__name__ == "Unknown":
# Return the field value as is
return field_value
msg = f"Unhandled field type {t} with value {field_value}" msg = f"Unhandled field type {t} with value {field_value}"
raise ClanError(msg) raise ClanError(msg)

View File

@@ -1,5 +1,6 @@
import copy import copy
import dataclasses import dataclasses
import inspect
import pathlib import pathlib
from dataclasses import MISSING from dataclasses import MISSING
from enum import EnumType from enum import EnumType
@@ -110,6 +111,12 @@ def type_to_dict(
if t is None: if t is None:
return {"type": "null"} return {"type": "null"}
if inspect.isclass(t) and t.__name__ == "Unknown":
# Empty should represent unknown
# We don't know anything about this type
# Nor about the nested fields, if there are any
return {}
if dataclasses.is_dataclass(t): if dataclasses.is_dataclass(t):
fields = dataclasses.fields(t) fields = dataclasses.fields(t)
properties = {} properties = {}

View File

@@ -1,12 +1,15 @@
# ruff: noqa: RUF001 # ruff: noqa: RUF001
import argparse import argparse
import json import json
import logging
import sys import sys
from collections.abc import Callable from collections.abc import Callable
from functools import partial from functools import partial
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
logger = logging.getLogger(__name__)
class Error(Exception): class Error(Exception):
pass pass
@@ -130,6 +133,12 @@ def field_def_from_default_value(
finalize_field: Callable[..., tuple[str, str]], finalize_field: Callable[..., tuple[str, str]],
) -> tuple[str, str] | None: ) -> tuple[str, str] | None:
# default_value = prop_info.get("default") # default_value = prop_info.get("default")
if "Unknown" in field_types:
# Unknown type, doesnt matter what the default value is
# type Unknown | a -> Unknown
return finalize_field(
field_types=field_types,
)
if default_value is None: if default_value is None:
return finalize_field( return finalize_field(
field_types=field_types | {"None"}, field_types=field_types | {"None"},
@@ -237,6 +246,9 @@ def generate_dataclass(
if not prop_type and not union_variants and not enum_variants: if not prop_type and not union_variants and not enum_variants:
msg = f"Type not found for property {prop} {prop_info}" msg = f"Type not found for property {prop} {prop_info}"
raise Error(msg) raise Error(msg)
msg = f"Type not found for property {prop} {prop_info}.\nConverting to unknown type.\n"
logger.warning(msg)
prop_type = "Unknown"
if union_variants: if union_variants:
field_types = map_json_type(union_variants) field_types = map_json_type(union_variants)
@@ -283,6 +295,8 @@ def generate_dataclass(
) )
) )
known_classes.add(nested_class_name) known_classes.add(nested_class_name)
elif prop_type == "Unknown":
field_types = {"Unknown"}
else: else:
field_types = map_json_type( field_types = map_json_type(
prop_type, prop_type,
@@ -388,6 +402,12 @@ def run_gen(args: argparse.Namespace) -> None:
# ruff: noqa: F401 # ruff: noqa: F401
# fmt: off # fmt: off
from typing import Any, Literal, NotRequired, TypedDict\n from typing import Any, Literal, NotRequired, TypedDict\n
# Mimic "unknown".
# 'Any' is unsafe because it allows any operations
# This forces the user to use type-narrowing or casting in the code
class Unknown:
pass
""" """
) )
f.write(dataclass_code) f.write(dataclass_code)