74 lines
1.8 KiB
Python
74 lines
1.8 KiB
Python
class Expando:
|
|
"""
|
|
Readonly dynamic class that eases the access to attributes and sub attributes
|
|
It is initialized with a dict
|
|
You can then access the property using dot '.' (ex. obj.prop1.prop2)
|
|
"""
|
|
|
|
def __init__(self, props):
|
|
self._props = props
|
|
|
|
def __getattr__(self, item):
|
|
if item not in self._props:
|
|
raise AttributeError(item)
|
|
|
|
current = self._props[item]
|
|
return Expando(current) if isinstance(current, dict) else current
|
|
|
|
def __setitem__(self, key, value):
|
|
self._props[key] = value
|
|
|
|
def get(self, path):
|
|
"""
|
|
returns the value, from a string with represents the path
|
|
:param path:
|
|
:return:
|
|
"""
|
|
current = self._props
|
|
for attr in path.split("."):
|
|
if isinstance(current, list):
|
|
temp = []
|
|
for value in current:
|
|
if value and attr in value:
|
|
temp.append(value[attr])
|
|
current = temp
|
|
|
|
else:
|
|
if current is None or attr not in current:
|
|
return None
|
|
current = current[attr]
|
|
|
|
return current
|
|
|
|
def as_dict(self):
|
|
"""
|
|
Return the information as a dictionary
|
|
:return:
|
|
"""
|
|
return self._props.copy()
|
|
|
|
def to_dict(self, mappings: dict) -> dict:
|
|
return {prop_name: self.get(path) for path, prop_name in mappings.items() if prop_name is not None}
|
|
|
|
def __hasattr__(self, item):
|
|
return item in self._props
|
|
|
|
def __repr__(self):
|
|
if "key" in self._props:
|
|
return f"Expando(key={self._props["key"]})"
|
|
|
|
props_as_str = str(self._props)
|
|
if len(props_as_str) > 50:
|
|
props_as_str = props_as_str[:50] + "..."
|
|
|
|
return f"Expando({props_as_str})"
|
|
|
|
def __eq__(self, other):
|
|
if not isinstance(other, Expando):
|
|
return False
|
|
|
|
return self._props == other._props
|
|
|
|
def __hash__(self):
|
|
return hash(tuple(sorted(self._props.items())))
|