""" Type Helpers Utilities for type introspection and resolution. Used by generators and loaders. """ import dataclasses as dc from enum import Enum from typing import Any, Union, get_args, get_origin def unwrap_optional(type_hint: Any) -> tuple[Any, bool]: """Unwrap Optional[T] -> (T, True) or (T, False) if not optional.""" origin = get_origin(type_hint) if origin is Union: args = [a for a in get_args(type_hint) if a is not type(None)] return (args[0] if args else str, True) return (type_hint, False) def get_origin_name(type_hint: Any) -> str | None: """Get origin type name: 'dict', 'list', or None.""" origin = get_origin(type_hint) if origin is dict: return "dict" if origin is list: return "list" return None def get_type_name(type_hint: Any) -> str | None: """Get type name for special types like UUID, datetime.""" if hasattr(type_hint, "__name__"): return type_hint.__name__ return None def get_list_inner(type_hint: Any) -> str: """Get inner type of List[T].""" args = get_args(type_hint) if args and args[0] in (str, int, float, bool): return {str: "str", int: "int", float: "float", bool: "bool"}[args[0]] return "str" def get_field_default(field: dc.Field) -> Any: """Get default value from dataclass field.""" if field.default is not dc.MISSING: return field.default return dc.MISSING def format_opts(optional: bool, extra: list[str] | None = None) -> str: """Format field options string for Django.""" parts = [] if optional: parts.append("null=True, blank=True") if extra: parts.extend(extra) return ", ".join(parts) def is_enum(type_hint: Any) -> bool: """Check if type is an Enum.""" base, _ = unwrap_optional(type_hint) return isinstance(base, type) and issubclass(base, Enum) def get_enum_values(enum_class: type) -> list[tuple[str, str]]: """Get list of (name, value) pairs from an Enum.""" return [(m.name, m.value) for m in enum_class]