"""Convert pyVmomi objects into plain, JSON-safe Python values. The drivers never parse pyVmomi objects directly. Everything fetched from the vSphere API goes through :func:`to_plain` first, so a parser sees the same shape whether its input came from a live host or from a JSON fixture that ``tools/harvest.py`` captured. Conventions: * a managed object (``HostSystem``, ``VirtualMachine`` ...) becomes its MoRef id string, e.g. ``"host-21"`` * a data object becomes a dict of its set properties plus ``"_type"``, the WSDL type name (``"VirtualDisk"``) -- device lists are told apart by it * enums become ``str``, datetimes become epoch seconds, binary data ``None`` """ from __future__ import annotations import datetime from typing import Any from pyVmomi import VmomiSupport _NOISE = frozenset({"dynamicType", "dynamicProperty"}) def to_plain(value: Any) -> Any: """Recursively convert ``value`` into dicts, lists and scalars.""" if value is None or isinstance(value, bool): return value if isinstance(value, VmomiSupport.ManagedObject): return value._moId if isinstance(value, VmomiSupport.DataObject): return _data_object(value) if isinstance(value, str): return str(value) if isinstance(value, (int, float)): return value if isinstance(value, datetime.datetime): return value.timestamp() if isinstance(value, (bytes, bytearray)): return None if isinstance(value, (list, tuple)): return [to_plain(v) for v in value] return str(value) def _data_object(obj: Any) -> dict[str, Any]: out: dict[str, Any] = {"_type": obj._wsdlName} for prop in obj._GetPropertyList(): if prop.name in _NOISE: continue val = getattr(obj, prop.name, None) if val is None or (isinstance(val, list) and not val): continue out[prop.name] = to_plain(val) return out