-
Notifications
You must be signed in to change notification settings - Fork 95
Expand file tree
/
Copy pathbase_entity.py
More file actions
248 lines (193 loc) · 6.46 KB
/
base_entity.py
File metadata and controls
248 lines (193 loc) · 6.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
import ujson as json
import re
import yaml
from collections import OrderedDict
def represent_odict(dump, tag, mapping, flow_style=None):
"""
Like BaseRepresenter.represent_mapping, but does not issue the sort().
"""
value = []
node = yaml.MappingNode(tag, value, flow_style=flow_style)
if dump.alias_key is not None:
dump.represented_objects[dump.alias_key] = node
best_style = True
if hasattr(mapping, 'items'):
mapping = mapping.items()
for item_key, item_value in mapping:
node_key = dump.represent_data(item_key)
node_value = dump.represent_data(item_value)
if not (isinstance(node_key, yaml.ScalarNode) and not node_key.style):
best_style = False
if not (isinstance(node_value, yaml.ScalarNode) and not node_value.style):
best_style = False
value.append((node_key, node_value))
if flow_style is None:
if dump.default_flow_style is not None:
node.flow_style = dump.default_flow_style
else:
node.flow_style = best_style
return node
class Property(object):
def __init__(
self,
name,
displayName,
description,
typeClass,
typeName,
required,
default
):
self.name = name
self.displayName = displayName
self.description = description
self.typeClass = typeClass
self.typeName = typeName
self.required = required
self.default = default
class Field(Property):
def __init__(self, property, value):
super(Field, self).__init__(
property.name,
property.displayName,
property.description,
property.typeClass,
property.typeName,
property.required,
property.default
)
self.value = value
def __str__(self):
if self.typeClass.startswith("array"):
return "{} = [{}]".format(
self.displayName, len(self.value)
)
if self.typeClass.startswith("object"):
v = str(self.value)
v = v.strip()
v = "{ " + ", ".join(v.split("\n")) + " }"
return "{} = {}".format(
self.displayName, v
)
return "{} = {}".format(
self.displayName,
self.value
)
def value_ordered_dict(self, verbose):
if self.typeClass == "array_object":
return [ x.ordered_dict(verbose) for x in self.value ]
if self.typeClass == "object":
return self.value.ordered_dict(verbose)
return self.value
class EntityDict(object):
def __init__(self):
self.dict = {}
def __len__(self):
return len(self.dict)
def prop_dict_value(self, value):
if hasattr(value, 'dict'):
return value.dict()
return value
def set(self, key, value):
if isinstance(value, list):
self.dict[key] = [self.prop_dict_value(v) for v in value]
else:
self.dict[key] = self.prop_dict_value(value)
class BaseEntity(object):
_properties = []
def __init__(self):
pass
def fields(self):
for prop in self._properties:
value = getattr(self, prop.name)
if value is not None:
yield Field(prop, value)
def name(self):
name_string = self._name_format
for m in re.findall(r'{[^}]+}', name_string):
key = m[1:-1]
value = getattr(self, key)
if value is not None:
name_string = name_string.replace(m, str(value))
return name_string
def summary(self):
summary_string = self._summary_format
for m in re.findall(r'{[^}]+}', summary_string):
key = m[1:-1]
value = getattr(self, key)
if value is not None:
summary_string = summary_string.replace(m, str(value))
return summary_string
def title(self):
name = self.name()
summary = self.summary()
title_string = name
if len(name) > 0 and len(summary) > 0:
title_string += ": "
title_string += summary
return title_string
def fields_str(self):
s = ""
for field in self.fields():
s += str(field) + "\n"
return s
def __str__(self):
return self.yaml(False)
def ordered_dict(self, verbose):
d = OrderedDict()
for field in self.fields():
key = field.name
if verbose:
key = field.displayName
d[key] = field.value_ordered_dict(
verbose
)
return d
def yaml(self, verbose=False):
yaml.SafeDumper.add_representer(
OrderedDict,
lambda dumper, value: represent_odict(
dumper, u'tag:yaml.org,2002:map', value
)
)
return yaml.safe_dump(
self.ordered_dict(verbose=verbose),
default_flow_style=False,
indent=2
).strip()
def dict(self):
spec = EntityDict()
for field in self.fields():
if field.typeName == "primitives.DecimalNumber" or \
field.typeName == "primitives.AccountUnits" or \
field.typeName == "pricing.PriceValue":
spec.set(field.name, str(field.value))
else:
spec.set(field.name, field.value)
return spec.dict
def json(self):
return json.dumps(self.dict())
def diff(self, other):
for property in self._properties:
self_value = getattr(self, property.name)
other_value = getattr(other, property.name)
if self_value is None:
continue
assert \
other_value is not None, \
"Did not expected {}.{} to be unset".format(
self.__class__.__name__,
property.name
)
if property.typeClass == "primitive":
assert \
self_value == other_value, \
"Expected value for {}.{} is {}, got {}".format(
self.__class__.__name__,
property.name,
self_value,
other_value
)
elif property.typeClass == "object":
self_value.diff(other_value)
return True