Warning, file /harvester/pandaharvester/harvestercore/spec_base.py was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 """
0002 Base class for XyzSpec
0003
0004 """
0005
0006 import json
0007 import pickle
0008 from json.decoder import JSONDecodeError
0009
0010 import rpyc
0011
0012
0013
0014 class PythonObjectEncoder(json.JSONEncoder):
0015 def default(self, obj):
0016 if isinstance(obj, rpyc.core.netref.BaseNetref):
0017 retVal = rpyc.utils.classic.obtain(obj)
0018 else:
0019 retVal = {"_non_json_object": pickle.dumps(obj)}
0020 return retVal
0021
0022
0023
0024 def as_python_object(dct):
0025 if "_non_json_object" in dct:
0026 return pickle.loads(str(dct["_non_json_object"]))
0027 return dct
0028
0029
0030
0031 class SpecBase(object):
0032
0033 attributesWithTypes = ()
0034 zeroAttrs = ()
0035 skipAttrsToSlim = ()
0036
0037
0038 def __init__(self):
0039
0040 object.__setattr__(self, "attributes", [])
0041 object.__setattr__(self, "serializedAttrs", set())
0042 for attr in self.attributesWithTypes:
0043 attr, attrType = attr.split(":")
0044 attrType = attrType.split()[0]
0045 self.attributes.append(attr)
0046 if attrType in ["blob"]:
0047 self.serializedAttrs.add(attr)
0048
0049 for attr in self.attributes:
0050 if attr in self.zeroAttrs:
0051 object.__setattr__(self, attr, 0)
0052 else:
0053 object.__setattr__(self, attr, None)
0054
0055 object.__setattr__(self, "changedAttrs", {})
0056
0057
0058 def __setattr__(self, name, value):
0059 oldVal = getattr(self, name)
0060 object.__setattr__(self, name, value)
0061 newVal = getattr(self, name)
0062
0063 if oldVal != newVal:
0064 self.changedAttrs[name] = value
0065
0066
0067 def __getstate__(self):
0068 odict = self.__dict__.copy()
0069 del odict["changedAttrs"]
0070 return odict
0071
0072
0073 def __setstate__(self, state):
0074 self.__init__()
0075 for k, v in state.items():
0076 object.__setattr__(self, k, v)
0077
0078
0079 def reset_changed_list(self):
0080 object.__setattr__(self, "changedAttrs", {})
0081
0082
0083 def force_update(self, name):
0084 if name in self.attributes:
0085 self.changedAttrs[name] = getattr(self, name)
0086
0087
0088 def force_not_update(self, name):
0089 if name in self.changedAttrs:
0090 del self.changedAttrs[name]
0091
0092
0093 def has_updated_attributes(self):
0094 return len(self.changedAttrs) > 0
0095
0096
0097 def pack(self, values, slim=False):
0098 if hasattr(values, "_asdict"):
0099 values = values._asdict()
0100 for attr in self.attributes:
0101 if slim and attr in self.skipAttrsToSlim:
0102 val = None
0103 else:
0104 val = values[attr]
0105 if attr in self.serializedAttrs and val is not None:
0106 try:
0107 val = json.loads(val, object_hook=as_python_object)
0108 except JSONDecodeError:
0109 pass
0110 object.__setattr__(self, attr, val)
0111
0112
0113 def set_blob_attribute(self, key, val):
0114 try:
0115 val = json.loads(val, object_hook=as_python_object)
0116 object.__setattr__(self, key, val)
0117 except JSONDecodeError:
0118 pass
0119
0120
0121 def column_names(cls, prefix=None, slim=False):
0122 ret = ""
0123 for attr in cls.attributesWithTypes:
0124 attr = attr.split(":")[0]
0125 if slim and attr in cls.skipAttrsToSlim:
0126 continue
0127 if prefix is None:
0128 ret += f"{attr},"
0129 else:
0130 ret += f"{prefix}.{attr},"
0131 ret = ret[:-1]
0132 return ret
0133
0134 column_names = classmethod(column_names)
0135
0136
0137 def bind_values_expression(cls):
0138 ret = "VALUES("
0139 for attr in cls.attributesWithTypes:
0140 attr = attr.split(":")[0]
0141 ret += f":{attr},"
0142 ret = ret[:-1]
0143 ret += ")"
0144 return ret
0145
0146 bind_values_expression = classmethod(bind_values_expression)
0147
0148
0149 def bind_update_changes_expression(self):
0150 ret = ""
0151 for attr in self.attributes:
0152 if attr in self.changedAttrs:
0153 ret += f"{attr}=:{attr},"
0154 ret = ret[:-1]
0155 ret += " "
0156 return ret
0157
0158
0159 def values_map(self, only_changed=False):
0160 ret = {}
0161 for attr in self.attributes:
0162
0163 if only_changed:
0164 if attr not in self.changedAttrs:
0165 continue
0166 val = getattr(self, attr)
0167 if val is None:
0168 if attr in self.zeroAttrs:
0169 val = 0
0170 else:
0171 val = None
0172 if attr in self.serializedAttrs:
0173 val = json.dumps(val, cls=PythonObjectEncoder)
0174 ret[f":{attr}"] = val
0175 return ret
0176
0177
0178 def values_list(self, only_changed=False):
0179 ret = []
0180 for attr in self.attributes:
0181
0182 if only_changed:
0183 if attr not in self.changedAttrs:
0184 continue
0185 val = getattr(self, attr)
0186 if val is None:
0187 if attr in self.zeroAttrs:
0188 val = 0
0189 else:
0190 val = None
0191 if attr in self.serializedAttrs:
0192 val = json.dumps(val, cls=PythonObjectEncoder)
0193 ret.append(val)
0194 return ret
0195
0196
0197 def get_changed_attributes(self):
0198 retDict = dict()
0199 for attr in self.changedAttrs:
0200 retDict[attr] = getattr(self, attr)
0201 return retDict
0202
0203
0204 def set_attributes_with_dict(self, attr_dict):
0205 for attr, val in attr_dict.items():
0206 setattr(self, attr, val)