from __future__ import annotations import inspect import logging from collections.abc import Iterator from dataclasses import dataclass from typing import Any, Generic, Type, TypeVar from dcs.unittype import FlyingType from .propertyvalue import PropertyValue ValueT = TypeVar("ValueT", bool, int) @dataclass(frozen=True) class UnitProperty(Generic[ValueT]): id: str default: ValueT values: list[PropertyValue[Any]] @classmethod def for_aircraft( cls, unit_type: Type[FlyingType] ) -> Iterator[UnitProperty[ValueT]]: try: props = unit_type.Properties # type: ignore except AttributeError: return if unit_type.property_defaults is None: raise RuntimeError(f"{unit_type} has Properties but no defaults") for name, attr in inspect.getmembers(props, inspect.isclass): if name.startswith("__"): continue attr_values = getattr(attr, "Values", None) if attr_values is None and unit_type.property_defaults[name] is None: msg = f"Skipping property '{name}' for '{unit_type.id}': default value is None." logging.warning(msg) continue yield cls.property_from(attr, unit_type.property_defaults[name]) @classmethod def property_from(cls, attr: Type[ValueT], default: ValueT) -> UnitProperty[ValueT]: prop_id = attr.id # type: ignore values = getattr(attr, "Values", None) if values is None: prop_values = list(cls.default_values_for(prop_id, default)) else: prop_values = [] for name, value in inspect.getmembers(values): if name.startswith("__"): continue prop_values.append(PropertyValue(name, value)) return UnitProperty(prop_id, default, prop_values) @classmethod def default_values_for( cls, prop_id: str, default: ValueT ) -> Iterator[PropertyValue[ValueT]]: if isinstance(default, bool): yield PropertyValue("True", True) yield PropertyValue("False", False) elif isinstance(default, int): for i in range(10): yield PropertyValue(str(i), i) else: raise TypeError( f"Unexpected property type for {prop_id}: {default.__class__}" )