def METHOD_NAME(obj) -> Optional[Dict]:
    """
    get a dictionary from obj, works if obj is a dict, dataclass or has a __dict__ or __slots__
    :param obj:
    :return: a dict, writes to the dict will not necessarily update obj
    """
    if isinstance(obj, dict):
        return obj
    if dataclasses.is_dataclass(obj):
        return dataclasses.asdict(obj)
    if hasattr(obj, '__slots__'):
        return {slot: getattr(obj, slot) for slot in obj.__slots__}
    if hasattr(obj, '__dict__') and not isinstance(obj, Enum):
        return obj.__dict__
    # raise ValueError(f'cannot coerce {type(obj)} to dict')
    return None