"""Helper utilities extracted from monitor.py for formatting and enum lookups. These functions are UI-agnostic and can be unit-tested independently. """ import importlib import sys UNSET_TEXT = "" def fmt_enum(val, enum_names): """Format numeric `val` with possible enum name(s).""" try: enums_mod = None try: enums_mod = importlib.import_module('Grifo_E_1553lib.data_types.enums') except Exception: try: enums_mod = importlib.import_module('pybusmonitor1553.Grifo_E_1553lib.data_types.enums') except Exception: enums_mod = None if enums_mod is None: return str(val) for name in enum_names: enum_cls = getattr(enums_mod, name, None) if enum_cls is not None: try: v = int(val) try: enum_name = enum_cls(v).name except Exception: enum_name = str(getattr(enum_cls, v, '')) try: if not enum_name or str(enum_name).lower() == 'none': return str(v) except Exception: pass return f"{v} ({enum_name})" except Exception: continue except Exception: pass return str(val) def get_enum_items(class_name): """Return list of (name, value) tuples for enum class, or None.""" try: enums_mod = None try: enums_mod = importlib.import_module('Grifo_E_1553lib.data_types.enums') except Exception: try: enums_mod = importlib.import_module('pybusmonitor1553.Grifo_E_1553lib.data_types.enums') except Exception: enums_mod = None if enums_mod is None: return None enum_cls = getattr(enums_mod, class_name, None) if enum_cls is None: return None items = [] if hasattr(enum_cls, '__members__'): for name, member in enum_cls.__members__.items(): try: items.append((name, int(member.value))) except Exception: try: items.append((name, int(member))) except Exception: pass return items for a in dir(enum_cls): if not a.isupper(): continue try: v = getattr(enum_cls, a) if isinstance(v, int): items.append((a, int(v))) except Exception: continue return items if items else None except Exception: return None def format_ctypes_obj(obj, indent=0, max_depth=3): pad = ' ' * indent if obj is None: return f"{pad}{UNSET_TEXT}\n" try: if hasattr(obj, 'value') and not hasattr(obj, '__dict__'): try: return f"{pad}{int(obj.value)}\n" except Exception: return f"{pad}{obj}\n" if isinstance(obj, (int, float, str)): return f"{pad}{obj}\n" except Exception: pass if hasattr(obj, 'raw') and not hasattr(obj, '__dict__'): try: raw = int(obj.raw) cls_name = obj.__class__.__name__ enum_str = fmt_enum(raw, [cls_name]) if enum_str == str(raw): return f"{pad}{raw}\n" else: return f"{pad}{enum_str}\n" except Exception: return f"{repr(obj)}\n" if max_depth <= 0: return f"{pad}{obj}\n" names = [n for n in dir(obj) if not n.startswith('_')] simple_fields = [] for n in names: try: v = getattr(obj, n) except Exception: continue if callable(v): continue if isinstance(v, (int, float, str)) or hasattr(v, 'raw') or hasattr(v, 'value'): try: nested = format_ctypes_obj(v, indent=indent+1, max_depth=max_depth-1) simple_fields.append(f"{pad}{n}:\n{nested}") except Exception: simple_fields.append(f"{pad}{n}: \n") else: try: nested = format_ctypes_obj(v, indent=indent+1, max_depth=max_depth-1) simple_fields.append(f"{pad}{n}:\n{nested}") except Exception: simple_fields.append(f"{pad}{n}: \n") if simple_fields: return '\n'.join(simple_fields) + '\n' return f"{pad}{repr(obj)}\n" def format_value_for_table(val): try: if val is None: return UNSET_TEXT if isinstance(val, (int, float, str)): return str(val) if hasattr(val, 'raw'): try: return fmt_enum(int(getattr(val, 'raw')), [val.__class__.__name__]) except Exception: try: return str(getattr(val, 'raw')) except Exception: return repr(val) if hasattr(val, 'value'): try: return str(int(val.value)) except Exception: try: return str(val.value) except Exception: return repr(val) try: s = format_ctypes_obj(val, indent=0, max_depth=1) return s.strip().splitlines()[0] except Exception: return repr(val) except Exception: return '' def coerce_text_to_type(text: str): try: if text.startswith('0x'): return int(text, 16) except Exception: pass try: return int(text) except Exception: try: return float(text) except Exception: return text