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 inspect
from dataclasses import dataclass, fields, is_dataclass
from enum import Enum
from pathlib import Path
@@ -261,6 +262,10 @@ def construct_value(
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}"
raise ClanError(msg)

View File

@@ -1,5 +1,6 @@
import copy
import dataclasses
import inspect
import pathlib
from dataclasses import MISSING
from enum import EnumType
@@ -110,6 +111,12 @@ def type_to_dict(
if t is None:
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):
fields = dataclasses.fields(t)
properties = {}

View File

@@ -1,12 +1,15 @@
# ruff: noqa: RUF001
import argparse
import json
import logging
import sys
from collections.abc import Callable
from functools import partial
from pathlib import Path
from typing import Any
logger = logging.getLogger(__name__)
class Error(Exception):
pass
@@ -130,6 +133,12 @@ def field_def_from_default_value(
finalize_field: Callable[..., tuple[str, str]],
) -> tuple[str, str] | None:
# 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:
return finalize_field(
field_types=field_types | {"None"},
@@ -237,6 +246,9 @@ def generate_dataclass(
if not prop_type and not union_variants and not enum_variants:
msg = f"Type not found for property {prop} {prop_info}"
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:
field_types = map_json_type(union_variants)
@@ -283,6 +295,8 @@ def generate_dataclass(
)
)
known_classes.add(nested_class_name)
elif prop_type == "Unknown":
field_types = {"Unknown"}
else:
field_types = map_json_type(
prop_type,
@@ -388,6 +402,12 @@ def run_gen(args: argparse.Namespace) -> None:
# ruff: noqa: F401
# fmt: off
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)