tricc-oo 1.0.1__py3-none-any.whl → 1.4.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. tests/build.py +213 -0
  2. tests/test_cql.py +197 -0
  3. tests/to_ocl.py +51 -0
  4. {tricc → tricc_oo}/__init__.py +3 -1
  5. tricc_oo/converters/codesystem_to_ocl.py +169 -0
  6. tricc_oo/converters/cql/cqlLexer.py +822 -0
  7. tricc_oo/converters/cql/cqlListener.py +1632 -0
  8. tricc_oo/converters/cql/cqlParser.py +11204 -0
  9. tricc_oo/converters/cql/cqlVisitor.py +913 -0
  10. tricc_oo/converters/cql_to_operation.py +402 -0
  11. tricc_oo/converters/datadictionnary.py +115 -0
  12. tricc_oo/converters/drawio_type_map.py +222 -0
  13. tricc_oo/converters/tricc_to_xls_form.py +61 -0
  14. tricc_oo/converters/utils.py +65 -0
  15. tricc_oo/converters/xml_to_tricc.py +1003 -0
  16. tricc_oo/models/__init__.py +4 -0
  17. tricc_oo/models/base.py +732 -0
  18. tricc_oo/models/calculate.py +216 -0
  19. tricc_oo/models/ocl.py +281 -0
  20. tricc_oo/models/ordered_set.py +125 -0
  21. tricc_oo/models/tricc.py +418 -0
  22. tricc_oo/parsers/xml.py +138 -0
  23. tricc_oo/serializers/__init__.py +0 -0
  24. tricc_oo/serializers/xls_form.py +745 -0
  25. tricc_oo/strategies/__init__.py +0 -0
  26. tricc_oo/strategies/input/__init__.py +0 -0
  27. tricc_oo/strategies/input/base_input_strategy.py +111 -0
  28. tricc_oo/strategies/input/drawio.py +317 -0
  29. tricc_oo/strategies/output/base_output_strategy.py +148 -0
  30. tricc_oo/strategies/output/spice.py +365 -0
  31. tricc_oo/strategies/output/xls_form.py +697 -0
  32. tricc_oo/strategies/output/xlsform_cdss.py +189 -0
  33. tricc_oo/strategies/output/xlsform_cht.py +200 -0
  34. tricc_oo/strategies/output/xlsform_cht_hf.py +334 -0
  35. tricc_oo/visitors/__init__.py +0 -0
  36. tricc_oo/visitors/tricc.py +2198 -0
  37. tricc_oo/visitors/utils.py +17 -0
  38. tricc_oo/visitors/xform_pd.py +264 -0
  39. tricc_oo-1.4.15.dist-info/METADATA +219 -0
  40. tricc_oo-1.4.15.dist-info/RECORD +46 -0
  41. {tricc_oo-1.0.1.dist-info → tricc_oo-1.4.15.dist-info}/WHEEL +1 -1
  42. tricc_oo-1.4.15.dist-info/top_level.txt +2 -0
  43. tricc/converters/mc_to_tricc.py +0 -542
  44. tricc/converters/tricc_to_xls_form.py +0 -553
  45. tricc/converters/utils.py +0 -44
  46. tricc/converters/xml_to_tricc.py +0 -740
  47. tricc/models/tricc.py +0 -1093
  48. tricc/parsers/xml.py +0 -81
  49. tricc/serializers/xls_form.py +0 -364
  50. tricc/strategies/input/base_input_strategy.py +0 -80
  51. tricc/strategies/input/drawio.py +0 -246
  52. tricc/strategies/input/medalcreator.py +0 -168
  53. tricc/strategies/output/base_output_strategy.py +0 -92
  54. tricc/strategies/output/xls_form.py +0 -194
  55. tricc/strategies/output/xlsform_cdss.py +0 -46
  56. tricc/strategies/output/xlsform_cht.py +0 -106
  57. tricc/visitors/tricc.py +0 -375
  58. tricc_oo-1.0.1.dist-info/LICENSE +0 -78
  59. tricc_oo-1.0.1.dist-info/METADATA +0 -229
  60. tricc_oo-1.0.1.dist-info/RECORD +0 -26
  61. tricc_oo-1.0.1.dist-info/top_level.txt +0 -2
  62. venv/bin/vba_extract.py +0 -78
  63. {tricc → tricc_oo}/converters/__init__.py +0 -0
  64. {tricc → tricc_oo}/models/lang.py +0 -0
  65. {tricc/serializers → tricc_oo/parsers}/__init__.py +0 -0
  66. {tricc → tricc_oo}/serializers/planuml.py +0 -0
