src/opera/value.py
import copy
from opera.error import DataError
class Value:
FUNCTIONS = frozenset((
"get_attribute",
"get_input",
"get_property",
"get_artifact",
"concat",
"join",
"token",
))
def __init__(self, typ, present, data=None):
self.type = typ
self.present = present
self._data = data
def dump(self):
return dict(is_set=self.present, data=self._data)
def load(self, data):
self.present = data["is_set"]
self._data = data["data"]
@property
def data(self):
if not self.present:
raise AssertionError("Accessing an unset value. Bug-fixing ahead ;)")
return self._data
def copy(self):
return type(self)(self.type, self.present, copy.deepcopy(self._data))
def set(self, data):
self._data = data
self.present = True
def unset(self):
self._data = None
self.present = False
def eval(self, instance, key):
if not self.present:
raise DataError(f"Cannot use an unset value: {key}")
if self.is_function:
return Value.eval_function(self.data, instance)
if isinstance(self.data, dict):
result_map = {}
for map_key, value in self.data.items():
result_map[map_key] = Value.check_eval_function(value, instance)
return result_map
if isinstance(self.data, list):
result_list = []
for value in self.data:
result_list.append(Value.check_eval_function(value, instance))
return result_list
return self.data
@property
def is_function(self):
return Value.check_function(self.data)
@staticmethod
def check_function(data):
return isinstance(data, dict) and len(data) == 1 and tuple(data.keys())[0] in Value.FUNCTIONS
@staticmethod
def eval_function(data, instance):
(function_name, params), = data.items()
return getattr(instance, function_name)(params)
@staticmethod
def check_eval_function(data, instance):
if Value.check_function(data):
return Value.eval_function(data, instance)
return data
def __str__(self):
return f"Value({self.present})[{self._data}]"