@@ -1,740 +0,0 @@
1
- import base64
2
- import os
3
- import re
4
- from curses.ascii import isalnum, isalpha, isdigit
5
-
6
- from numpy import isnan
7
-
8
- from tricc.converters.utils import OPERATION_LIST, clean_name, remove_html
9
- from tricc.models.tricc import *
10
- from tricc.parsers.xml import (get_edges_list, get_mxcell,
11
- get_mxcell_parent_list, get_tricc_type,
12
- get_tricc_type_list)
13
-
14
- from tricc.visitors.tricc import *
15
-
16
- TRICC_YES_LABEL = ['yes', "oui"]
17
- TRICC_NO_LABEL = ['no', "non"]
18
- TRICC_FOLOW_LABEL = ['folow', "suivre"]
19
- NO_LABEL = "NO_LABEL"
20
- TRICC_LIST_NAME = 'list_{0}'
21
- import logging
22
-
23
- logger = logging.getLogger("default")
24
-
25
-
26
- def create_activity(diagram, media_path):
27
- id = diagram.attrib.get('id')
28
- root = create_root_node(diagram)
29
- name = diagram.attrib.get('name')
30
- form_id=diagram.attrib.get('name',None)
31
- if root is not None:
32
- activity = TriccNodeActivity(
33
- root=root,
34
- name=id,
35
- id=id,
36
- label=name,
37
- form_id=form_id,
38
- )
39
- # activity definition is never instanciated
40
- if isinstance(root, TriccNodeActivityStart):
41
- activity.instance = 0
42
- # add the group on the root node
43
- root.group = activity
44
- activity.group = activity
45
- edges = get_edges(diagram)
46
- if edges and len(edges)>0:
47
- activity.edges = edges
48
- nodes = get_nodes(diagram, activity)
49
- groups = get_groups(diagram, nodes, activity)
50
- if groups and len(groups)>0:
51
- activity.groups = groups
52
- if nodes and len(nodes)>0:
53
- activity.nodes = nodes
54
-
55
- process_edges(diagram, media_path, activity, nodes)
56
- # link back the activity
57
- activity.root.activity = activity
58
- manage_dandling_calculate(activity)
59
-
60
- return activity
61
- else:
62
- logger.warning("root not found for page {0}".format(name))
63
-
64
- def manage_dandling_calculate(activity):
65
- dandling = {}
66
- for node in activity.nodes.values():
67
- prev_nodes = [activity.nodes[n.source] for n in list(filter(lambda x: (x.target == node.id or x.target == node) and (x.source in activity.nodes or x.source in activity.nodes.values()), activity.edges ))]
68
- if len(prev_nodes) == 0 and issubclass(node.__class__, TriccNodeCalculate):
69
- dandling[node.id] = node
70
- if len(dandling)>0:
71
- activity.calculates+=list(dandling.values())
72
- #wait = get_activity_wait([activity.root], [activity.root], dandling.values(), edge_only=True)
73
- #activity.nodes.update(dandling)
74
-
75
-
76
- def process_edges(diagram, media_path, activity, nodes):
77
- end_found = False
78
- for edge in activity.edges:
79
- # enrich nodes
80
- if edge.target not in nodes :
81
- activity.unused_edges.append(edge)
82
- elif edge.source not in nodes and edge.target in nodes:
83
- enriched = enrich_node(diagram, media_path, edge, nodes[edge.target])
84
- if enriched is None:
85
- activity.unused_edges.append(edge)
86
- elif isinstance(nodes[edge.target], (TriccNodeActivityEnd, TriccNodeEnd)):
87
- end_found = True
88
- if edge.target in nodes and issubclass(nodes[edge.target].__class__, TriccRhombusMixIn) and edge.source != nodes[edge.target].path.id :
89
- edge.target = nodes[edge.target].path.id
90
- # modify edge for selectyesNo
91
- if edge.source in nodes and isinstance(nodes[edge.source], TriccNodeSelectYesNo):
92
- process_yesno_edge(edge, nodes)
93
-
94
- # create calculate based on edges label
95
- elif edge.value is not None:
96
- label = edge.value.strip()
97
- processed = False
98
- calc = None
99
- if isinstance(nodes[edge.source], TriccNodeRhombus) and label.lower() in TRICC_FOLOW_LABEL:
100
- edge.source = nodes[edge.source].path.id
101
- processed = True
102
- elif label.lower() in (TRICC_YES_LABEL )or label == '':
103
- # do nothinbg for yes
104
- processed = True
105
- elif re.search(r'^\-?[0-9]+([.,][0-9]+)?$', edge.value.strip() ):
106
- calc = process_factor_edge(edge,nodes)
107
- elif label.lower() in TRICC_NO_LABEL:
108
- calc = process_exclusive_edge(edge, nodes)
109
- else:
110
- # manage comment
111
- calc = process_condition_edge(edge,nodes)
112
-
113
- if calc is not None:
114
- processed = True
115
- nodes[calc.id] = calc
116
- # add edge between calc and
117
- set_prev_next_node(calc,nodes[edge.target], edge_only=True)
118
- edge.target = calc.id
119
- if not processed:
120
- logger.warning("Edge between {0} and {1} with label '{2}' could not be interpreted: {3}".format(
121
- nodes[edge.source].get_name(),
122
- nodes[edge.target].get_name(),
123
- edge.value.strip(),
124
- "not management found"))
125
- if not end_found:
126
- logger.error("the activity {} has no end node".format(activity.get_name()))
127
- exit()
128
-
129
- def get_nodes(diagram, activity):
130
- nodes = {activity.root.id: activity.root}
131
- add_note_nodes(nodes, diagram, activity)
132
- add_calculate_nodes(nodes, diagram, activity)
133
- add_select_nodes(nodes, diagram, activity)
134
- add_input_nodes(nodes, diagram, activity)
135
- add_link_nodes(nodes, diagram, activity)
136
- get_hybride_node(nodes, diagram, activity)
137
- new_nodes={}
138
- node_to_remove=[]
139
- activity_end_node = None
140
- end_node = None
141
- for node in nodes.values():
142
- # clean name
143
- if hasattr(node, 'name') and node.name is not None and (node.name.endswith(('_','.'))):
144
- node.name = node.name + node.id
145
- if issubclass(node.__class__, TriccRhombusMixIn) and node.path is None:
146
- # generate rhombuse path
147
- calc = inject_bridge_path(node,nodes)
148
- node.path = calc
149
- new_nodes[calc.id] = calc
150
- # add the edge between trhombus and its path
151
- elif isinstance(node, TriccNodeGoTo):
152
- #find if the node has next nodes, if yes, add a bridge + Rhoimbus
153
- path = inject_bridge_path(node,nodes)
154
- new_nodes[path.id] = path
155
- # action after the activity
156
- next_nodes_id = [ e.target for e in activity.edges if e.source == node.id]
157
- if len(next_nodes_id)>0:
158
-
159
- calc = get_activity_wait([path], [node], next_nodes_id, node, edge_only=True)
160
- new_nodes[calc.id] = calc
161
- elif isinstance(node, TriccNodeEnd):
162
- if not end_node:
163
- end_node = node
164
- else:
165
- merge_node(node,end_node)
166
- node_to_remove.append(node.id)
167
- elif isinstance(node, TriccNodeActivityEnd):
168
- if not activity_end_node:
169
- activity_end_node = node
170
- else:
171
- merge_node(node,activity_end_node)
172
- node_to_remove.append(node.id)
173
-
174
- nodes.update(new_nodes)
175
-
176
- for key in node_to_remove:
177
- del nodes[key]
178
- edge_list = activity.edges.copy()
179
- for edge in edge_list:
180
- if edge.source in node_to_remove or edge.target in node_to_remove:
181
- activity.edges.remove(edge)
182
-
183
- return nodes
184
-
185
-
186
- def create_root_node(diagram):
187
- node = None
188
- elm = get_tricc_type(diagram, 'object', TriccNodeType.start)
189
- if elm is not None:
190
- node= TriccNodeMainStart(
191
- id = elm.attrib.get('id'),
192
- parent= elm.attrib.get('parent'),
193
- name = 'ms'+diagram.attrib.get('id'),
194
- label = elm.attrib.get('label'),
195
- form_id= elm.attrib.get('form_id'),
196
- process= elm.attrib.get('process')
197
- )
198
- else:
199
- elm = get_tricc_type(diagram, 'object', TriccNodeType.activity_start)
200
- if elm is not None:
201
- node = TriccNodeActivityStart(
202
- id = elm.attrib.get('id'),
203
- parent= elm.attrib.get('parent'),
204
- name = 'ma'+diagram.attrib.get('id'),
205
- label = diagram.attrib.get('name'),
206
- instance = int(elm.attrib.get('instance') if elm.attrib.get('instance') is not None else 1)
207
- )
208
-
209
- return node
210
-
211
-
212
- # converter XML item to object
213
-
214
- def set_additional_attributes(attribute_names, elm, node):
215
- if not isinstance(attribute_names, list):
216
- attribute_names = [attribute_names]
217
- for attributename in attribute_names:
218
- attribute = elm.attrib.get(attributename)
219
- if attribute is not None:
220
- # input expression can add a condition to either relevance (display) or calculate expression
221
- if attributename == 'expression_inputs':
222
- attribute = [attribute]
223
- elif attributename == 'instance':
224
- attribute = int(attribute)
225
- else:
226
- attribute
227
- setattr(node, attributename, attribute)
228
-
229
- def add_note_nodes(nodes, diagram, group):
230
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.note)
231
- add_tricc_nodes(nodes, TriccNodeNote, list, group, ['relevance'])
232
-
233
-
234
- def add_select_nodes(nodes, diagram, group=None):
235
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.select_one)
236
- add_tricc_select_nodes(diagram, nodes, TriccNodeSelectOne, list, group, ['required','save','filter','constraint','constraint_message'])
237
- #list = get_tricc_type_list(diagram, 'UserObject', TriccNodeType.select_yesno)
238
- #add_tricc_nodes(nodes, TriccNodeSelectYesNo, list, ['constraint','save','constraint_message','required'])
239
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.select_multiple)
240
- add_tricc_select_nodes(diagram, nodes, TriccNodeSelectMultiple, list, group, ['required','save','filter','constraint','constraint_message'])
241
-
242
- def add_input_nodes(nodes, diagram, group= None):
243
- list = get_tricc_type_list(diagram, ['object','UserObject'], TriccNodeType.decimal)
244
- add_tricc_nodes(nodes, TriccNodeDecimal, list, group, ['min','max', 'constraint','save','constraint_message','required'])
245
- list = get_tricc_type_list(diagram, ['object','UserObject'], TriccNodeType.integer)
246
- add_tricc_nodes(nodes, TriccNodeInteger, list, group, ['min','max', 'constraint','save','constraint_message','required'])
247
- list = get_tricc_type_list(diagram, ['object','UserObject'], TriccNodeType.text)
248
- add_tricc_nodes(nodes, TriccNodeText, list, group, ['constraint','save','constraint_message','required'])
249
- list = get_tricc_type_list(diagram, ['object','UserObject'], TriccNodeType.date)
250
- add_tricc_nodes(nodes, TriccNodeDate, list, group, ['constraint','save','constraint_message','required'])
251
-
252
- def add_calculate_nodes(nodes, diagram, group=None):
253
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.calculate)
254
- add_tricc_nodes(nodes, TriccNodeCalculate, list, group, ['save','expression','help', 'hint'])
255
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.add)
256
- add_tricc_nodes(nodes, TriccNodeAdd, list, group, ['save','expression'])
257
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.count)
258
- add_tricc_nodes(nodes, TriccNodeCount, list, group, ['save','expression'])
259
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.rhombus)
260
- add_tricc_nodes(nodes, TriccNodeRhombus, list, group, ['save','expression'],['reference'])
261
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.exclusive)
262
- add_tricc_base_node(nodes, TriccNodeExclusive, list, group)
263
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.wait)
264
- add_tricc_nodes(nodes, TriccNodeWait, list, group, ['save','expression'],['reference'])
265
- def get_hybride_node(nodes, diagram, group=None):
266
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.not_available)
267
- add_tricc_hybrid_select_nodes(nodes, TriccNodeSelectNotAvailable, list, group, [])
268
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.select_yesno)
269
- add_tricc_hybrid_select_nodes(nodes, TriccNodeSelectYesNo, list, group, ['required','save','filter','constraint','constraint_message'])
270
- #to do generate option
271
-
272
- def add_link_nodes(nodes, diagram, group=None):
273
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.link_out)
274
- add_tricc_nodes(nodes, TriccNodeLinkOut, list, group, [], ['reference'])
275
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.link_in)
276
- add_tricc_nodes(nodes, TriccNodeLinkIn, list, group)
277
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.goto)
278
- add_tricc_nodes(nodes, TriccNodeGoTo, list, group,['instance'],['link'])
279
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.activity_end)
280
- add_tricc_base_node(nodes, TriccNodeActivityEnd, list, group)
281
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.end)
282
- add_tricc_base_node(nodes, TriccNodeEnd, list, group)
283
- list = get_tricc_type_list(diagram, ['UserObject','object'], TriccNodeType.bridge)
284
- add_tricc_base_node(nodes, TriccNodeBridge, list, group)
285
-
286
-
287
-
288
- def get_select_options(diagram, select_node, nodes):
289
- options = {}
290
- i = 0
291
- list = get_mxcell_parent_list(diagram, select_node.id, TriccNodeType.select_option)
292
- options_name_list = []
293
- for elm in list:
294
- name = elm.attrib.get('name')
295
- if name in options_name_list and not name.endswith('_'):
296
- logger.error("Select question {0} have twice the option name {1}"\
297
- .format(select_node.get_name() ,name))
298
- else:
299
- options_name_list.append(name)
300
- id=elm.attrib.get('id')
301
- option = TriccNodeSelectOption(
302
- id = id,
303
- label = elm.attrib.get('label'),
304
- name = name,
305
- select = select_node,
306
- list_name = select_node.list_name,
307
- group = select_node.group
308
- )
309
- set_additional_attributes(['save'], elm, option)
310
- options[i]=option
311
- nodes[id]=option
312
- i += 1
313
- if len(list)== 0:
314
- logger.error("select {} does not have any option".format(select_node.label))
315
- else:
316
- return options
317
-
318
- ##TBR START
319
-
320
- def get_max_version(dict):
321
- max_version = None
322
- for id, sim_node in dict.items():
323
- if max_version is None or max_version.version < sim_node.version :
324
- max_version = sim_node
325
- return max_version
326
-
327
- def get_last_version(dict, name):
328
- max_version = None
329
- if name in dict:
330
- for sim_node in dict[name].values():
331
- if max_version is None or max_version.path_len < sim_node.path_len :
332
- max_version = sim_node
333
- return max_version
334
-
335
- def process_calculate(node,processed_nodes, stashed_nodes, calculates, used_calculates, warn = False, **kwargs ):
336
- # used_calculates dict[name, Dict[id, node]]
337
- # processed_nodes Dict[id, node]
338
- # calculates dict[name, Dict[id, node]]
339
- if node not in processed_nodes:
340
- # generate condition
341
- if is_ready_to_process(node, processed_nodes,False) and process_reference(node, calculates,used_calculates,processed_nodes,warn = warn):
342
- if is_rhombus_ready_to_process(node,processed_nodes):
343
- generate_calculates(node,calculates, used_calculates,processed_nodes)
344
- if issubclass(node.__class__, (TriccNodeDisplayCalculateBase )) and node.name is not None:
345
- # generate the calc node version by looking in the processed calculate
346
- last_calc = get_last_version(calculates, node.name)
347
- # get max version used
348
- #last_used_version = get_max_named_version(used_calculates, node.name)
349
- last_used_calc = get_last_version(used_calculates, node.name)
350
- # add calculate is added after the version collection so it is 0 in case there is no calc found
351
- add_calculate(calculates,node)
352
- # merge is there is unused version ->
353
- # current node not yet in the list so 1 item is enough
354
- if last_calc is not None:
355
- if last_used_calc is None or last_calc.path_len > last_used_calc.path_len:
356
- node.version = last_calc.version + 1
357
- node_to_delete = merge_calculate(node, calculates[node.name],last_used_calc)
358
- if node_to_delete is not None:
359
- for d_node in node_to_delete:
360
- del calculates[d_node.name][d_node.id]
361
-
362
- if d_node.name in used_calculates:
363
- if d_node.id in used_calculates[d_node.name]:
364
- logger.error("node {} used but deleted".format(d_node.get_name()))
365
- if d_node.id in d_node.activity.nodes:
366
- # mostly for end nodes
367
- if isinstance(d_node,(TriccNodeEnd,TriccNodeActivityEnd)):
368
- del d_node.activity.nodes[d_node.id]
369
- if d_node in stashed_nodes:
370
- logger.error("node {} not porcessed but deleted".format(d_node.get_name()))
371
- # chaining the calculate, this is needed each time there is a last used version
372
- if last_used_calc is not None :
373
- logger.debug("set last to false for node {} and add its link it to next one".format(last_used_calc.get_name()))
374
- set_prev_next_node(last_used_calc,node)
375
- last_used_calc.last = False
376
- update_calc_version(calculates,node.name)
377
- #if hasattr(node, 'next_nodes'):
378
- #node.next_nodes=reorder_node_list(node.next_nodes, node.group)
379
- return True
380
- # not ready to process or already processed
381
-
382
- return False
383
-
384
- def update_calc_version(calculates,name):
385
- if name in calculates and len(calculates[name])>1:
386
- ordered_list = sorted(list(calculates[name].values()), key=lambda x:x.path_len)
387
- i = 1
388
- len_max=len(calculates[name])
389
- for elm in ordered_list:
390
- elm.version=i
391
- elm.last= (i == len_max)
392
- i+=1
393
-
394
-
395
- def get_max_named_version(calculates,name):
396
- max = 0
397
- if name in calculates:
398
- for node in calculates[name].values():
399
- if node.version > max:
400
- max = node.version
401
- return max
402
-
403
- def get_count_node(node):
404
- count_id = generate_id()
405
- count_name = "cnt_"+count_id
406
- return TriccNodeCount(
407
- id = count_id,
408
- group = node.group,
409
- activity = node.activity,
410
- label = "count: "+node.get_name(),
411
- name = count_name,
412
- path_len=node.path_len
413
- )
414
-
415
-
416
- def inject_bridge_path(node, nodes):
417
- calc_id = generate_id()
418
- calc_name = "path_"+calc_id
419
- data = {
420
- 'id': calc_id,
421
- 'group': node.group,
422
- 'activity': node.activity,
423
- 'label': "path: " + node.get_name(),
424
- 'name': calc_name,
425
- 'path_len': node.path_len
426
- }
427
- prev_nodes = [nodes[n.source] for n in list(filter(lambda x: (x.target == node.id or x.target == node) and x.source in nodes ,node.activity.edges ))]
428
- if sum([0 if issubclass(n.__class__, (TriccNodeDisplayCalculateBase, TriccNodeRhombus)) else 1 for n in prev_nodes])>0 : #and len(node.prev_nodes)>1:
429
- calc= TriccNodeDisplayBridge( **data)
430
- else:
431
- calc = TriccNodeBridge( **data)
432
-
433
- for e in node.activity.edges:
434
- if e.target == node.id:
435
- e.target = calc.id
436
-
437
- # add edge between bridge and node
438
- set_prev_next_node(calc,node,edge_only=True)
439
-
440
- node.path_len += 1
441
- return calc
442
-
443
-
444
-
445
- def enrich_node(diagram, media_path, edge, node):
446
- if edge.target == node.id:
447
- # get node and process type
448
- type, message = get_message(diagram, edge.source)
449
- if type is not None:
450
- if type in (TriccNodeType.start, TriccNodeType.activity_start):
451
- return True
452
- elif hasattr(node, type):
453
- if message is not None:
454
- setattr(node,type,message)
455
- return True
456
- else:
457
- logger.warning("A attribute box of type {0} and value {1} is attached to an object not compatible {2}".format(type, message, node.get_name()))
458
- else:
459
- image = get_image(diagram, media_path, edge.source )
460
- if image is not None :
461
- if hasattr(node, 'image'):
462
- node.image = image
463
- return image
464
- else:
465
- print('image not supported for {} '.format(node.get_name()))
466
-
467
- def add_tricc_hybrid_select_nodes(nodes, type, list, group, attributes):
468
- for elm in list:
469
- id = elm.attrib.get('id')
470
- label = elm.attrib.get('label')
471
- name = elm.attrib.get('name')
472
- if name is None:
473
- name = elm.attrib.get('id')
474
- node = type(
475
- id=id,
476
- parent= elm.attrib.get('parent'),
477
- label = label if type != TriccNodeSelectNotAvailable else NO_LABEL,
478
- name = name,
479
- required=True,
480
- group = group,
481
- activity = group,
482
- list_name = 'yes_no' if type == TriccNodeSelectYesNo else TRICC_LIST_NAME.format(id)
483
- )
484
- if type == TriccNodeSelectNotAvailable:
485
- node.options = get_select_not_available_options(node, group, label)
486
- nodes[node.options[0].id]=node.options[0]
487
- elif type == TriccNodeSelectYesNo:
488
- node.options = get_select_yes_no_options(node, group)
489
- nodes[node.options[0].id]=node.options[0]
490
- nodes[node.options[1].id]=node.options[1]
491
- set_additional_attributes(attributes, elm, node)
492
- nodes[id]=node
493
-
494
-
495
- def add_tricc_select_nodes(diagram, nodes, type, list, group, attributes):
496
- for elm in list:
497
- id = elm.attrib.get('id')
498
- node = type(
499
- id = id,
500
- parent= elm.attrib.get('parent'),
501
- label = elm.attrib.get('label'),
502
- name = elm.attrib.get('name'),
503
- required=True,
504
- group = group,
505
- activity = group,
506
- list_name = TRICC_LIST_NAME.format(id)
507
- )
508
- node.options = get_select_options(diagram, node, nodes)
509
- set_additional_attributes(attributes, elm, node)
510
-
511
- nodes[id]=node
512
-
513
-
514
-
515
- def add_tricc_nodes(nodes, type, list, group, attributes = [], mandatory_attributes = []):
516
- mandatory_attributes += ['label','name']
517
- add_tricc_base_node(nodes, type, list, group, attributes, mandatory_attributes)
518
-
519
-
520
- def add_tricc_base_node(nodes, type, list, group, attributes = [], mandatory_attributes = []):
521
- for elm in list:
522
- id = elm.attrib.get('id')
523
- parent= elm.attrib.get('parent')
524
- node = type(
525
- id = id,
526
- parent= parent,
527
- group = group,
528
- activity = group,
529
- **set_mandatory_attribute(elm, mandatory_attributes, group.name)
530
- )
531
- set_additional_attributes(attributes, elm, node)
532
- nodes[id]=node
533
-
534
- def set_mandatory_attribute(elm, mandatory_attributes, groupname = None):
535
- param = {}
536
- for attributes in mandatory_attributes:
537
- attribute_value = elm.attrib.get(attributes)
538
- if attribute_value is None:
539
- if elm.attrib.get('label')is not None:
540
- display_name = elm.attrib.get('label')
541
- elif elm.attrib.get('name')is not None:
542
- display_name = elm.attrib.get('name')
543
- else:
544
- display_name = elm.attrib.get('id')
545
- logger.error("the attibute {} is mandatory but not found in {} within group {}".format(attributes, display_name, groupname if groupname is not None else ''))
546
- if mandatory_attributes == "source":
547
- if elm.attrib.get('target') is not None:
548
- logger.error("the attibute target is ".format(elm.attrib.get('target')))
549
- elif mandatory_attributes == "target":
550
- if elm.attrib.get('source') is not None:
551
- logger.error("the attibute target is ".format(elm.attrib.get('source')))
552
- exit()
553
- if attributes == 'link':
554
- param[attributes] = clean_link(attribute_value)
555
- elif attributes in ('parent','id', 'source', 'target'):
556
- param[attributes]=attribute_value
557
- elif attribute_value is not None:
558
- param[attributes]=remove_html(attribute_value.strip())
559
- return param
560
-
561
- def clean_link(link):
562
- # link have the format "data:page/id,DiagramID"
563
- link_parts = link.split(',')
564
- if link_parts[0] == 'data:page/id' and len(link_parts)==2:
565
- return link_parts[1]
566
-
567
- def get_groups(diagram, nodes, parent_group):
568
- groups = {}
569
- list=get_tricc_type_list(diagram, 'object', TriccNodeType.page )
570
- for elm in list:
571
- add_group(elm, diagram, nodes, groups,parent_group)
572
- return groups
573
-
574
- def add_group(elm, diagram, nodes, groups, parent_group):
575
- id = elm.attrib.get('id')
576
- if id not in groups:
577
- group = TriccGroup(
578
- name = elm.attrib.get('name'),
579
- label = elm.attrib.get('label'),
580
- id = id,
581
- group = parent_group
582
- )
583
- # get elememt witn parent = id and tricc_type defiend
584
- list_child = get_tricc_type_list(diagram, ['object','UserObject'], tricc_type=None, parent_id = id)
585
- add_group_to_child(group, diagram,list_child, nodes, groups, parent_group)
586
- if group is not None:
587
- groups[group.id] = group
588
- return group
589
-
590
- def add_group_to_child(group, diagram,list_child, nodes, groups, parent_group):
591
- for child_elm in list_child:
592
- if child_elm.attrib.get('tricc_type') == TriccNodeType.container_hint_media:
593
- list_sub_child = get_tricc_type_list(diagram, ['object','UserObject'], tricc_type=None, parent_id =child_elm.attrib.get('id') )
594
- add_group_to_child(group, diagram,list_sub_child, nodes, groups, parent_group )
595
- elif child_elm.attrib.get('tricc_type') == TriccNodeType.page:
596
- child_group_id = child_elm.attrib.get('id')
597
- if not child_group_id in groups:
598
- child_group = add_group(child_elm, diagram, nodes, groups, group)
599
- else:
600
- child_group = groups[child_group_id]
601
- child_group.group = group
602
- else:
603
- child_id=child_elm.attrib.get('id')
604
- if child_id is not None and child_id in nodes:
605
- nodes[child_id].group = group
606
-
607
-
608
- def get_image(diagram, path, id, image_name = None ):
609
- elm = get_mxcell(diagram, id)
610
- if elm is not None:
611
- style=elm.attrib.get('style')
612
- if image_name is None:
613
- image_name = id
614
- file_name = add_image_from_style(style, path, image_name)
615
- if file_name is not None:
616
- return file_name
617
-
618
-
619
- def add_image_from_style(style,path, image_name):
620
- image_attrib = None
621
- if style is not None and 'image=data:image/' in style:
622
- image_attrib = style.split('image=data:image/')
623
- if image_attrib is not None and len(image_attrib)==2:
624
- image_parts = image_attrib[1].split(',')
625
- if len(image_parts) == 2:
626
- payload = image_parts[1][:-1]
627
- path = os.path.join(path, 'images')
628
- file_name = os.path.join(path , image_name+ '.' + image_parts[0])
629
- if not(os.path.isdir(path)): # check if it exists, because if it does, error will be raised
630
- # (later change to make folder complaint to CHT)
631
- os.makedirs(path, exist_ok = True)
632
- with open(file_name , "wb") as fh:
633
- fh.write(base64.decodebytes(payload.encode('ascii')))
634
- return os.path.basename(file_name)
635
-
636
- def get_contained_main_node(diagram, id):
637
- list = get_mxcell_parent_list(diagram, id, media_nodes)
638
- if isinstance(list, List) and len(list)>0:
639
- #use only the first one
640
- return list[0]
641
-
642
- def get_message(diagram, id):
643
- elm = get_mxcell(diagram, id)
644
- if elm is not None:
645
- type = elm.attrib.get('odk_type')
646
- if type is not None:
647
- if type.endswith("-message"):
648
- type = type[:-8]
649
- return type, elm.attrib.get('label')
650
- #use only the first one
651
- return None, None
652
-
653
- def get_edges( diagram):
654
- edges = []
655
- list = get_edges_list(diagram)
656
- for elm in list:
657
- id = elm.attrib.get('id')
658
- edge = TriccEdge(
659
- id = id,
660
- **set_mandatory_attribute(elm, ['source' , 'parent', 'target'], diagram.attrib.get('name'))
661
- )
662
- set_additional_attributes(['value'], elm, edge)
663
- if edge.value is not None:
664
- edge.value = remove_html(edge.value)
665
- edges.append(edge)
666
- return edges
667
-
668
- ## Process edges
669
-
670
- def process_factor_edge(edge,nodes):
671
- factor = edge.value.strip()
672
- if factor != 1:
673
- return TriccNodeCalculate(
674
- id = edge.id,
675
- expression_reference = "number(${{{}}}) * {}".format('', factor),
676
- reference = [nodes[edge.source]],
677
- activity = nodes[edge.source].activity,
678
- group = nodes[edge.source].group,
679
- label= "factor {}".format(factor)
680
- )
681
- return None
682
-
683
-
684
- def process_condition_edge(edge,nodes):
685
- label = edge.value.strip()
686
- for op in OPERATION_LIST:
687
- if op in label:
688
- # insert rhombus
689
- return TriccNodeRhombus(
690
- id = edge.id,
691
- reference = [nodes[edge.source]],
692
- path = nodes[edge.source],
693
- activity = nodes[edge.source].activity,
694
- group = nodes[edge.source].group,
695
- label= label
696
- )
697
- def process_exclusive_edge(edge, nodes):
698
- error = None
699
- if issubclass(nodes[edge.source].__class__, TriccNodeCalculateBase):
700
- # insert Negate
701
- if not isinstance(nodes[edge.target], TriccNodeExclusive) or not isinstance(nodes[edge.source], TriccNodeExclusive):
702
- return TriccNodeExclusive(
703
- id = edge.id,
704
- activity = nodes[edge.target].activity,
705
- group = nodes[edge.target].group
706
- )
707
- else:
708
- error = "No after or before a exclusice/negate node"
709
- else:
710
- error = "label not after a yesno nor a calculate"
711
- if error is not None:
712
- logger.warning("Edge between {0} and {1} with label '{2}' could not be interpreted: {3}".format(
713
- nodes[edge.source].get_name(),
714
- nodes[edge.target].get_name(),
715
- edge.value.strip(),
716
- error
717
- ))
718
- return None
719
-
720
- def process_yesno_edge(edge, nodes):
721
- if edge.value is None:
722
- logger.error("yesNo {} node with labelless edges".format(nodes[edge.source].get_name()))
723
- exit()
724
- label = edge.value.strip().lower()
725
- yes_option = None
726
- no_option = None
727
- for option in nodes[edge.source].options.values():
728
- if option.name == '1':
729
- yes_option = option
730
- else:
731
- no_option = option
732
- if label.lower() in TRICC_FOLOW_LABEL:
733
- pass
734
- elif label.lower() in TRICC_YES_LABEL:
735
- edge.source = yes_option.id
736
- elif label.lower() in TRICC_NO_LABEL:
737
- edge.source = no_option.id
738
- else:
739
- logger.warning("edge {0} is coming from select {1}".format(edge.id, nodes[edge.source].get_name()))
740
-