tricc-oo 1.5.22__py3-none-any.whl → 1.5.24__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 (45) hide show
  1. tests/build.py +17 -23
  2. tests/test_cql.py +37 -108
  3. tests/to_ocl.py +15 -17
  4. tricc_oo/__init__.py +0 -6
  5. tricc_oo/converters/codesystem_to_ocl.py +51 -40
  6. tricc_oo/converters/cql/cqlLexer.py +1 -0
  7. tricc_oo/converters/cql/cqlListener.py +1 -0
  8. tricc_oo/converters/cql/cqlParser.py +1 -0
  9. tricc_oo/converters/cql/cqlVisitor.py +1 -0
  10. tricc_oo/converters/cql_to_operation.py +125 -123
  11. tricc_oo/converters/datadictionnary.py +45 -54
  12. tricc_oo/converters/drawio_type_map.py +143 -61
  13. tricc_oo/converters/tricc_to_xls_form.py +14 -24
  14. tricc_oo/converters/utils.py +3 -3
  15. tricc_oo/converters/xml_to_tricc.py +286 -231
  16. tricc_oo/models/__init__.py +2 -1
  17. tricc_oo/models/base.py +300 -308
  18. tricc_oo/models/calculate.py +63 -49
  19. tricc_oo/models/lang.py +26 -27
  20. tricc_oo/models/ocl.py +146 -161
  21. tricc_oo/models/ordered_set.py +15 -19
  22. tricc_oo/models/tricc.py +145 -89
  23. tricc_oo/parsers/xml.py +15 -30
  24. tricc_oo/serializers/planuml.py +4 -6
  25. tricc_oo/serializers/xls_form.py +81 -135
  26. tricc_oo/strategies/input/base_input_strategy.py +28 -32
  27. tricc_oo/strategies/input/drawio.py +59 -71
  28. tricc_oo/strategies/output/base_output_strategy.py +142 -67
  29. tricc_oo/strategies/output/fhir_form.py +377 -0
  30. tricc_oo/strategies/output/html_form.py +224 -0
  31. tricc_oo/strategies/output/openmrs_form.py +647 -0
  32. tricc_oo/strategies/output/spice.py +106 -127
  33. tricc_oo/strategies/output/xls_form.py +263 -222
  34. tricc_oo/strategies/output/xlsform_cdss.py +623 -142
  35. tricc_oo/strategies/output/xlsform_cht.py +108 -115
  36. tricc_oo/strategies/output/xlsform_cht_hf.py +13 -24
  37. tricc_oo/visitors/tricc.py +1297 -1016
  38. tricc_oo/visitors/utils.py +16 -16
  39. tricc_oo/visitors/xform_pd.py +91 -89
  40. {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.24.dist-info}/METADATA +127 -84
  41. tricc_oo-1.5.24.dist-info/RECORD +50 -0
  42. tricc_oo-1.5.24.dist-info/licenses/LICENSE +373 -0
  43. tricc_oo-1.5.22.dist-info/RECORD +0 -46
  44. {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.24.dist-info}/WHEEL +0 -0
  45. {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.24.dist-info}/top_level.txt +0 -0
@@ -1,65 +1,119 @@
1
1
  import re
2
2
  import logging
3
-
4
- from tricc_oo.converters.utils import *
5
- from tricc_oo.models import *
6
- from tricc_oo.visitors.tricc import *
3
+ import requests
4
+ import base64
5
+
6
+
7
+ from tricc_oo.converters.utils import generate_id
8
+ from tricc_oo.models.base import (
9
+ TriccBaseModel, TriccNodeType,
10
+ TriccOperator, TriccOperation, TriccStatic, TriccReference, not_clean,
11
+ and_join, or_join, clean_or_list, nand_join, TriccEdge
12
+ )
13
+ from tricc_oo.models.ordered_set import OrderedSet
14
+ from tricc_oo.models.calculate import (
15
+ TriccNodeDisplayBridge,
16
+ TriccNodeBridge,
17
+ TriccNodeWait,
18
+ TriccNodeCalculate,
19
+ TriccNodeRhombus,
20
+ TriccNodeDisplayCalculateBase,
21
+ TriccNodeExclusive,
22
+ TriccNodeProposedDiagnosis,
23
+ TriccNodeCount,
24
+ TriccNodeAdd,
25
+ TriccNodeFakeCalculateBase,
26
+ TriccRhombusMixIn,
27
+ TriccNodeInput,
28
+ TriccNodeActivityEnd,
29
+ TriccNodeActivityStart,
30
+ TriccNodeEnd,
31
+ get_node_from_id,
32
+
33
+ )
34
+ from tricc_oo.models.tricc import (
35
+ TriccNodeCalculateBase, TriccNodeActivity, TriccNodeBaseModel, TriccNodeNumber,
36
+ TriccNodeSelectMultiple,
37
+ TriccNodeSelectOne,
38
+ TriccNodeSelectOption,
39
+ TriccNodeSelectYesNo,
40
+ TriccNodeInputModel,
41
+ TriccNodeSelect,
42
+ TriccNodeSelectNotAvailable,
43
+ TriccNodeMoreInfo,
44
+ TriccNodeDisplayModel,
45
+ TriccNodeMainStart,
46
+ TriccNodeAcceptDiagnostic,
47
+ )
7
48
  from tricc_oo.visitors.utils import PROCESSES
49
+ from tricc_oo.converters.cql_to_operation import transform_cql_to_operation
8
50
  from tricc_oo.converters.datadictionnary import lookup_codesystems_code
51
+ from tricc_oo.converters.tricc_to_xls_form import get_list_names, get_export_name
9
52
 
10
53
  logger = logging.getLogger("default")
11
54
  ONE_QUESTION_AT_A_TIME = False
12
55
 
13
- TRICC_TRUE_VALUE = 'true'
14
- TRICC_FALSE_VALUE = 'false'
56
+ TRICC_TRUE_VALUE = "true"
57
+ TRICC_FALSE_VALUE = "false"
58
+
15
59
 
16
- def merge_node(from_node,to_node):
60
+ def merge_node(from_node, to_node):
17
61
  if from_node.activity != to_node.activity:
18
62
  logger.critical("Cannot merge nodes from different activities")
19
- elif issubclass(from_node.__class__, TriccNodeCalculateBase) and issubclass(to_node.__class__, TriccNodeCalculateBase):
63
+ elif issubclass(from_node.__class__, TriccNodeCalculateBase) and issubclass(
64
+ to_node.__class__, TriccNodeCalculateBase
65
+ ):
20
66
  for e in to_node.activity.edges:
21
67
  if e.target == from_node.id:
22
68
  e.target = to_node.id
23
69
  else:
24
70
  logger.critical("Cannot merge not calculate nodes ")
25
-
71
+
26
72
 
27
73
  def get_max_version(dict):
28
74
  max_version = None
29
75
  for id, sim_node in dict.items():
30
- if max_version is None or max_version.version < sim_node.version :
76
+ if max_version is None or max_version.version < sim_node.version:
31
77
  max_version = sim_node
32
78
  return max_version
33
79
 
80
+
34
81
  def get_versions(name, iterable):
35
82
  return [n for n in iterable if version_filter(name)(n)]
36
83
 
84
+
37
85
  def version_filter(name):
38
- return lambda item: hasattr(item, 'name') and ( (isinstance(item, TriccNodeEnd) and name == item.get_reference()) or item.name == name ) and not isinstance(item, TriccNodeSelectOption)
86
+ return (
87
+ lambda item: hasattr(item, "name")
88
+ and ((isinstance(item, TriccNodeEnd) and name == item.get_reference()) or item.name == name)
89
+ and not isinstance(item, TriccNodeSelectOption)
90
+ )
91
+
39
92
 
40
- def get_last_version(name, processed_nodes, _list=None):
93
+ def get_last_version(name, processed_nodes, _list=None):
41
94
  max_version = None
42
95
  if isinstance(_list, dict):
43
96
  _list = _list[name].values() if name in _list else []
44
97
  if _list is None:
45
98
  if isinstance(processed_nodes, OrderedSet):
46
99
  return processed_nodes.find_last(version_filter(name))
47
- else:
100
+ else:
48
101
  _list = get_versions(name, processed_nodes)
49
102
  if _list:
50
- for sim_node in _list:
103
+ for sim_node in _list:
51
104
  # get the max version while not taking a node that have a next node before next calc
52
- if ((max_version is None
53
- or max_version.activity.path_len < sim_node.activity.path_len
54
- or max_version.path_len < sim_node.path_len
105
+ if (
106
+ max_version is None
107
+ or max_version.activity.path_len < sim_node.activity.path_len
108
+ or max_version.path_len < sim_node.path_len
55
109
  or (max_version.path_len == sim_node.path_len and hash(max_version.id) < hash(sim_node.id))
56
- ) ):
110
+ ):
57
111
  max_version = sim_node
58
112
  if not max_version:
59
- already_processed = list(filter(lambda p_node: hasattr(p_node, 'name') and p_node.name == name , _list))
113
+ already_processed = list(filter(lambda p_node: hasattr(p_node, "name") and p_node.name == name, _list))
60
114
  if already_processed:
61
- max_version = sorted(filtered, key=lambda x: x.path_len, reverse=False)[0]
62
-
115
+ max_version = sorted(already_processed, key=lambda x: x.path_len, reverse=False)[0]
116
+
63
117
  return max_version
64
118
 
65
119
 
@@ -67,324 +121,321 @@ def get_last_version(name, processed_nodes, _list=None):
67
121
  # node is the node to calculate
68
122
  # processed_nodes are the list of processed nodes
69
123
  def get_node_expressions(node, processed_nodes, process=None):
70
- get_overall_exp = issubclass(node.__class__, TriccNodeCalculateBase) and not issubclass(node.__class__, (TriccNodeDisplayBridge,TriccNodeBridge))
124
+ get_overall_exp = issubclass(node.__class__, TriccNodeCalculateBase) and not issubclass(
125
+ node.__class__, (TriccNodeDisplayBridge, TriccNodeBridge)
126
+ )
71
127
  expression = None
72
128
  # in case of recursive call processed_nodes will be None
73
129
  if processed_nodes is None or is_ready_to_process(node, processed_nodes=processed_nodes):
74
- expression = get_node_expression(node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process)
75
-
130
+ expression = get_node_expression(
131
+ node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process
132
+ )
133
+
76
134
  # if get_overall_exp:
77
- # if expression and (not isinstance(expression, str) or expression != '') and expression is not TriccStatic(True) :
135
+ # if expression and (not isinstance(expression, str) or expression != '')
136
+ # and expression is not TriccStatic(True) :
78
137
  # num_expression = TriccOperation(
79
138
  # TriccOperator.CAST_NUMBER,
80
139
  # [expression]
81
140
  # )
82
141
  # elif expression is TriccStatic(True) or (not expression and get_overall_exp):
83
- # expression = TriccStatic(True)
142
+ # expression = TriccStatic(True)
84
143
  # else:
85
144
  # expression = None
86
145
  if (
87
- issubclass(node.__class__, TriccNodeCalculateBase)
88
- and not isinstance(expression, (TriccStatic, TriccReference, TriccOperation))
89
- and str(expression) != ''
146
+ issubclass(node.__class__, TriccNodeCalculateBase)
147
+ and not isinstance(expression, (TriccStatic, TriccReference, TriccOperation))
148
+ and str(expression) != ""
90
149
  and not isinstance(node, (TriccNodeWait, TriccNodeActivityEnd, TriccNodeActivityStart, TriccNodeEnd))
91
150
  ):
92
151
  logger.warning("Calculate {0} returning no calculations".format(node.get_name()))
93
152
  expression = TriccStatic(True)
94
153
  return expression
95
154
 
155
+
96
156
  def set_last_version_false(node, processed_nodes):
97
- if isinstance(node, (TriccNodeDiagnosis, TriccNodeSelectOption)):
157
+ if isinstance(node, (TriccNodeSelectOption)):
98
158
  return
99
159
  node_name = node.name if not isinstance(node, TriccNodeEnd) else node.get_reference()
100
- #last_version = get_last_version(node_name, processed_nodes) if issubclass(node.__class__, (TriccNodeDisplayModel, TriccNodeDisplayCalculateBase, TriccNodeEnd)) and not isinstance(node, TriccNodeSelectOption) else None
101
160
  last_version = processed_nodes.find_prev(node, version_filter(node_name))
102
- if last_version and getattr(node, 'process', '') != 'pause':
103
- # 0-100 for manually specified instance. 100-200 for auto instance
161
+ if last_version and getattr(node, "process", "") != "pause":
162
+ # 0-100 for manually specified instance. 100-200 for auto instance
104
163
  node.version = get_next_version(node.name, processed_nodes, last_version.version, 0)
105
164
  last_version.last = False
106
165
  node.path_len = max(node.path_len, last_version.path_len + 1)
107
166
  return last_version
108
-
167
+
168
+
109
169
  def get_version_inheritance(node, last_version, processed_nodes):
110
- # FIXME this is for XLS form where only calculate are evaluated for a activity that is not triggered
111
- if not issubclass(node.__class__, (TriccNodeInputModel)):
112
- node.last = True
113
- if (
114
- issubclass(node.__class__, (TriccNodeDisplayCalculateBase, TriccNodeEnd)) and node.name is not None
115
- ):
116
- #logger.debug("set last to false for node {} and add its link it to next one".format(last_used_calc.get_name()))
117
- if node.prev_nodes:
118
- set_prev_next_node(last_version, node)
119
- else:
120
- expression = node.expression or node.expression_reference or getattr(node, 'relevance', None)
121
- expression = merge_expression(expression, last_version)
122
- if node.expression:
123
- node.expression = expression
124
- elif node.expression_reference:
125
- node.expression_reference = expression
126
- elif node.relevance:
127
- node.relevance = expression
128
- else:
129
- node.last = False
130
- calc = TriccNodeCalculate(
131
- id=generate_id(f"save{node.id}"),
132
- name=node.name,
133
- path_len=node.path_len+1,
134
- #version=get_next_version(node.name, processed_nodes, node.version+2),
135
- expression= merge_expression(node, last_version),
136
- label= f"merge{node.id}",
137
- last=True,
138
- activity=node.activity,
139
- group=node.group
140
- )
141
- node.activity.nodes[calc.id]=calc
142
- node.activity.calculates.append(calc)
143
- #set_last_version_false(calc, processed_nodes)
144
- processed_nodes.add(calc)
145
- if issubclass(node.__class__, TriccNodeInputModel):
146
- node.expression = TriccOperation(
147
- TriccOperator.COALESCE,
148
- [
149
- '$this',
150
- last_version
151
- ]
152
- )
153
-
170
+ # FIXME this is for XLS form where only calculate are evaluated
171
+ # for a activity that is not triggered
172
+ if not issubclass(node.__class__, (TriccNodeInputModel)):
173
+ node.last = True
174
+ if issubclass(node.__class__, (TriccNodeDisplayCalculateBase, TriccNodeEnd)) and node.name is not None:
175
+ # logger.debug("set last to false for node {}
176
+ # and add its link it to next one".format(last_used_calc.get_name()))
177
+ if node.prev_nodes:
178
+ set_prev_next_node(last_version, node)
179
+ else:
180
+ expression = node.expression or node.expression_reference or getattr(node, "relevance", None)
181
+ expression = merge_expression(expression, last_version)
182
+ if node.expression:
183
+ node.expression = expression
184
+ elif node.expression_reference:
185
+ node.expression_reference = expression
186
+ elif node.relevance:
187
+ node.relevance = expression
188
+ else:
189
+ node.last = False
190
+ calc = TriccNodeCalculate(
191
+ id=generate_id(f"save{node.id}"),
192
+ name=node.name,
193
+ path_len=node.path_len + 1,
194
+ # version=get_next_version(node.name, processed_nodes, node.version+2),
195
+ expression=merge_expression(node, last_version),
196
+ label=f"merge{node.id}",
197
+ last=True,
198
+ activity=node.activity,
199
+ group=node.group,
200
+ )
201
+ node.activity.nodes[calc.id] = calc
202
+ node.activity.calculates.append(calc)
203
+ # set_last_version_false(calc, processed_nodes)
204
+ processed_nodes.add(calc)
205
+ if issubclass(node.__class__, TriccNodeInputModel):
206
+ node.expression = TriccOperation(TriccOperator.COALESCE, ["$this", last_version])
207
+
208
+
154
209
  def merge_expression(expression, last_version):
155
210
  datatype = expression.get_datatype()
156
- if datatype == 'boolean':
157
- expression = or_join(
158
- [TriccOperation(TriccOperator.ISTRUE, [last_version]), expression]
159
- )
160
-
161
- elif datatype == 'number':
162
- expression = TriccOperation(
163
- TriccOperator.PLUS,
164
- [last_version, expression]
165
- )
211
+ if datatype == "boolean":
212
+ expression = or_join([TriccOperation(TriccOperator.ISTRUE, [last_version]), expression])
213
+
214
+ elif datatype == "number":
215
+ expression = TriccOperation(TriccOperator.PLUS, [last_version, expression])
166
216
  else:
167
- expression = TriccOperation(
168
- TriccOperator.COALESCE,
169
- [last_version, expression]
170
- )
217
+ expression = TriccOperation(TriccOperator.COALESCE, [last_version, expression])
171
218
  return expression
172
219
 
173
- def process_calculate(node,processed_nodes, stashed_nodes, calculates, used_calculates,
174
- warn = False, process=None, **kwargs ):
175
- # used_calculates dict[name, Dict[id, node]]
176
- # processed_nodes Dict[id, node]
177
- # calculates dict[name, Dict[id, node]]
178
-
179
-
220
+
221
+ def load_calculate(
222
+ node, processed_nodes, stashed_nodes, calculates, used_calculates, warn=False, process=None, **kwargs
223
+ ):
224
+ # used_calculates dict[name, Dict[id, node]]
225
+ # processed_nodes Dict[id, node]
226
+ # calculates dict[name, Dict[id, node]]
227
+
180
228
  if node not in processed_nodes:
181
229
  # generate condition
182
- if (
183
- is_ready_to_process(node, processed_nodes,True)
184
- and process_reference(
185
- node,
186
- processed_nodes=processed_nodes,
187
- calculates=calculates,
188
- used_calculates=used_calculates,
189
- replace_reference=False,
190
- warn = warn,
191
- codesystems= kwargs.get('codesystems', None)
192
- )
230
+ if is_ready_to_process(node, processed_nodes, True) and process_reference(
231
+ node,
232
+ processed_nodes=processed_nodes,
233
+ calculates=calculates,
234
+ used_calculates=used_calculates,
235
+ replace_reference=False,
236
+ warn=warn,
237
+ codesystems=kwargs.get("codesystems", None),
193
238
  ):
194
- if kwargs.get('warn', True):
195
- logger.debug('Processing relevance for node {0}'.format(node.get_name()))
239
+ if kwargs.get("warn", True):
240
+ logger.debug("Processing relevance for node {0}".format(node.get_name()))
196
241
  # tricc diagnostic have the same name as proposed diag but will be serialised with different names
197
242
 
198
- last_version = set_last_version_false(node, processed_nodes)
243
+ last_version = set_last_version_false(node, processed_nodes)
199
244
  if last_version:
200
245
  last_version = get_version_inheritance(node, last_version, processed_nodes)
201
246
 
202
- generate_calculates(node,calculates, used_calculates,processed_nodes=processed_nodes, process=process)
203
-
204
-
247
+ generate_calculates(node, calculates, used_calculates, processed_nodes=processed_nodes, process=process)
205
248
 
206
- # if has prev, create condition
207
- if hasattr(node, 'relevance') and (node.relevance is None or isinstance(node.relevance, TriccOperation)):
249
+ # if has prev, create condition
250
+ if hasattr(node, "relevance") and (node.relevance is None or isinstance(node.relevance, TriccOperation)):
208
251
  node.relevance = get_node_expressions(node, processed_nodes=processed_nodes, process=process)
209
252
  # manage not Available
210
253
  if isinstance(node, TriccNodeSelectNotAvailable):
211
254
  # update the checkbox
212
- if node.parent:
255
+ if node.parent:
213
256
  if len(node.prev_nodes) == 1:
214
257
  prev = list(node.prev_nodes)[0]
215
258
  if isinstance(prev, TriccNodeMoreInfo) and prev.parent.name == node.name:
216
259
  prev.parent = node
217
-
218
-
260
+
219
261
  # managing more info on NotAvaialbee
220
262
  parent_empty = TriccOperation(TriccOperator.ISNULL, [node.parent])
221
- node.relevance = and_join([node.parent.relevance, parent_empty])
263
+ node.relevance = and_join([node.parent.relevance, parent_empty])
222
264
  node.required = parent_empty
223
265
  node.constraint = parent_empty
224
266
  node.constraint_message = "Cannot be selected with a value entered above"
225
267
  # update the check box parent : create loop error
226
268
  node.parent.required = None # "${{{0}}}=''".format(node.name)
227
269
  else:
228
- logger.warning("not available node {} does't have a single parent".format(node.get_name()))
270
+ logger.warning("not available node {} does't have a single parent".format(node.get_name()))
229
271
  elif isinstance(node.relevance, TriccOperation):
230
272
  relevance_reference = list(node.relevance.get_references())
231
273
  for r in relevance_reference:
232
- if issubclass(r.__class__, (TriccNodeDisplayCalculateBase )):
274
+ if issubclass(r.__class__, (TriccNodeDisplayCalculateBase)):
233
275
  add_used_calculate(node, r, calculates, used_calculates, processed_nodes)
234
-
235
- if last_version and hasattr(node, 'relevance'):
276
+
277
+ if last_version and hasattr(node, "relevance"):
236
278
  if isinstance(node, TriccNodeInputModel):
237
- version_relevance = TriccOperation(
238
- TriccOperator.ISNULL,
239
- [last_version]
240
- )
279
+ version_relevance = TriccOperation(TriccOperator.ISNULL, [last_version])
241
280
  elif last_version.relevance:
242
- version_relevance = not_clean(
243
- last_version.relevance
244
- )
281
+ version_relevance = not_clean(last_version.relevance)
245
282
  elif last_version.activity.relevance:
246
283
  version_relevance = not_clean(
247
- last_version.activity.relevance,
284
+ last_version.activity.relevance,
248
285
  )
249
286
  else:
250
287
  version_relevance = None
251
-
288
+
252
289
  if version_relevance:
253
- if getattr(node, 'relevance', None):
254
- node.relevance = and_join(
255
- [
256
- version_relevance,
257
- node.relevance
258
- ])
259
-
260
- elif hasattr(node, 'relevance'):
290
+ if getattr(node, "relevance", None):
291
+ node.relevance = and_join([version_relevance, node.relevance])
292
+
293
+ elif hasattr(node, "relevance"):
261
294
  node.relevance = version_relevance
262
295
 
263
- #if hasattr(node, 'next_nodes'):
264
- #node.next_nodes=reorder_node_list(node.next_nodes, node.group)
296
+ # if hasattr(node, 'next_nodes'):
297
+ # node.next_nodes=reorder_node_list(node.next_nodes, node.group)
265
298
  process_reference(
266
- node,
267
- processed_nodes=processed_nodes,
299
+ node,
300
+ processed_nodes=processed_nodes,
268
301
  calculates=calculates,
269
- used_calculates=used_calculates,
270
- replace_reference=True,
271
- warn = warn,
272
- codesystems= kwargs.get('codesystems', None)
302
+ used_calculates=used_calculates,
303
+ replace_reference=True,
304
+ warn=warn,
305
+ codesystems=kwargs.get("codesystems", None),
273
306
  )
274
307
  if isinstance(node, (TriccNodeMainStart, TriccNodeActivityStart)):
275
308
  process_reference(
276
309
  node.activity,
277
- processed_nodes=processed_nodes,
310
+ processed_nodes=processed_nodes,
278
311
  calculates=calculates,
279
- used_calculates=used_calculates,
280
- replace_reference=True,
281
- warn = warn,
282
- codesystems= kwargs.get('codesystems', None)
312
+ used_calculates=used_calculates,
313
+ replace_reference=True,
314
+ warn=warn,
315
+ codesystems=kwargs.get("codesystems", None),
283
316
  )
284
317
 
285
318
  return True
286
319
  # not ready to process or already processed
287
320
 
288
321
  return False
289
-
290
322
 
291
323
 
292
- def get_max_named_version(calculates,name):
324
+ def get_max_named_version(calculates, name):
293
325
  max = 0
294
- if name in calculates:
295
- for node in calculates[name].values():
326
+ if name in calculates:
327
+ for node in calculates[name].values():
296
328
  if node.version > max:
297
329
  max = node.version
298
330
  return max
299
331
 
332
+
300
333
  def get_count_node(node):
301
334
  count_id = generate_id(f"count{node.id}")
302
- count_name = "cnt_"+count_id
335
+ count_name = "cnt_" + count_id
303
336
  return TriccNodeCount(
304
- id = count_id,
305
- group = node.group,
306
- activity = node.activity,
307
- label = "count: "+node.get_name(),
308
- name = count_name,
309
- path_len=node.path_len
337
+ id=count_id,
338
+ group=node.group,
339
+ activity=node.activity,
340
+ label="count: " + node.get_name(),
341
+ name=count_name,
342
+ path_len=node.path_len,
310
343
  )
311
-
312
- ### Function that inject a wait after path that will wait for the nodes
313
- def get_activity_wait(prev_nodes, nodes_to_wait, next_nodes, replaced_node = None, edge_only = False, activity = None):
314
344
 
315
- if issubclass(nodes_to_wait.__class__,TriccBaseModel):
345
+
346
+ # Function that inject a wait after path that will wait for the nodes
347
+
348
+
349
+ def get_activity_wait(prev_nodes, nodes_to_wait, next_nodes, replaced_node=None, edge_only=False, activity=None):
350
+
351
+ if issubclass(nodes_to_wait.__class__, TriccBaseModel):
316
352
  nodes_to_wait = [nodes_to_wait]
317
- if issubclass(prev_nodes.__class__,TriccBaseModel):
353
+ if issubclass(prev_nodes.__class__, TriccBaseModel):
318
354
  prev_nodes = set([prev_nodes])
319
355
  elif isinstance(prev_nodes, list):
320
356
  prev_nodes = set(prev_nodes)
321
-
357
+
322
358
  iterator = iter(prev_nodes)
323
359
  prev_node = next(iterator)
324
360
  path = prev_node if len(prev_nodes) == 1 else get_bridge_path(prev_nodes, activity)
325
-
361
+
326
362
  activity = activity or prev_node.activity
327
363
  calc_node = TriccNodeWait(
328
- id = generate_id(f"ar{''.join([x.id for x in nodes_to_wait])}{activity.id}"),
329
- reference = nodes_to_wait,
330
- activity = activity,
331
- group = activity,
332
- path = path
333
- )
364
+ id=generate_id(f"ar{''.join([x.id for x in nodes_to_wait])}{activity.id}"),
365
+ reference=nodes_to_wait,
366
+ activity=activity,
367
+ group=activity,
368
+ path=path,
369
+ )
334
370
 
335
- #start the wait and the next_nodes from the prev_nodes
336
- #add the wait as dependency of the next_nodes
371
+ # start the wait and the next_nodes from the prev_nodes
372
+ # add the wait as dependency of the next_nodes
337
373
 
338
- # add edge between rhombus and node
374
+ # add edge between rhombus and node
339
375
 
340
- set_prev_next_node(path,calc_node, edge_only=edge_only, activity=activity )
376
+ set_prev_next_node(path, calc_node, edge_only=edge_only, activity=activity)
341
377
  for next_node in next_nodes:
342
- #if prev != replaced_node and next_node != replaced_node :
343
- # set_prev_next_node(prev,next_node,replaced_node)
344
- #if first:
345
- #first = False
346
- set_prev_next_node(calc_node,next_node, edge_only=edge_only,activity=activity)
347
-
348
-
378
+ # if prev != replaced_node and next_node != replaced_node :
379
+ # set_prev_next_node(prev,next_node,replaced_node)
380
+ # if first:
381
+ # first = False
382
+ set_prev_next_node(calc_node, next_node, edge_only=edge_only, activity=activity)
383
+
349
384
  return calc_node
350
-
351
- def get_bridge_path(prev_nodes, node=None,edge_only=False):
385
+
386
+
387
+ def get_bridge_path(prev_nodes, node=None, edge_only=False):
352
388
  iterator = iter(prev_nodes)
353
- p_p_node = next(iterator)
389
+ p_p_node = next(iterator)
354
390
  if node is None:
355
391
  node = p_p_node
356
- calc_id = generate_id(f"br{''.join([x.id for x in prev_nodes])}{node.id}")
357
- calc_name = "path_"+calc_id
392
+ calc_id = generate_id(f"br{''.join([x.id for x in prev_nodes])}{node.id}")
393
+ calc_name = "path_" + calc_id
358
394
  data = {
359
- 'id': calc_id,
360
- 'group': node.group,
361
- 'activity': node.activity,
362
- 'label': "path: " + ( node.get_name()),
363
- 'name': calc_name,
364
- 'path_len': node.path_len + 1 * (node == p_p_node)
395
+ "id": calc_id,
396
+ "group": node.group,
397
+ "activity": node.activity,
398
+ "label": "path: " + (node.get_name()),
399
+ "name": calc_name,
400
+ "path_len": node.path_len + 1 * (node == p_p_node),
365
401
  }
366
-
367
- if len(prev_nodes)>1 and sum([0 if issubclass(n.__class__, (TriccNodeDisplayCalculateBase, TriccNodeRhombus)) else 1 for n in prev_nodes])>0 :
368
- calc= TriccNodeDisplayBridge( **data)
402
+
403
+ if (
404
+ len(prev_nodes) > 1
405
+ and sum(
406
+ [0 if issubclass(n.__class__, (TriccNodeDisplayCalculateBase, TriccNodeRhombus)) else 1 for n in prev_nodes]
407
+ )
408
+ > 0
409
+ ):
410
+ calc = TriccNodeDisplayBridge(**data)
369
411
  else:
370
- calc = TriccNodeBridge( **data)
412
+ calc = TriccNodeBridge(**data)
371
413
  return calc
372
-
414
+
415
+
373
416
  def inject_bridge_path(node, nodes):
374
417
 
375
- prev_nodes = [nodes[n.source] for n in list(filter(lambda x: (x.target == node.id or x.target == node) and x.source in list(nodes.keys()), node.activity.edges))]
418
+ prev_nodes = [
419
+ nodes[n.source]
420
+ for n in list(
421
+ filter(
422
+ lambda x: (x.target == node.id or x.target == node) and x.source in list(nodes.keys()),
423
+ node.activity.edges,
424
+ )
425
+ )
426
+ ]
376
427
  if prev_nodes:
377
- calc = get_bridge_path(prev_nodes, node,edge_only=True)
428
+ calc = get_bridge_path(prev_nodes, node, edge_only=True)
378
429
 
379
430
  for e in node.activity.edges:
380
431
  if e.target == node.id:
381
432
  # if e.source in node.activity.nodes and len(node.activity.nodes[e.source].next_nodes):
382
433
  # set_prev_next_node(node.activity[e.source], node, edge_only=True, replaced_node=node)
383
434
  # else:
384
- e.target = calc.id
385
-
435
+ e.target = calc.id
436
+
386
437
  # add edge between bridge and node
387
- set_prev_next_node(calc,node,edge_only=True, activity=node.activity)
438
+ set_prev_next_node(calc, node, edge_only=True, activity=node.activity)
388
439
  node.path_len += 1
389
440
  return calc
390
441
 
@@ -394,45 +445,50 @@ def inject_node_before(before, node, activity):
394
445
  before.activity = activity
395
446
  activity.nodes[before.id] = before
396
447
  nodes = activity.nodes
397
- prev_nodes = node.prev_nodes.union(set(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))))
448
+ prev_nodes = node.prev_nodes.union(
449
+ set(
450
+ nodes[n.source]
451
+ for n in list(
452
+ filter(lambda x: (x.target == node.id or x.target == node) and x.source in nodes, node.activity.edges)
453
+ )
454
+ )
455
+ )
398
456
  edge_processed = False
399
457
  before.path_len = node.path_len
400
458
  for e in node.activity.edges:
401
459
  if e.target == node.id:
402
460
  e.target = before.id
403
- for p in prev_nodes:
404
- prev_processed = len(node.next_nodes) > 0
461
+ for p in prev_nodes:
405
462
  if node in p.next_nodes:
406
463
  p.next_nodes.remove(node)
407
464
  p.next_nodes.append(before)
408
465
 
409
466
  # add edge between bridge and node
410
- set_prev_next_node(before,node,edge_only=not edge_processed, activity=node.activity)
467
+ set_prev_next_node(before, node, edge_only=not edge_processed, activity=node.activity)
411
468
  node.path_len += 1
412
469
 
413
-
414
-
415
- def generate_calculates(node,calculates, used_calculates,processed_nodes, process):
470
+
471
+ def generate_calculates(node, calculates, used_calculates, processed_nodes, process):
416
472
  list_calc = []
417
473
  count_node = None
418
- ## add select calcualte
474
+ # add select calcualte
419
475
  if issubclass(node.__class__, TriccNodeCalculateBase):
420
476
  if isinstance(node, TriccNodeRhombus):
421
477
  if (
422
478
  (node.expression_reference is None or isinstance(node.expression_reference, TriccOperation))
423
479
  and isinstance(node.reference, list)
424
- and len(node.reference)==1
480
+ and len(node.reference) == 1
425
481
  and issubclass(node.reference[0].__class__, TriccNodeSelect)
426
482
  ):
427
483
 
428
484
  count_node = get_count_node(node)
429
485
  list_calc.append(count_node)
430
- set_prev_next_node(node.reference[0],count_node)
431
- node.path_len+=1
432
-
486
+ set_prev_next_node(node.reference[0], count_node)
487
+ node.path_len += 1
488
+
433
489
  if isinstance(node.expression_reference, TriccOperation):
434
490
  node.expression_reference.replace_node(node.reference, count_node)
435
- node.reference[0] = count_node
491
+ node.reference[0] = count_node
436
492
  # elif isinstance(node.reference, TriccOperation):
437
493
  # references = node.reference.get_references()
438
494
  # if len(references) == 1 and issubclass(node.reference[0].__class__, TriccNodeSelect):
@@ -445,68 +501,67 @@ def generate_calculates(node,calculates, used_calculates,processed_nodes, proces
445
501
  processed_nodes.add(count_node)
446
502
  add_calculate(calculates, count_node)
447
503
  add_used_calculate(
448
- node,
449
- count_node,
450
- calculates=calculates,
504
+ node,
505
+ count_node,
506
+ calculates=calculates,
451
507
  used_calculates=used_calculates,
452
- processed_nodes=processed_nodes
508
+ processed_nodes=processed_nodes,
453
509
  )
454
-
455
-
510
+
456
511
  # if a prev node is a calculate then it must be added in used_calc
457
512
  for prev in node.prev_nodes:
458
513
  add_used_calculate(
459
- node,
460
- prev,
461
- calculates=calculates,
462
- used_calculates=used_calculates,
463
- processed_nodes=processed_nodes
514
+ node, prev, calculates=calculates, used_calculates=used_calculates, processed_nodes=processed_nodes
464
515
  )
465
- #if the node have a save
466
- if hasattr(node, 'save') and node.save is not None and node.save != '':
516
+ # if the node have a save
517
+ if hasattr(node, "save") and node.save is not None and node.save != "":
467
518
  # get fragments type.name.icdcode
468
- calculate_name=node.save
519
+ calculate_name = node.save
469
520
  if node.name != calculate_name:
470
521
  calc_id = generate_id(f"autosave{node.id}")
471
522
  if issubclass(node.__class__, TriccNodeSelect) or isinstance(node, TriccNodeSelectNotAvailable):
472
- expression = get_count_terms_details( node, processed_nodes, True, False, process)
523
+ expression = get_count_terms_details(node, processed_nodes, True, False, process)
473
524
  else:
474
- expression = get_node_expression(node,processed_nodes,True,True)
525
+ expression = get_node_expression(node, processed_nodes, True, True)
475
526
  calc_node = TriccNodeCalculate(
476
527
  name=calculate_name,
477
- id = calc_id,
478
- group = node.group,
479
- #version=get_next_version(calculate_name, processed_nodes, node.version+2),
480
- activity = node.activity,
481
- label = "save: " +node.get_name(),
482
- path_len=node.path_len+ 1,
528
+ id=calc_id,
529
+ group=node.group,
530
+ # version=get_next_version(calculate_name, processed_nodes, node.version+2),
531
+ activity=node.activity,
532
+ label="save: " + node.get_name(),
533
+ path_len=node.path_len + 1,
483
534
  last=True,
484
- expression=expression
535
+ expression=expression,
485
536
  )
486
537
  node.activity.calculates.append(calc_node)
487
538
  last_version = set_last_version_false(calc_node, processed_nodes)
488
539
  if last_version:
489
540
  calc_node.expression = merge_expression(calc_node.expression, last_version)
490
541
  processed_nodes.add(calc_node)
491
- logger.debug("generate_save_calculate:{}:{} as {}".format(calc_node.tricc_type, node.name if hasattr(node,'name') else node.id, calculate_name))
492
-
542
+ logger.debug(
543
+ "generate_save_calculate:{}:{} as {}".format(
544
+ calc_node.tricc_type, node.name if hasattr(node, "name") else node.id, calculate_name
545
+ )
546
+ )
547
+
493
548
  list_calc.append(calc_node)
494
- #add_save_calculate(calc_node, calculates, used_calculates,processed_nodes)
549
+ # add_save_calculate(calc_node, calculates, used_calculates,processed_nodes)
495
550
  for calc in list_calc:
496
551
  node.activity.nodes[calc.id] = calc
497
552
  add_calculate(calculates, calc)
498
553
  return list_calc
499
554
 
500
555
 
501
-
502
556
  def add_calculate(calculates, calc_node):
503
557
  if issubclass(calc_node.__class__, TriccNodeDisplayCalculateBase):
504
558
  if calc_node.name not in calculates:
505
- calculates[calc_node.name]= {}
559
+ calculates[calc_node.name] = {}
506
560
  calculates[calc_node.name][calc_node.id] = calc_node
507
561
 
562
+
508
563
  def get_option_code_from_label(node, option_label):
509
- if hasattr(node, 'options'):
564
+ if hasattr(node, "options"):
510
565
  for i in node.options:
511
566
  if node.options[i].label.strip() == option_label.strip():
512
567
  return node.options[i].name
@@ -515,43 +570,95 @@ def get_option_code_from_label(node, option_label):
515
570
  logger.critical(f"node {node.get_name()} has no options")
516
571
 
517
572
 
518
- def process_reference(node, processed_nodes, calculates, used_calculates=None, replace_reference=False,warn=False, codesystems=None):
519
- if getattr(node, 'expression_reference', None):
573
+ # CQL is deined as a cql library and this code will
574
+ # parse the definition and will extract the logic under the define statement
575
+
576
+
577
+ def extract_with_regex(data):
578
+ text = data
579
+ # Pattern to match define statement and capture the name and body
580
+ pattern = r'define\s+"([^"]+)":\s*(.*)'
581
+ match = re.search(pattern, text, re.DOTALL)
582
+
583
+ if match:
584
+ definition_name = match.group(1)
585
+ definition_body = match.group(2).strip()
586
+ return {"name": definition_name, "body": definition_body, "full": match.group(0)}
587
+ return None
588
+
589
+
590
+ def process_reference(
591
+ node, processed_nodes, calculates, used_calculates=None, replace_reference=False, warn=False, codesystems=None
592
+ ):
593
+ # process a remote reference coded as a cql
594
+ if getattr(node, "remote_reference", None):
595
+ remote_reference_url = node.remote_reference
596
+ print(f"Fetching remote reference from {remote_reference_url}")
597
+ response = requests.get(remote_reference_url)
598
+ response_json = response.json()
599
+ cql_content = response_json["content"][0]["data"]
600
+ decode_cql_content = base64.b64decode(cql_content).decode("utf-8")
601
+ definition = extract_with_regex(decode_cql_content)
602
+
603
+ if definition:
604
+ cql_expression = definition["body"]
605
+
606
+ # We use `transform_cql_to_operation` to parse the raw CQL string.
607
+ operation = transform_cql_to_operation(cql_expression, context=f"remote reference for {node.get_name()}")
608
+
609
+ if not operation:
610
+ logger.error(f"Failed to parse remote CQL expression for node {node.get_name()}: {cql_expression}")
611
+ return False
612
+
613
+ # The parsed operation is assigned to `expression_reference`.
614
+ # The original code incorrectly assigned the raw string to `node.reference`
615
+ # and had an unreachable `if isinstance(cql_expression, list):` block.
616
+ node.expression_reference = operation
617
+ node.remote_reference = None
618
+
619
+ # By setting `expression_reference` and clearing `remote_reference`,
620
+ # we can now re-process this node. A recursive call to `process_reference`
621
+ # will now enter the `elif getattr(node, 'expression_reference', None):`
622
+ # block, which will correctly handle the newly parsed expression.
623
+ return process_reference(
624
+ node, processed_nodes, calculates, used_calculates, replace_reference, warn, codesystems
625
+ )
626
+
627
+ elif getattr(node, "expression_reference", None):
520
628
  modified_expression = process_operation_reference(
521
- node.expression_reference,
522
- node,
629
+ node.expression_reference,
630
+ node,
523
631
  processed_nodes=processed_nodes,
524
- calculates=calculates,
525
- used_calculates=used_calculates,
632
+ calculates=calculates,
633
+ used_calculates=used_calculates,
526
634
  replace_reference=replace_reference,
527
- warn=warn,
528
- codesystems=codesystems
635
+ warn=warn,
636
+ codesystems=codesystems,
529
637
  )
530
638
  if modified_expression is False:
531
639
  return False
532
640
  elif modified_expression and replace_reference:
533
641
  node.reference = list(modified_expression.get_references())
534
642
  node.expression_reference = modified_expression
535
- elif getattr(node, 'reference', None):
643
+
644
+ elif getattr(node, "reference", None):
536
645
  reference = node.reference
537
646
  if isinstance(reference, list):
538
647
  if isinstance(node, TriccNodeWait):
539
- reference = [TriccOperation(TriccOperator.ISTRUE,[n]) for n in reference]
540
- if len(node.reference) == 1 :
648
+ reference = [TriccOperation(TriccOperator.ISTRUE, [n]) for n in reference]
649
+ if len(node.reference) == 1:
541
650
  operation = reference[0]
542
651
  else:
543
- operation = and_join(
544
- reference
545
- )
652
+ operation = and_join(reference)
546
653
  modified_expression = process_operation_reference(
547
- operation,
654
+ operation,
548
655
  node,
549
656
  processed_nodes=processed_nodes,
550
- calculates=calculates,
551
- used_calculates=used_calculates,
657
+ calculates=calculates,
658
+ used_calculates=used_calculates,
552
659
  replace_reference=replace_reference,
553
- warn=warn,
554
- codesystems=codesystems
660
+ warn=warn,
661
+ codesystems=codesystems,
555
662
  )
556
663
  if modified_expression is False:
557
664
  return False
@@ -561,14 +668,14 @@ def process_reference(node, processed_nodes, calculates, used_calculates=None,
561
668
  node.expression_reference = modified_expression
562
669
  elif isinstance(node.reference, (TriccOperation, TriccReference)):
563
670
  modified_expression = process_operation_reference(
564
- node.reference,
565
- node,
671
+ node.reference,
672
+ node,
566
673
  processed_nodes=processed_nodes,
567
- calculates=calculates,
568
- used_calculates=used_calculates,
674
+ calculates=calculates,
675
+ used_calculates=used_calculates,
569
676
  replace_reference=replace_reference,
570
- warn=warn,
571
- codesystems=codesystems
677
+ warn=warn,
678
+ codesystems=codesystems,
572
679
  )
573
680
  if modified_expression is False:
574
681
  return False
@@ -576,95 +683,95 @@ def process_reference(node, processed_nodes, calculates, used_calculates=None,
576
683
  node.reference = list(modified_expression.get_references())
577
684
  node.expression_reference = modified_expression
578
685
 
579
- if isinstance(getattr(node, 'relevance', None), (TriccOperation, TriccReference)):
686
+ if isinstance(getattr(node, "relevance", None), (TriccOperation, TriccReference)):
580
687
  modified_expression = process_operation_reference(
581
- node.relevance,
582
- node,
688
+ node.relevance,
689
+ node,
583
690
  processed_nodes=processed_nodes,
584
- calculates=calculates,
585
- used_calculates=used_calculates,
691
+ calculates=calculates,
692
+ used_calculates=used_calculates,
586
693
  replace_reference=replace_reference,
587
- warn=warn,
588
- codesystems=codesystems
694
+ warn=warn,
695
+ codesystems=codesystems,
589
696
  )
590
697
  if modified_expression is False:
591
698
  return False
592
699
  elif modified_expression and replace_reference:
593
700
  node.relevance = modified_expression
594
-
595
- if isinstance(getattr(node, 'trigger', None), (TriccOperation, TriccReference)):
701
+
702
+ if isinstance(getattr(node, "trigger", None), (TriccOperation, TriccReference)):
596
703
  modified_expression = process_operation_reference(
597
- node.trigger,
598
- node,
704
+ node.trigger,
705
+ node,
599
706
  processed_nodes=processed_nodes,
600
- calculates=calculates,
601
- used_calculates=used_calculates,
707
+ calculates=calculates,
708
+ used_calculates=used_calculates,
602
709
  replace_reference=replace_reference,
603
- warn=warn,
604
- codesystems=codesystems
710
+ warn=warn,
711
+ codesystems=codesystems,
605
712
  )
606
713
  if modified_expression is False:
607
714
  return False
608
715
  elif modified_expression and replace_reference:
609
716
  node.trigger = modified_expression
610
- if isinstance(getattr(node, 'constraint', None), (TriccOperation, TriccReference)):
717
+ if isinstance(getattr(node, "constraint", None), (TriccOperation, TriccReference)):
611
718
  modified_expression = process_operation_reference(
612
- node.constraint,
613
- node,
719
+ node.constraint,
720
+ node,
614
721
  processed_nodes=processed_nodes,
615
- calculates=calculates,
616
- used_calculates=used_calculates,
722
+ calculates=calculates,
723
+ used_calculates=used_calculates,
617
724
  replace_reference=replace_reference,
618
- warn=warn,
619
- codesystems=codesystems
725
+ warn=warn,
726
+ codesystems=codesystems,
620
727
  )
621
728
  if modified_expression is False:
622
729
  return False
623
730
  elif modified_expression and replace_reference:
624
731
  node.constraint = modified_expression
625
-
626
- if isinstance(getattr(node, 'default', None), (TriccOperation, TriccReference)):
732
+
733
+ if isinstance(getattr(node, "default", None), (TriccOperation, TriccReference)):
627
734
  modified_expression = process_operation_reference(
628
- node.default,
629
- node,
735
+ node.default,
736
+ node,
630
737
  processed_nodes=processed_nodes,
631
- calculates=calculates,
632
- used_calculates=used_calculates,
738
+ calculates=calculates,
739
+ used_calculates=used_calculates,
633
740
  replace_reference=replace_reference,
634
- warn=warn,
635
- codesystems=codesystems
636
- )
741
+ warn=warn,
742
+ codesystems=codesystems,
743
+ )
637
744
  if modified_expression is False:
638
745
  return False
639
746
  elif modified_expression and replace_reference:
640
747
  node.relevance = modified_expression
641
-
642
- if isinstance(getattr(node, 'expression', None), (TriccOperation, TriccReference)):
748
+
749
+ if isinstance(getattr(node, "expression", None), (TriccOperation, TriccReference)):
643
750
  modified_expression = process_operation_reference(
644
- node.expression,
645
- node,
751
+ node.expression,
752
+ node,
646
753
  processed_nodes=processed_nodes,
647
- calculates=calculates,
648
- used_calculates=used_calculates,
754
+ calculates=calculates,
755
+ used_calculates=used_calculates,
649
756
  replace_reference=replace_reference,
650
- warn=warn,
651
- codesystems=codesystems
757
+ warn=warn,
758
+ codesystems=codesystems,
652
759
  )
653
760
  if modified_expression is False:
654
761
  return False
655
762
  elif modified_expression and replace_reference:
656
763
  node.expression = modified_expression
657
-
658
- if isinstance(getattr(node, 'applicability', None), (TriccOperation, TriccReference)):
764
+
765
+ if isinstance(getattr(node, "applicability", None), (TriccOperation, TriccReference)):
659
766
  modified_expression = process_operation_reference(
660
- node.applicability,
661
- node,
767
+ node.applicability,
768
+ node,
662
769
  processed_nodes=processed_nodes,
663
- calculates=calculates,
664
- used_calculates=used_calculates,
770
+ calculates=calculates,
771
+ used_calculates=used_calculates,
665
772
  replace_reference=replace_reference,
666
- warn=warn,
667
- codesystems=codesystems
773
+ warn=warn,
774
+ codesystems=codesystems,
668
775
  )
669
776
  if modified_expression is False:
670
777
  return False
@@ -672,7 +779,17 @@ def process_reference(node, processed_nodes, calculates, used_calculates=None,
672
779
  node.applicability = modified_expression
673
780
  return True
674
781
 
675
- def process_operation_reference(operation, node, processed_nodes, calculates, used_calculates=None, replace_reference=False,warn=False, codesystems=None):
782
+
783
+ def process_operation_reference(
784
+ operation,
785
+ node,
786
+ processed_nodes,
787
+ calculates,
788
+ used_calculates=None,
789
+ replace_reference=False,
790
+ warn=False,
791
+ codesystems=None,
792
+ ):
676
793
  modified_operation = None
677
794
  node_reference = []
678
795
  reference = []
@@ -680,13 +797,13 @@ def process_operation_reference(operation, node, processed_nodes, calculates, us
680
797
  ref_list = [r.value for r in operation.get_references() if isinstance(r, TriccReference)]
681
798
  real_ref_list = [r for r in operation.get_references() if issubclass(r.__class__, TriccNodeBaseModel)]
682
799
  for ref in ref_list:
683
- if ref.endswith(']'):
684
- terms = ref[:-1].split('[')
800
+ if ref.endswith("]"):
801
+ terms = ref[:-1].split("[")
685
802
  option_label = terms[1]
686
803
  ref = terms[0]
687
804
  else:
688
805
  option_label = None
689
- node_in_act = [n for n in node.activity.nodes.values() if n.name == ref and n != node]
806
+ node_in_act = [n for n in node.activity.nodes.values() if n.name == ref and n != node]
690
807
  if node_in_act:
691
808
  if any(n not in processed_nodes for n in node_in_act):
692
809
  return False
@@ -694,16 +811,16 @@ def process_operation_reference(operation, node, processed_nodes, calculates, us
694
811
  last_found = node_in_act[0]
695
812
  else:
696
813
  last_found = get_last_version(name=ref, processed_nodes=processed_nodes)
697
- if last_found is None:
814
+ if last_found is None:
698
815
  if codesystems:
699
- concept = lookup_codesystems_code(codesystems, ref)
816
+ concept = lookup_codesystems_code(codesystems, ref)
700
817
  if not concept:
701
818
  logger.critical(f"reference {ref} not found in the project for{str(node)} ")
702
819
  exit(1)
703
820
  else:
704
821
  if warn:
705
822
  logger.debug(f"reference {ref}::{concept.display} not yet processed {node.get_name()}")
706
-
823
+
707
824
  elif warn:
708
825
  logger.debug(f"reference {ref} not found for a calculate {node.get_name()}")
709
826
  return False
@@ -711,7 +828,9 @@ def process_operation_reference(operation, node, processed_nodes, calculates, us
711
828
  node_reference.append(last_found)
712
829
  reference.append(TriccReference(ref))
713
830
  if replace_reference:
714
- if not issubclass(last_found.__class__, (TriccNodeDisplayModel, TriccNodeDisplayCalculateBase, TriccNodeInput)):
831
+ if not issubclass(
832
+ last_found.__class__, (TriccNodeDisplayModel, TriccNodeDisplayCalculateBase, TriccNodeInput)
833
+ ):
715
834
  last_found = get_node_expression(last_found, processed_nodes, is_prev=True)
716
835
  if isinstance(operation, (TriccOperation)):
717
836
  if modified_operation is None:
@@ -723,118 +842,141 @@ def process_operation_reference(operation, node, processed_nodes, calculates, us
723
842
  # Resolve human-readable label
724
843
  option_code = get_option_code_from_label(last_found, option_label)
725
844
  if option_code:
726
- modified_operation = replace_code_reference(operation, old=f"{ref}[{option_label}]", new=option_code )
845
+ modified_operation = replace_code_reference(
846
+ operation, old=f"{ref}[{option_label}]", new=option_code
847
+ )
727
848
  else:
728
849
  if warn:
729
850
  logger.warning(f"Could not resolve label '{option_label}' for reference {ref}")
730
851
  return False
731
- if hasattr(last_found, 'path_len'):
732
- path_len = last_found.path_len
852
+ if hasattr(last_found, "path_len"):
853
+ path_len = last_found.path_len
733
854
  elif isinstance(last_found, TriccOperation):
734
- path_len = max(getattr(n, 'path_len', 0) for n in last_found.get_references())
855
+ path_len = max(getattr(n, "path_len", 0) for n in last_found.get_references())
735
856
  else:
736
857
  path_len = 0
737
858
  node.path_len = max(node.path_len, path_len)
738
859
  for ref in real_ref_list:
739
860
  if is_prev_processed(ref, node, processed_nodes=processed_nodes, local=False) is False:
740
861
  return False
741
-
862
+
742
863
  if used_calculates is not None:
743
864
  for ref_nodes in node_reference:
744
865
  if issubclass(ref_nodes.__class__, TriccNodeCalculateBase):
745
866
  add_used_calculate(node, ref_nodes, calculates, used_calculates, processed_nodes=processed_nodes)
746
867
  return modified_operation
747
868
 
869
+
748
870
  def replace_code_reference(expression, old, new):
749
871
  if isinstance(expression, str):
750
- return expression_reference.replace(old, f"'{new}'")
872
+ return expression.replace(old, f"'{new}'")
751
873
  if isinstance(expression, TriccOperation):
752
874
  expression.replace_node(TriccReference(old), TriccStatic(new))
753
875
  return expression
754
- #add_used_calculate(node, calc_node, calculates, used_calculates, processed_nodes)
876
+
877
+
878
+ # add_used_calculate(node, calc_node, calculates, used_calculates, processed_nodes)
879
+
755
880
 
756
881
  def add_used_calculate(node, prev_node, calculates, used_calculates, processed_nodes):
757
882
  if issubclass(prev_node.__class__, TriccNodeDisplayCalculateBase):
758
883
  if prev_node in processed_nodes:
759
884
  # if not a verison, index will equal -1
760
- if prev_node.name not in calculates :
885
+ if prev_node.name not in calculates:
761
886
  logger.debug("node {} refered before being processed".format(node.get_name()))
762
887
  return False
763
- max_version = prev_node#get_max_version(calculates[node_clean_name])
888
+ max_version = prev_node # get_max_version(calculates[node_clean_name])
764
889
  if prev_node.name not in used_calculates:
765
890
  used_calculates[prev_node.name] = {}
766
- #save the max version only once
891
+ # save the max version only once
767
892
  if max_version.id not in used_calculates[prev_node.name]:
768
893
  used_calculates[prev_node.name][max_version.id] = max_version
769
894
  else:
770
- logger.debug("process_calculate_version_requirement: failed for {0} , prev Node {1} ".format(node.get_name(), prev_node.get_name()))
771
-
772
-
773
- def get_select_not_available_options(node,group,label):
774
- return {0:TriccNodeSelectOption(
775
- id = generate_id(f"notavaialble{node.id}"),
776
- name="1",
777
- label=label,
778
- select = node,
779
- group = group,
780
- list_name = node.list_name
781
- )}
782
-
895
+ logger.debug(
896
+ "load_calculate_version_requirement: failed for {0} , prev Node {1} ".format(
897
+ node.get_name(), prev_node.get_name()
898
+ )
899
+ )
900
+
901
+
902
+ def get_select_not_available_options(node, group, label):
903
+ return {
904
+ 0: TriccNodeSelectOption(
905
+ id=generate_id(f"notavaialble{node.id}"),
906
+ name="1",
907
+ label=label,
908
+ select=node,
909
+ group=group,
910
+ list_name=node.list_name,
911
+ )
912
+ }
913
+
914
+
783
915
  def get_select_yes_no_options(node, group):
784
916
  yes = TriccNodeSelectOption(
785
- id = generate_id(f'yes{node.id}'),
786
- name=f"{TRICC_TRUE_VALUE}",
787
- label="Yes",
788
- select = node,
789
- group = group,
790
- list_name = node.list_name
791
- )
917
+ id=generate_id(f"yes{node.id}"),
918
+ name=f"{TRICC_TRUE_VALUE}",
919
+ label="Yes",
920
+ select=node,
921
+ group=group,
922
+ list_name=node.list_name,
923
+ )
792
924
  no = TriccNodeSelectOption(
793
- id = generate_id(f'no{node.id}'),
794
- name=f"{TRICC_FALSE_VALUE}",
795
- label="No",
796
- select = node,
797
- group = group,
798
- list_name = node.list_name
799
- )
800
- return {0:yes, 1:no }
925
+ id=generate_id(f"no{node.id}"),
926
+ name=f"{TRICC_FALSE_VALUE}",
927
+ label="No",
928
+ select=node,
929
+ group=group,
930
+ list_name=node.list_name,
931
+ )
932
+ return {0: yes, 1: no}
933
+
801
934
 
802
- # walkthough all node in an iterative way, the same node might be parsed 2 times
935
+ # walkthough all node in an iterative way, the same node might be parsed 2 times
803
936
  # therefore to avoid double processing the nodes variable saves the node already processed
804
937
  # there 2 strategies : process it the first time or the last time (wait that all the previuous node are processed)
805
938
 
806
- def walktrhough_tricc_node_processed_stached(node, callback, processed_nodes, stashed_nodes, path_len, recursive=False, warn = False,
807
- node_path = [], process=None, **kwargs):
939
+
940
+ def walktrhough_tricc_node_processed_stached(
941
+ node,
942
+ callback,
943
+ processed_nodes,
944
+ stashed_nodes,
945
+ path_len,
946
+ recursive=False,
947
+ warn=False,
948
+ node_path=[],
949
+ process=None,
950
+ **kwargs,
951
+ ):
808
952
  ended_activity = False
809
953
  # logger.debug("walkthrough::{}::{}".format(callback.__name__, node.get_name()))
810
-
811
- path_len = max(node.activity.path_len, *[0,*[getattr(n,'path_len',0) + 1 for n in node.activity.prev_nodes]]) + 1
812
- if hasattr(node, 'prev_nodes'):
813
- path_len = max(path_len, *[0,*[getattr(n,'path_len',0)+ 1 for n in node.prev_nodes]])
814
- if hasattr(node, 'get_references'):
954
+
955
+ path_len = max(node.activity.path_len, *[0, *[getattr(n, "path_len", 0) + 1 for n in node.activity.prev_nodes]]) + 1
956
+ if hasattr(node, "prev_nodes"):
957
+ path_len = max(path_len, *[0, *[getattr(n, "path_len", 0) + 1 for n in node.prev_nodes]])
958
+ if hasattr(node, "get_references"):
815
959
  references = node.get_references()
816
960
  if references:
817
- path_len = max(path_len, *[0,*[getattr(n,'path_len',0) + 1 for n in references]])
961
+ path_len = max(path_len, *[0, *[getattr(n, "path_len", 0) + 1 for n in references]])
818
962
  node.path_len = max(node.path_len, path_len)
819
963
  prev_process = process[0] if process else None
820
- if isinstance(node, TriccNodeActivity) and getattr(node.root, 'process', None):
964
+ if isinstance(node, TriccNodeActivity) and getattr(node.root, "process", None):
821
965
  if process is None:
822
966
  process = [node.root.process]
823
967
  else:
824
968
  process[0] = node.root.process
825
- if (
826
- callback(
827
- node,
828
- processed_nodes=processed_nodes,
829
- stashed_nodes=stashed_nodes,
830
- warn = warn,
831
- node_path=node_path,
832
- process=process,
833
- **kwargs
834
- )
969
+ if callback(
970
+ node,
971
+ processed_nodes=processed_nodes,
972
+ stashed_nodes=stashed_nodes,
973
+ warn=warn,
974
+ node_path=node_path,
975
+ process=process,
976
+ **kwargs,
835
977
  ):
836
978
  node_path.append(node)
837
- # node processing succeed
979
+ # node processing succeed
838
980
  if not isinstance(node, TriccNodeActivity) and node not in processed_nodes:
839
981
  processed_nodes.add(node)
840
982
  if warn:
@@ -845,7 +987,11 @@ def walktrhough_tricc_node_processed_stached(node, callback, processed_nodes, st
845
987
  processed_nodes.add(node.activity)
846
988
  ended_activity = True
847
989
  if warn:
848
- logger.debug("{}::{}: processed ({})".format(callback.__name__, node.activity.get_name(), len(processed_nodes)))
990
+ logger.debug(
991
+ "{}::{}: processed ({})".format(
992
+ callback.__name__, node.activity.get_name(), len(processed_nodes)
993
+ )
994
+ )
849
995
  elif node in stashed_nodes:
850
996
  stashed_nodes.remove(node)
851
997
  # logger.debug("{}::{}: unstashed ({})".format(callback.__name__, node.get_name(), len(stashed_nodes)))
@@ -856,90 +1002,118 @@ def walktrhough_tricc_node_processed_stached(node, callback, processed_nodes, st
856
1002
  if recursive:
857
1003
  for gp in node.activity.groups.values():
858
1004
  walktrhough_tricc_node_processed_stached(
859
- gp,
1005
+ gp,
860
1006
  callback,
861
- processed_nodes=processed_nodes,
862
- stashed_nodes=stashed_nodes,
1007
+ processed_nodes=processed_nodes,
1008
+ stashed_nodes=stashed_nodes,
863
1009
  path_len=path_len,
864
1010
  recursive=recursive,
865
- warn = warn,
866
- node_path = node_path.copy(),
867
- **kwargs
1011
+ warn=warn,
1012
+ node_path=node_path.copy(),
1013
+ **kwargs,
868
1014
  )
869
1015
  for c in node.activity.calculates:
870
- if len(c.prev_nodes)== 0:
1016
+ if len(c.prev_nodes) == 0:
871
1017
  walktrhough_tricc_node_processed_stached(
872
1018
  c,
873
1019
  callback,
874
- processed_nodes=processed_nodes,
875
- stashed_nodes=stashed_nodes,
1020
+ processed_nodes=processed_nodes,
1021
+ stashed_nodes=stashed_nodes,
876
1022
  path_len=path_len,
877
1023
  recursive=recursive,
878
- warn = warn,
879
- node_path = node_path.copy(),
880
- **kwargs
881
- )
1024
+ warn=warn,
1025
+ node_path=node_path.copy(),
1026
+ **kwargs,
1027
+ )
882
1028
  else:
883
- stashed_nodes += [c for c in node.activity.calculates if len(c.prev_nodes)== 0]
1029
+ stashed_nodes += [c for c in node.activity.calculates if len(c.prev_nodes) == 0]
884
1030
  stashed_nodes += node.activity.groups.values()
885
1031
  elif issubclass(node.__class__, TriccNodeSelect):
886
1032
  for option in node.options.values():
887
- option.path_len = max(path_len, option.path_len)
888
- callback(option, processed_nodes=processed_nodes, stashed_nodes=stashed_nodes, warn = warn, node_path=node_path,**kwargs)
1033
+ option.path_len = max(path_len, option.path_len)
1034
+ callback(
1035
+ option,
1036
+ processed_nodes=processed_nodes,
1037
+ stashed_nodes=stashed_nodes,
1038
+ warn=warn,
1039
+ node_path=node_path,
1040
+ **kwargs,
1041
+ )
889
1042
  if option not in processed_nodes:
890
1043
  processed_nodes.add(option)
891
1044
  if warn:
892
1045
  logger.debug(
893
- "{}::{}: processed ({})".format(callback.__name__, option.get_name(), len(processed_nodes)))
894
- walkthrough_tricc_option(node, callback, processed_nodes, stashed_nodes, path_len + 1, recursive,
895
- warn = warn,node_path = node_path, **kwargs)
1046
+ "{}::{}: processed ({})".format(callback.__name__, option.get_name(), len(processed_nodes))
1047
+ )
1048
+ walkthrough_tricc_option(
1049
+ node,
1050
+ callback,
1051
+ processed_nodes,
1052
+ stashed_nodes,
1053
+ path_len + 1,
1054
+ recursive,
1055
+ warn=warn,
1056
+ node_path=node_path,
1057
+ **kwargs,
1058
+ )
896
1059
  if isinstance(node, TriccNodeActivity):
897
1060
  if node.root not in processed_nodes:
898
1061
  if node.root is not None:
899
- node.root.path_len = max(path_len, node.root.path_len)
1062
+ node.root.path_len = max(path_len, node.root.path_len)
900
1063
  if recursive:
901
- walktrhough_tricc_node_processed_stached(node.root, callback, processed_nodes, stashed_nodes, path_len,
902
- recursive, warn = warn,node_path = node_path.copy(),**kwargs)
903
- # for gp in node.groups:
904
- # walktrhough_tricc_node_processed_stached(gp, callback, processed_nodes, stashed_nodes, path_len,
905
- # recursive, warn = warn,**kwargs)
906
- # if node.calculates:
907
- # for c in node.calculates:
908
- # walktrhough_tricc_node_processed_stached(c, callback, processed_nodes, stashed_nodes, path_len,
909
- # recursive, warn = warn,**kwargs)
1064
+ walktrhough_tricc_node_processed_stached(
1065
+ node.root,
1066
+ callback,
1067
+ processed_nodes,
1068
+ stashed_nodes,
1069
+ path_len,
1070
+ recursive,
1071
+ warn=warn,
1072
+ node_path=node_path.copy(),
1073
+ **kwargs,
1074
+ )
910
1075
  elif node.root not in stashed_nodes:
911
- #stashed_nodes.insert(0,node.root)
912
1076
  stashed_nodes.insert_at_top(node.root)
913
- # if node.calculates:
914
- # stashed_nodes += node.calculates
915
- # for gp in node.groups:
916
- # stashed_nodes.add(gp)
917
- # # stashed_nodes.insert(0,gp)
918
1077
  return
919
1078
  elif ended_activity:
920
1079
  for next_node in node.next_nodes:
921
1080
  if next_node not in stashed_nodes:
922
- #stashed_nodes.insert(0,next_node)
1081
+ # stashed_nodes.insert(0,next_node)
923
1082
  if recursive:
924
- walktrhough_tricc_node_processed_stached(next_node, callback, processed_nodes, stashed_nodes, path_len,
925
- recursive, warn = warn,node_path = node_path.copy(),**kwargs)
1083
+ walktrhough_tricc_node_processed_stached(
1084
+ next_node,
1085
+ callback,
1086
+ processed_nodes,
1087
+ stashed_nodes,
1088
+ path_len,
1089
+ recursive,
1090
+ warn=warn,
1091
+ node_path=node_path.copy(),
1092
+ **kwargs,
1093
+ )
926
1094
  else:
927
1095
  stashed_nodes.insert_at_top(next_node)
928
-
929
-
930
- elif hasattr(node, 'next_nodes') and len(node.next_nodes) > 0 and not isinstance(node, TriccNodeActivity):
1096
+
1097
+ elif hasattr(node, "next_nodes") and len(node.next_nodes) > 0 and not isinstance(node, TriccNodeActivity):
931
1098
  if recursive:
932
- walkthrough_tricc_next_nodes(node, callback, processed_nodes, stashed_nodes, path_len + 1, recursive,
933
- warn = warn,node_path = node_path,**kwargs)
1099
+ walkthrough_tricc_next_nodes(
1100
+ node,
1101
+ callback,
1102
+ processed_nodes,
1103
+ stashed_nodes,
1104
+ path_len + 1,
1105
+ recursive,
1106
+ warn=warn,
1107
+ node_path=node_path,
1108
+ **kwargs,
1109
+ )
934
1110
  else:
935
1111
  for nn in node.next_nodes:
936
1112
  if nn not in stashed_nodes:
937
1113
  stashed_nodes.insert_at_top(nn)
938
1114
  if not recursive:
939
1115
  reorder_node_list(stashed_nodes, node.group, processed_nodes)
940
-
941
-
942
-
1116
+
943
1117
  else:
944
1118
  if prev_process and process and prev_process != process[0]:
945
1119
  process[0] = prev_process
@@ -950,8 +1124,10 @@ def walktrhough_tricc_node_processed_stached(node, callback, processed_nodes, st
950
1124
  logger.debug("{}::{}: stashed({})".format(callback.__name__, node.get_name(), len(stashed_nodes)))
951
1125
 
952
1126
 
953
- def walkthrough_tricc_next_nodes(node, callback, processed_nodes, stashed_nodes, path_len, recursive, warn = False, node_path = [], **kwargs):
954
-
1127
+ def walkthrough_tricc_next_nodes(
1128
+ node, callback, processed_nodes, stashed_nodes, path_len, recursive, warn=False, node_path=[], **kwargs
1129
+ ):
1130
+
955
1131
  if not recursive:
956
1132
  for next_node in node.next_nodes:
957
1133
  if next_node not in stashed_nodes:
@@ -961,73 +1137,100 @@ def walkthrough_tricc_next_nodes(node, callback, processed_nodes, stashed_nodes,
961
1137
  for next_node in list_next:
962
1138
  if not isinstance(node, (TriccNodeActivityEnd, TriccNodeEnd)):
963
1139
  if next_node not in processed_nodes:
964
- walktrhough_tricc_node_processed_stached(next_node, callback, processed_nodes, stashed_nodes,
965
- path_len + 1,recursive, warn = warn,node_path = node_path.copy(), **kwargs)
1140
+ walktrhough_tricc_node_processed_stached(
1141
+ next_node,
1142
+ callback,
1143
+ processed_nodes,
1144
+ stashed_nodes,
1145
+ path_len + 1,
1146
+ recursive,
1147
+ warn=warn,
1148
+ node_path=node_path.copy(),
1149
+ **kwargs,
1150
+ )
966
1151
  else:
967
1152
  logger.critical(
968
- "{}::end node of {} has a next node".format(callback.__name__, node.activity.get_name()))
1153
+ "{}::end node of {} has a next node".format(callback.__name__, node.activity.get_name())
1154
+ )
969
1155
  exit(1)
970
1156
 
971
1157
 
972
- def walkthrough_tricc_option(node, callback, processed_nodes, stashed_nodes, path_len, recursive, warn = False,node_path = [], **kwargs):
1158
+ def walkthrough_tricc_option(
1159
+ node, callback, processed_nodes, stashed_nodes, path_len, recursive, warn=False, node_path=[], **kwargs
1160
+ ):
973
1161
  if not recursive:
974
1162
  for option in node.options.values():
975
- if hasattr(option, 'next_nodes') and len(option.next_nodes) > 0:
1163
+ if hasattr(option, "next_nodes") and len(option.next_nodes) > 0:
976
1164
  for next_node in option.next_nodes:
977
1165
  if next_node not in stashed_nodes:
978
1166
  stashed_nodes.insert_at_top(next_node)
979
- #stashed_nodes.insert(0,next_node)
1167
+ # stashed_nodes.insert(0,next_node)
980
1168
  else:
981
1169
  list_option = []
982
1170
  while not all(elem in list_option for elem in list(node.options.values())):
983
1171
  for option in node.options.values():
984
1172
  if option not in list_option:
985
1173
  list_option.append(option)
986
- # then walk the options
987
- if hasattr(option, 'next_nodes') and len(option.next_nodes) > 0:
1174
+ # then walk the options
1175
+ if hasattr(option, "next_nodes") and len(option.next_nodes) > 0:
988
1176
  list_next = set(option.next_nodes)
989
1177
  for next_node in list_next:
990
1178
  if next_node not in processed_nodes:
991
- walktrhough_tricc_node_processed_stached(next_node, callback, processed_nodes,
992
- stashed_nodes, path_len + 1, recursive,
993
- warn = warn,
994
- node_path = node_path.copy(), **kwargs)
1179
+ walktrhough_tricc_node_processed_stached(
1180
+ next_node,
1181
+ callback,
1182
+ processed_nodes,
1183
+ stashed_nodes,
1184
+ path_len + 1,
1185
+ recursive,
1186
+ warn=warn,
1187
+ node_path=node_path.copy(),
1188
+ **kwargs,
1189
+ )
1190
+
995
1191
 
996
1192
  def get_next_version(name, processed_nodes, version=0, min=100):
997
- return max(version, min,*[(getattr(n,'version',None) or getattr(n,'instance',None) or 0) for n in get_versions(name, processed_nodes)])+1
1193
+ return (
1194
+ max(
1195
+ version,
1196
+ min,
1197
+ *[
1198
+ (getattr(n, "version", None) or getattr(n, "instance", None) or 0)
1199
+ for n in get_versions(name, processed_nodes)
1200
+ ],
1201
+ )
1202
+ + 1
1203
+ )
998
1204
 
999
1205
 
1000
1206
  def get_data_for_log(node):
1001
1207
  return "{}:{}|{} {}:{}".format(
1002
1208
  node.group.get_name() if node.group is not None else node.activity.get_name(),
1003
- node.group.instance if node.group is not None else node.activity.instance ,
1209
+ node.group.instance if node.group is not None else node.activity.instance,
1004
1210
  node.__class__,
1005
1211
  node.get_name(),
1006
- node.instance)
1212
+ node.instance,
1213
+ )
1214
+
1007
1215
 
1008
1216
  def stashed_node_func(node, callback, recursive=False, **kwargs):
1009
- processed_nodes = kwargs.pop('processed_nodes', OrderedSet())
1010
- stashed_nodes = kwargs.pop('stashed_nodes', OrderedSet())
1011
- process = kwargs.pop('process', ['main'])
1217
+ processed_nodes = kwargs.pop("processed_nodes", OrderedSet())
1218
+ stashed_nodes = kwargs.pop("stashed_nodes", OrderedSet())
1219
+ process = kwargs.pop("process", ["main"])
1012
1220
  path_len = 0
1013
-
1221
+
1014
1222
  walktrhough_tricc_node_processed_stached(
1015
- node,
1016
- callback,
1017
- processed_nodes,
1018
- stashed_nodes,
1019
- path_len,
1020
- recursive,
1021
- process=process,
1022
- **kwargs)
1223
+ node, callback, processed_nodes, stashed_nodes, path_len, recursive, process=process, **kwargs
1224
+ )
1023
1225
  # callback( node, **kwargs)
1024
- ## MANAGE STASHED NODES
1226
+ # MANAGE STASHED NODES
1025
1227
  prev_stashed_nodes = stashed_nodes.copy()
1026
1228
  loop_count = 0
1027
1229
  len_prev_processed_nodes = 0
1028
1230
  while len(stashed_nodes) > 0:
1029
- loop_count = check_stashed_loop(stashed_nodes, prev_stashed_nodes, processed_nodes, len_prev_processed_nodes,
1030
- loop_count)
1231
+ loop_count = check_stashed_loop(
1232
+ stashed_nodes, prev_stashed_nodes, processed_nodes, len_prev_processed_nodes, loop_count
1233
+ )
1031
1234
  prev_stashed_nodes = stashed_nodes.copy()
1032
1235
  len_prev_processed_nodes = len(processed_nodes)
1033
1236
  if len(stashed_nodes) > 0:
@@ -1035,11 +1238,13 @@ def stashed_node_func(node, callback, recursive=False, **kwargs):
1035
1238
  # remove duplicates
1036
1239
  if s_node in stashed_nodes:
1037
1240
  stashed_nodes.remove(s_node)
1038
- if kwargs.get('warn', True):
1039
- logger.debug("{}:: {}: unstashed for processing ({})".format(callback.__name__, s_node.__class__,
1040
- get_data_for_log(s_node),
1041
- len(stashed_nodes)))
1042
- warn = loop_count >= (9 * len(stashed_nodes )+1)
1241
+ if kwargs.get("warn", True):
1242
+ logger.debug(
1243
+ "{}:: {}: unstashed for processing ({})::{}".format(
1244
+ callback.__name__, s_node.__class__, get_data_for_log(s_node), len(stashed_nodes)
1245
+ )
1246
+ )
1247
+ warn = loop_count >= (9 * len(stashed_nodes) + 1)
1043
1248
  walktrhough_tricc_node_processed_stached(
1044
1249
  s_node,
1045
1250
  callback,
@@ -1049,77 +1254,87 @@ def stashed_node_func(node, callback, recursive=False, **kwargs):
1049
1254
  recursive,
1050
1255
  warn=warn,
1051
1256
  process=process,
1052
- **kwargs)
1257
+ **kwargs,
1258
+ )
1053
1259
 
1054
1260
 
1055
1261
  # check if the all the prev nodes are processed
1056
1262
  def is_ready_to_process(in_node, processed_nodes, strict=True, local=False):
1057
1263
  if isinstance(in_node, TriccNodeSelectOption):
1058
1264
  node = in_node.select
1059
- elif (
1060
- isinstance(in_node, (TriccNodeActivityStart, TriccNodeMainStart)) ):
1265
+ elif isinstance(in_node, (TriccNodeActivityStart, TriccNodeMainStart)):
1061
1266
  # check before
1062
1267
  return True
1063
1268
  else:
1064
1269
  node = in_node
1065
- if hasattr(node, 'prev_nodes'):
1270
+ if hasattr(node, "prev_nodes"):
1066
1271
  # ensure the previous node of the select are processed, not the option prev nodes
1067
1272
  for prev_node in node.prev_nodes:
1068
1273
  if is_prev_processed(prev_node, node, processed_nodes, local) is False:
1069
1274
  return False
1070
1275
  return True
1071
-
1276
+
1277
+
1072
1278
  def is_prev_processed(prev_node, node, processed_nodes, local):
1073
- if hasattr(prev_node, 'select'):
1074
- return is_prev_processed(prev_node.select, node, processed_nodes, local)
1279
+ if hasattr(prev_node, "select"):
1280
+ return is_prev_processed(prev_node.select, node, processed_nodes, local)
1075
1281
  if prev_node not in processed_nodes and (not local):
1076
1282
  if isinstance(prev_node, TriccNodeExclusive):
1077
1283
  iterator = iter(prev_node.prev_nodes)
1078
1284
  p_n_node = next(iterator)
1079
- logger.debug("is_ready_to_process:failed:via_excl: {} - {} > {} {}:{}".format(
1080
- get_data_for_log(p_n_node),
1081
- prev_node.get_name(),
1082
- node.__class__, node.get_name(), node.instance))
1285
+ logger.debug(
1286
+ "is_ready_to_process:failed:via_excl: {} - {} > {} {}:{}".format(
1287
+ get_data_for_log(p_n_node), prev_node.get_name(), node.__class__, node.get_name(), node.instance
1288
+ )
1289
+ )
1083
1290
 
1084
1291
  else:
1085
- logger.debug("is_ready_to_process:failed: {} -> {} {}:{}".format(
1086
- get_data_for_log(prev_node),
1087
- node.__class__, node.get_name(), node.instance))
1292
+ logger.debug(
1293
+ "is_ready_to_process:failed: {} -> {} {}:{}".format(
1294
+ get_data_for_log(prev_node), node.__class__, node.get_name(), node.instance
1295
+ )
1296
+ )
1088
1297
 
1089
- logger.debug("prev node node {}:{} for node {} not in processed".format(prev_node.__class__,
1090
- prev_node.get_name(),
1091
- node.get_name()))
1298
+ logger.debug(
1299
+ "prev node node {}:{} for node {} not in processed".format(
1300
+ prev_node.__class__, prev_node.get_name(), node.get_name()
1301
+ )
1302
+ )
1092
1303
  return False
1093
1304
  return True
1094
1305
 
1095
1306
 
1307
+ def print_trace(node, prev_node, processed_nodes, stashed_nodes, history=[]):
1096
1308
 
1097
- def print_trace(node, prev_node, processed_nodes, stashed_nodes, history = []):
1098
-
1099
1309
  if node != prev_node:
1100
1310
  if node in processed_nodes:
1101
- logger.warning("print trace :: node {} was the last not processed ({})".format(
1102
- get_data_for_log(prev_node), node.id, ">".join(history)))
1103
- #processed_nodes.add(prev_node)
1311
+ logger.warning(
1312
+ "print trace :: node {} was the last not processed ({}):{}".format(
1313
+ get_data_for_log(prev_node), node.id, ">".join(history)
1314
+ )
1315
+ )
1316
+ # processed_nodes.add(prev_node)
1104
1317
  return False
1105
1318
  elif node in history:
1106
- logger.critical("print trace :: CYCLE node {} found in history ({})".format(
1107
- get_data_for_log(prev_node), ">".join(history)))
1319
+ logger.critical(
1320
+ "print trace :: CYCLE node {} found in history ({})".format(
1321
+ get_data_for_log(prev_node), ">".join(history)
1322
+ )
1323
+ )
1108
1324
  exit(1)
1109
1325
  elif node in stashed_nodes:
1110
1326
  # logger.debug("print trace :: node {}::{} in stashed".format(node.__class__,node.get_name()))
1111
1327
  return False
1112
1328
  # else:
1113
- # logger.debug("print trace :: node {} not processed/stashed".format(node.get_name()))
1329
+ # logger.debug("print trace :: node {} not processed/stashed".format(node.get_name()))
1114
1330
  return True
1115
1331
 
1116
1332
 
1117
- def reverse_walkthrough(in_node, next_node, callback, processed_nodes, stashed_nodes, history = []):
1333
+ def reverse_walkthrough(in_node, next_node, callback, processed_nodes, stashed_nodes, history=[]):
1118
1334
  # transform dead-end nodes
1119
1335
  if next_node == in_node and next_node not in stashed_nodes:
1120
1336
  # workaround fir loop
1121
1337
  return False
1122
-
1123
1338
 
1124
1339
  if isinstance(in_node, TriccNodeSelectOption):
1125
1340
  node = in_node.select
@@ -1132,53 +1347,79 @@ def reverse_walkthrough(in_node, next_node, callback, processed_nodes, stashed_n
1132
1347
  if isinstance(in_node, TriccNodeActivity):
1133
1348
  prev_nodes = set(in_node.get_end_nodes())
1134
1349
  for prev in prev_nodes:
1135
- reverse_walkthrough(prev, next_node, callback, processed_nodes=processed_nodes, stashed_nodes=stashed_nodes, history=history)
1136
- if hasattr(node, 'prev_nodes'):
1350
+ reverse_walkthrough(
1351
+ prev,
1352
+ next_node,
1353
+ callback,
1354
+ processed_nodes=processed_nodes,
1355
+ stashed_nodes=stashed_nodes,
1356
+ history=history,
1357
+ )
1358
+ if hasattr(node, "prev_nodes"):
1137
1359
  if node.prev_nodes:
1138
1360
  for prev in node.prev_nodes:
1139
- reverse_walkthrough(prev, node, callback, processed_nodes=processed_nodes, stashed_nodes=stashed_nodes, history=history)
1361
+ reverse_walkthrough(
1362
+ prev,
1363
+ node,
1364
+ callback,
1365
+ processed_nodes=processed_nodes,
1366
+ stashed_nodes=stashed_nodes,
1367
+ history=history,
1368
+ )
1140
1369
  elif node in node.activity.calculates:
1141
- reverse_walkthrough(prev, node.activity.root, callback, processed_nodes=processed_nodes, stashed_nodes=stashed_nodes, history=history)
1370
+ reverse_walkthrough(
1371
+ prev,
1372
+ node.activity.root,
1373
+ callback,
1374
+ processed_nodes=processed_nodes,
1375
+ stashed_nodes=stashed_nodes,
1376
+ history=history,
1377
+ )
1142
1378
 
1143
1379
  if issubclass(node.__class__, TriccRhombusMixIn):
1144
1380
  if isinstance(node.reference, list):
1145
1381
  for ref in node.reference:
1146
- reverse_walkthrough(ref, node, callback, processed_nodes=processed_nodes, stashed_nodes=stashed_nodes, history= history)
1147
-
1148
-
1382
+ reverse_walkthrough(
1383
+ ref,
1384
+ node,
1385
+ callback,
1386
+ processed_nodes=processed_nodes,
1387
+ stashed_nodes=stashed_nodes,
1388
+ history=history,
1389
+ )
1149
1390
 
1150
1391
 
1151
1392
  def get_prev_node_by_name(processed_nodes, name, node):
1152
- # look for the node in the same activity
1153
- last_calc = get_last_version(
1154
- name,
1155
- processed_nodes
1156
- )
1393
+ # look for the node in the same activity
1394
+ last_calc = get_last_version(name, processed_nodes)
1157
1395
  if last_calc:
1158
1396
  return last_calc
1159
-
1397
+
1160
1398
  filtered = list(
1161
- filter(lambda p_node:
1162
- hasattr(p_node,'name')
1163
- and p_node.name == name
1164
- and p_node.instance == node.instance
1165
- and p_node.path_len <= node.path_len, processed_nodes
1166
- ))
1399
+ filter(
1400
+ lambda p_node: hasattr(p_node, "name")
1401
+ and p_node.name == name
1402
+ and p_node.instance == node.instance
1403
+ and p_node.path_len <= node.path_len,
1404
+ processed_nodes,
1405
+ )
1406
+ )
1167
1407
  if len(filtered) == 0:
1168
- filtered = list(filter(lambda p_node: hasattr(p_node, 'name') and p_node.name == name , processed_nodes))
1408
+ filtered = list(filter(lambda p_node: hasattr(p_node, "name") and p_node.name == name, processed_nodes))
1169
1409
  if len(filtered) > 0:
1170
1410
  return sorted(filtered, key=lambda x: x.path_len, reverse=False)[0]
1171
1411
 
1412
+
1172
1413
  MIN_LOOP_COUNT = 10
1173
1414
 
1415
+
1174
1416
  def check_stashed_loop(stashed_nodes, prev_stashed_nodes, processed_nodes, len_prev_processed_nodes, loop_count):
1175
- loop_out = {}
1176
-
1417
+
1177
1418
  if len(stashed_nodes) == len(prev_stashed_nodes):
1178
- # to avoid checking the details
1179
- if loop_count<=0:
1419
+ # to avoid checking the details
1420
+ if loop_count <= 0:
1180
1421
  if loop_count < -MIN_LOOP_COUNT:
1181
- loop_count = MIN_LOOP_COUNT+1
1422
+ loop_count = MIN_LOOP_COUNT + 1
1182
1423
  else:
1183
1424
  loop_count -= 1
1184
1425
  if loop_count > MIN_LOOP_COUNT:
@@ -1186,51 +1427,56 @@ def check_stashed_loop(stashed_nodes, prev_stashed_nodes, processed_nodes, len_p
1186
1427
  loop_count += 1
1187
1428
  if loop_count > max(MIN_LOOP_COUNT, 11 * len(prev_stashed_nodes) + 1):
1188
1429
  logger.critical("Stashed node list was unchanged: loop likely or unresolved dependence")
1189
- waited, looped = get_all_dependant(stashed_nodes, stashed_nodes, processed_nodes)
1430
+ waited, looped = get_all_dependant(stashed_nodes, stashed_nodes, processed_nodes)
1190
1431
  logger.debug(f"{len(looped)} nodes waiting stashed nodes")
1191
1432
  logger.info("unresolved reference")
1192
1433
  for es_node in [n for n in stashed_nodes if isinstance(n, TriccReference)]:
1193
- logger.info("Stashed node {}:{}|{} {}".format(
1194
- es_node.activity.get_name() if hasattr(es_node,'activity') else '' ,
1195
- es_node.activity.instance if hasattr(es_node,'activity') else '',
1196
- es_node.__class__,
1197
- es_node.get_name()))
1198
- for es_node in [node for node_list in looped.values() for node in node_list if isinstance(node, TriccReference)]:
1199
- logger.info("looped node {}:{}|{} {}".format(
1200
- es_node.activity.get_name() if hasattr(es_node,'activity') else '' ,
1201
- es_node.activity.instance if hasattr(es_node,'activity') else '',
1202
- es_node.__class__,
1203
- es_node.get_name()))
1204
- for es_node in [node for node_list in waited.values() for node in node_list if isinstance(node, TriccReference)]:
1205
- logger.info("waited node {}:{}|{} {}".format(
1206
- es_node.activity.get_name() if hasattr(es_node,'activity') else '' ,
1207
- es_node.activity.instance if hasattr(es_node,'activity') else '',
1208
- es_node.__class__,
1209
- es_node.get_name()))
1434
+ logger.info(
1435
+ "Stashed node {}:{}|{} {}".format(
1436
+ es_node.activity.get_name() if hasattr(es_node, "activity") else "",
1437
+ es_node.activity.instance if hasattr(es_node, "activity") else "",
1438
+ es_node.__class__,
1439
+ es_node.get_name(),
1440
+ )
1441
+ )
1442
+ for es_node in [
1443
+ node for node_list in looped.values() for node in node_list if isinstance(node, TriccReference)
1444
+ ]:
1445
+ logger.info(
1446
+ "looped node {}:{}|{} {}".format(
1447
+ es_node.activity.get_name() if hasattr(es_node, "activity") else "",
1448
+ es_node.activity.instance if hasattr(es_node, "activity") else "",
1449
+ es_node.__class__,
1450
+ es_node.get_name(),
1451
+ )
1452
+ )
1453
+ for es_node in [
1454
+ node for node_list in waited.values() for node in node_list if isinstance(node, TriccReference)
1455
+ ]:
1456
+ logger.info(
1457
+ "waited node {}:{}|{} {}".format(
1458
+ es_node.activity.get_name() if hasattr(es_node, "activity") else "",
1459
+ es_node.activity.instance if hasattr(es_node, "activity") else "",
1460
+ es_node.__class__,
1461
+ es_node.get_name(),
1462
+ )
1463
+ )
1210
1464
  logger.info("looped nodes")
1211
1465
  for dep_list in looped:
1212
1466
  for d in looped[dep_list]:
1213
1467
  if str(d) in looped:
1214
- logger.critical("[{}] depends on [{}]".format(
1215
- dep_list, str(d)
1216
- ))
1468
+ logger.critical("[{}] depends on [{}]".format(dep_list, str(d)))
1217
1469
  else:
1218
- logger.error("[{}] depends on [{}]".format(
1219
- dep_list, str(d)
1220
- ))
1470
+ logger.error("[{}] depends on [{}]".format(dep_list, str(d)))
1221
1471
  if dep_list in waited:
1222
1472
  for d in waited[dep_list]:
1223
- logger.warning("[{}] depends on [{}]".format(
1224
- dep_list, str(d)
1225
- ))
1473
+ logger.warning("[{}] depends on [{}]".format(dep_list, str(d)))
1226
1474
  logger.info("waited nodes")
1227
1475
  for dep_list in waited:
1228
1476
  if dep_list not in looped:
1229
1477
  for d in waited[dep_list]:
1230
- logger.warning("[{}] depends on [{}]".format(
1231
- dep_list, d.get_name()
1232
- ))
1233
-
1478
+ logger.warning("[{}] depends on [{}]".format(dep_list, d.get_name()))
1479
+
1234
1480
  if len(stashed_nodes) == len(prev_stashed_nodes):
1235
1481
  exit(1)
1236
1482
  else:
@@ -1239,6 +1485,7 @@ def check_stashed_loop(stashed_nodes, prev_stashed_nodes, processed_nodes, len_p
1239
1485
  loop_count = 0
1240
1486
  return loop_count
1241
1487
 
1488
+
1242
1489
  def add_to_tree(tree, n, d):
1243
1490
  n_str = str(n)
1244
1491
  if n_str not in tree:
@@ -1247,10 +1494,10 @@ def add_to_tree(tree, n, d):
1247
1494
  tree[n_str].append(d)
1248
1495
  return tree
1249
1496
 
1250
-
1251
- def get_all_dependant(loop, stashed_nodes, processed_nodes, depth=0, waited=None , looped=None, path = None):
1497
+
1498
+ def get_all_dependant(loop, stashed_nodes, processed_nodes, depth=0, waited=None, looped=None, path=None):
1252
1499
  if path is None:
1253
- path =[]
1500
+ path = []
1254
1501
  if looped is None:
1255
1502
  looped = {}
1256
1503
  if waited is None:
@@ -1260,50 +1507,55 @@ def get_all_dependant(loop, stashed_nodes, processed_nodes, depth=0, waited=None
1260
1507
  cur_path = path.copy()
1261
1508
  cur_path.append(n)
1262
1509
  dependant = OrderedSet()
1263
- i=0
1264
- #logger.critical(f"{i}: {n.__class__}::{n.get_name()}::{getattr(n,'instance','')}::{process_reference(n, processed_nodes, [])}")
1265
- i += 1
1266
- if hasattr(n, 'prev_nodes') and n.prev_nodes:
1267
- dependant = dependant | n.prev_nodes
1268
- if hasattr(n, 'get_references'):
1269
- dependant = dependant | (n.get_references() or OrderedSet())
1510
+ if hasattr(n, "prev_nodes") and n.prev_nodes:
1511
+ dependant = dependant | n.prev_nodes
1512
+ if hasattr(n, "get_references"):
1513
+ dependant = dependant | (n.get_references() or OrderedSet())
1270
1514
  if not isinstance(dependant, list):
1271
1515
  pass
1272
1516
  for d in dependant:
1273
1517
  if d in path:
1274
- logger.warning(f"loop {str(d)} already in path {'::'.join(map(str, path))} ")
1518
+ logger.warning(
1519
+ f"loop {str(d)} already in path {'::'.join(map(str, path))} "
1520
+ )
1275
1521
  if isinstance(d, TriccNodeSelectOption):
1276
1522
  d = d.select
1277
-
1523
+
1278
1524
  if isinstance(d, TriccReference):
1279
1525
  if not any(n.name == d.value for n in processed_nodes):
1280
1526
  if not any(n.name == d.value for n in stashed_nodes):
1281
1527
  waited = add_to_tree(waited, n, d)
1282
- else :
1528
+ else:
1283
1529
  looped = add_to_tree(looped, n, d)
1284
-
1530
+
1285
1531
  elif d not in processed_nodes:
1286
1532
  if d in stashed_nodes:
1287
1533
  looped = add_to_tree(looped, n, d)
1288
- else :
1534
+ else:
1289
1535
  waited = add_to_tree(waited, n, d)
1290
1536
  all_dependant = all_dependant.union(dependant)
1291
1537
  if depth < MAX_DRILL:
1292
- waited, looped = get_all_dependant(all_dependant, stashed_nodes, processed_nodes, depth+1, waited , looped, path=cur_path)
1293
-
1538
+ waited, looped = get_all_dependant(
1539
+ all_dependant, stashed_nodes, processed_nodes, depth + 1, waited, looped, path=cur_path
1540
+ )
1541
+
1294
1542
  return waited, looped
1295
1543
 
1296
1544
 
1297
1545
  MAX_DRILL = 3
1298
1546
 
1547
+
1299
1548
  def get_last_end_node(processed_nodes, process=None):
1300
- end_name = 'tricc_end_'
1549
+ end_name = "tricc_end_"
1301
1550
  if process:
1302
1551
  end_name += process
1303
1552
  return get_last_version(end_name, processed_nodes)
1304
1553
 
1554
+
1305
1555
  # Set the source next node to target and clean next nodes of replace node
1306
- def set_prev_next_node(source_node, target_node, replaced_node=None, edge_only = False, activity=None):
1556
+
1557
+
1558
+ def set_prev_next_node(source_node, target_node, replaced_node=None, edge_only=False, activity=None):
1307
1559
  activity = activity or source_node.activity
1308
1560
  source_id, source_node = get_node_from_id(activity, source_node, edge_only)
1309
1561
  target_id, target_node = get_node_from_id(activity, target_node, edge_only)
@@ -1311,36 +1563,39 @@ def set_prev_next_node(source_node, target_node, replaced_node=None, edge_only =
1311
1563
  if not edge_only:
1312
1564
  set_prev_node(source_node, target_node, replaced_node, edge_only)
1313
1565
  set_next_node(source_node, target_node, replaced_node, edge_only)
1314
-
1315
- if activity and not any([(e.source == source_id) and ( e.target == target_id) for e in activity.edges]):
1566
+
1567
+ if activity and not any([(e.source == source_id) and (e.target == target_id) for e in activity.edges]):
1316
1568
  label = "continue" if issubclass(source_node.__class__, TriccNodeSelect) else None
1317
- activity.edges.append(TriccEdge(id = generate_id(), source = source_id, target = target_id, value = label))
1569
+ activity.edges.append(TriccEdge(id=generate_id(), source=source_id, target=target_id, value=label))
1570
+
1318
1571
 
1319
1572
  def remove_prev_next(prev_node, next_node, activity=None):
1320
1573
  activity = activity or prev_node.activity
1321
- if hasattr(prev_node, 'next_nodes') and next_node in prev_node.next_nodes:
1574
+ if hasattr(prev_node, "next_nodes") and next_node in prev_node.next_nodes:
1322
1575
  prev_node.next_nodes.remove(next_node)
1323
- if hasattr(next_node, 'prev_nodes') and prev_node in next_node.prev_nodes:
1576
+ if hasattr(next_node, "prev_nodes") and prev_node in next_node.prev_nodes:
1324
1577
  next_node.prev_nodes.remove(prev_node)
1325
-
1578
+
1326
1579
  for e in list(activity.edges):
1327
- if (e.target == getattr(next_node, 'id', next_node) and e.source == getattr(prev_node, 'id', prev_node)):
1580
+ if e.target == getattr(next_node, "id", next_node) and e.source == getattr(prev_node, "id", prev_node):
1328
1581
  activity.edges.remove(e)
1329
-
1330
-
1331
-
1332
- def set_next_node(source_node, target_node, replaced_node=None, edge_only = False, activity=None):
1582
+
1583
+
1584
+ def set_next_node(source_node, target_node, replaced_node=None, edge_only=False, activity=None):
1333
1585
  activity = activity or source_node.activity
1334
1586
  replace_target = None
1335
- if not edge_only:
1336
- if replaced_node is not None and hasattr(source_node, 'path') and replaced_node == source_node.path:
1587
+ if not edge_only:
1588
+ if replaced_node is not None and hasattr(source_node, "path") and replaced_node == source_node.path:
1337
1589
  source_node.path = target_node
1338
- elif replaced_node is not None and hasattr(source_node, 'next_nodes') and replaced_node in source_node.next_nodes:
1590
+ elif (
1591
+ replaced_node is not None and hasattr(source_node, "next_nodes") and replaced_node in source_node.next_nodes
1592
+ ):
1339
1593
  replace_target = True
1340
1594
  source_node.next_nodes.remove(replaced_node)
1341
- if hasattr(replaced_node, 'prev_nodes') and source_node in replaced_node.prev_nodes:
1595
+ if hasattr(replaced_node, "prev_nodes") and source_node in replaced_node.prev_nodes:
1342
1596
  replaced_node.prev_nodes.remove(source_node)
1343
- #if replaced_node is not None and hasattr(target_node, 'next_nodes') and replaced_node in target_node.next_nodes:
1597
+ # if replaced_node is not None and hasattr(target_node, 'next_nodes')
1598
+ # and replaced_node in target_node.next_nodes:
1344
1599
  # target_node.next_nodes.remove(replaced_node)
1345
1600
  if target_node not in source_node.next_nodes:
1346
1601
  source_node.next_nodes.add(target_node)
@@ -1359,31 +1614,34 @@ def set_next_node(source_node, target_node, replaced_node=None, edge_only = Fals
1359
1614
  if replaced_node and replace_target:
1360
1615
  if replaced_node.id in replaced_node.activity.nodes:
1361
1616
  del replaced_node.activity.nodes[replaced_node.id]
1362
- next_edges = set([
1363
- e for e in replaced_node.activity.edges if (e.target == replaced_node.id or e.target == replaced_node)
1364
- ] + [
1365
- e for e in activity.edges if (e.target == replaced_node.id or e.target == replaced_node)
1366
- ])
1367
- if len(next_edges)==0:
1368
- for e in next_edges:
1617
+ next_edges = set(
1618
+ [
1619
+ e for e in replaced_node.activity.edges
1620
+ if (e.target == replaced_node.id or e.target == replaced_node)
1621
+ ] + [
1622
+ e for e in activity.edges
1623
+ if (e.target == replaced_node.id or e.target == replaced_node)
1624
+ ]
1625
+ )
1626
+ if len(next_edges) == 0:
1627
+ for e in next_edges:
1369
1628
  e.target = target_node.id
1370
1629
 
1371
-
1372
1630
 
1373
1631
  # Set the target_node prev node to source and clean prev nodes of replace_node
1374
- def set_prev_node(source_node, target_node, replaced_node=None, edge_only = False, activity=None):
1632
+ def set_prev_node(source_node, target_node, replaced_node=None, edge_only=False, activity=None):
1375
1633
  activity = activity or source_node.activity
1376
1634
  replace_source = False
1377
1635
  # update the prev node of the target not if not an end node
1378
1636
  # update directly the prev node of the target
1379
- if replaced_node is not None and hasattr(target_node, 'path') and replaced_node == target_node.path:
1637
+ if replaced_node is not None and hasattr(target_node, "path") and replaced_node == target_node.path:
1380
1638
  target_node.path = source_node
1381
- if replaced_node is not None and hasattr(target_node, 'prev_nodes') and replaced_node in target_node.prev_nodes:
1639
+ if replaced_node is not None and hasattr(target_node, "prev_nodes") and replaced_node in target_node.prev_nodes:
1382
1640
  replace_source = True
1383
1641
  target_node.prev_nodes.remove(replaced_node)
1384
- if hasattr(replaced_node, 'next_nodes') and source_node in replaced_node.next_nodes:
1642
+ if hasattr(replaced_node, "next_nodes") and source_node in replaced_node.next_nodes:
1385
1643
  replaced_node.next_nodes.remove(source_node)
1386
- #if replaced_node is not None and hasattr(source_node, 'prev_nodes') and replaced_node in source_node.prev_nodes:
1644
+ # if replaced_node is not None and hasattr(source_node, 'prev_nodes') and replaced_node in source_node.prev_nodes:
1387
1645
  # source_node.prev_nodes.remove(replaced_node)
1388
1646
  if source_node not in target_node.prev_nodes:
1389
1647
  target_node.prev_nodes.add(source_node)
@@ -1391,18 +1649,17 @@ def set_prev_node(source_node, target_node, replaced_node=None, edge_only = Fals
1391
1649
  activity.nodes[source_node.id] = source_node
1392
1650
  if replaced_node and replace_source:
1393
1651
  if replaced_node.id in replaced_node.activity.nodes:
1394
- del replaced_node.activity.nodes[replaced_node.id]
1395
- next_edges = set([
1396
- e for e in replaced_node.activity.edges if (e.source == replaced_node.id or e.source == replaced_node)
1397
- ] + [
1398
- e for e in activity.edges if (e.source == replaced_node.id or e.source == replaced_node)
1399
- ])
1400
- if len(next_edges)==0:
1401
- for e in next_edges:
1652
+ del replaced_node.activity.nodes[replaced_node.id]
1653
+ next_edges = set(
1654
+ [e for e in replaced_node.activity.edges if (e.source == replaced_node.id or e.source == replaced_node)]
1655
+ + [e for e in activity.edges if (e.source == replaced_node.id or e.source == replaced_node)]
1656
+ )
1657
+ if len(next_edges) == 0:
1658
+ for e in next_edges:
1402
1659
  e.target = target_node.id
1403
-
1404
1660
 
1405
- def replace_node(old, new, page = None):
1661
+
1662
+ def replace_node(old, new, page=None):
1406
1663
  if page is None:
1407
1664
  page = old.activity
1408
1665
  logger.debug("replacing node {} with node {} from page {}".format(old.get_name(), new.get_name(), page.get_name()))
@@ -1429,23 +1686,25 @@ def replace_node(old, new, page = None):
1429
1686
  if edge.target == old.id:
1430
1687
  edge.target = new.id
1431
1688
 
1432
- def replace_prev_next_node(prev_node, next_node, old_node, force = False):
1689
+
1690
+ def replace_prev_next_node(prev_node, next_node, old_node, force=False):
1433
1691
  replace_prev_node(prev_node, next_node, old_node)
1434
1692
  replace_next_node(prev_node, next_node, old_node)
1435
1693
 
1436
- def replace_prev_node(prev_node, next_node, old_node, force = False):
1437
- #create a copy pf the list
1694
+
1695
+ def replace_prev_node(prev_node, next_node, old_node, force=False):
1696
+ # create a copy pf the list
1438
1697
  list_nodes = list(next_node.prev_nodes)
1439
1698
  # replace in case old node is found
1440
1699
  for p_n_node in list_nodes:
1441
1700
  if p_n_node == old_node or force:
1442
1701
  set_prev_next_node(prev_node, next_node, old_node)
1443
-
1444
-
1445
- def replace_next_node(prev_node,next_node,old_node):
1702
+
1703
+
1704
+ def replace_next_node(prev_node, next_node, old_node):
1446
1705
  list_nodes = list(prev_node.next_nodes)
1447
1706
  for n_p_node in list_nodes:
1448
- if n_p_node == old_node :
1707
+ if n_p_node == old_node:
1449
1708
  set_prev_next_node(prev_node, next_node, old_node)
1450
1709
 
1451
1710
 
@@ -1458,6 +1717,7 @@ ACTIVE_ACTIVITY_LOWER_PRIORITY = 3000
1458
1717
  RHOMBUS_PRIORITY = 1000
1459
1718
  DEFAULT_PRIORITY = 2000
1460
1719
 
1720
+
1461
1721
  def reorder_node_list(node_list, group, processed_nodes):
1462
1722
  # Cache active activities for O(1) lookup
1463
1723
  active_activities = {n.activity for n in processed_nodes}
@@ -1493,49 +1753,51 @@ def reorder_node_list(node_list, group, processed_nodes):
1493
1753
 
1494
1754
  # Sort in place, highest priority first
1495
1755
  node_list.sort(key=get_priority, reverse=True)
1496
-
1756
+
1757
+
1497
1758
  def loop_info(loop, **kwargs):
1498
1759
  logger.critical("dependency details")
1499
1760
  for n in loop:
1500
- i=0
1761
+ i = 0
1501
1762
  logger.critical(f"{i}: {n.__class__}::{n.get_name()}")
1502
1763
  i += 1
1503
1764
 
1504
1765
 
1505
- def has_loop(node, processed_nodes, stashed_nodes, warn , node_path=[], action_on_loop=loop_info,action_on_other=None, **kwargs):
1766
+ def has_loop(
1767
+ node, processed_nodes, stashed_nodes, warn, node_path=[], action_on_loop=loop_info, action_on_other=None, **kwargs
1768
+ ):
1506
1769
  next_nodes = get_extended_next_nodes(node)
1507
- for next_node in next_nodes:
1770
+ for next_node in next_nodes:
1508
1771
  if next_node in node_path:
1509
1772
  loop_start_key = node_path.index(next_node)
1510
1773
  loop = node_path[loop_start_key:]
1511
1774
  loop.append(node)
1512
1775
  loop.append(next_node)
1513
1776
  action_on_loop(loop, **kwargs)
1514
- return False
1777
+ return False
1515
1778
  if callable(action_on_other):
1516
1779
  action_on_other(next_node, **kwargs)
1517
1780
  return True
1518
-
1519
-
1781
+
1520
1782
 
1521
1783
  def get_extended_next_nodes(node):
1522
-
1523
- nodes = node.next_nodes if hasattr(node,'next_nodes') else set()
1524
- if issubclass(node.__class__, TriccNodeSelect ):
1784
+
1785
+ nodes = node.next_nodes if hasattr(node, "next_nodes") else set()
1786
+ if issubclass(node.__class__, TriccNodeSelect):
1525
1787
  for o in node.options.values():
1526
1788
  nodes = nodes | o.next_nodes
1527
- if isinstance(node, ( TriccNodeActivity) ):
1789
+ if isinstance(node, (TriccNodeActivity)):
1528
1790
  nodes = nodes | node.root.next_nodes
1529
1791
  return nodes
1530
-
1792
+
1531
1793
 
1532
1794
  # calculate or retrieve a node expression
1533
- def get_node_expression( in_node, processed_nodes, get_overall_exp=False, is_prev=False, negate=False, process=None):
1795
+ def get_node_expression(in_node, processed_nodes, get_overall_exp=False, is_prev=False, negate=False, process=None):
1534
1796
  # in case of calculate we only use the select multiple if none is not selected
1535
1797
  expression = None
1536
1798
  negate_expression = None
1537
1799
  node = in_node
1538
- if isinstance(node, (TriccNodeActivityStart,TriccNodeMainStart)):
1800
+ if isinstance(node, (TriccNodeActivityStart, TriccNodeMainStart)):
1539
1801
  if is_prev and get_overall_exp:
1540
1802
  expression = get_node_expression(
1541
1803
  node.activity,
@@ -1543,13 +1805,13 @@ def get_node_expression( in_node, processed_nodes, get_overall_exp=False, is_pre
1543
1805
  get_overall_exp=True,
1544
1806
  is_prev=is_prev,
1545
1807
  negate=negate,
1546
- process=process
1808
+ process=process,
1547
1809
  )
1548
1810
  if isinstance(node, TriccNodeMainStart):
1549
- expression = get_applicability_expression(node.activity, processed_nodes, process, expression )
1811
+ expression = get_applicability_expression(node.activity, processed_nodes, process, expression)
1550
1812
  elif isinstance(node, (TriccNodeActivityStart)):
1551
1813
  return TriccStatic(True)
1552
-
1814
+
1553
1815
  elif isinstance(node, TriccNodeWait):
1554
1816
  if is_prev:
1555
1817
  # the wait don't do any calculation with the reference it is only use to wait until the reference are valid
@@ -1558,86 +1820,78 @@ def get_node_expression( in_node, processed_nodes, get_overall_exp=False, is_pre
1558
1820
  processed_nodes=processed_nodes,
1559
1821
  get_overall_exp=get_overall_exp,
1560
1822
  is_prev=True,
1561
- process=process
1562
- )
1823
+ process=process,
1824
+ )
1563
1825
  else:
1564
- #it is a empty calculate
1826
+ # it is a empty calculate
1565
1827
  return None
1566
1828
  elif isinstance(node, TriccNodeRhombus):
1567
- # if is_prev:
1568
- # expression = TriccOperation(
1569
- # TriccOperator.ISTRUE,
1570
- # [node]
1571
- # )
1572
- # else:
1573
- expression = get_rhombus_terms(node, processed_nodes, process=process) # if issubclass(node.__class__, TricNodeDisplayCalulate) else TRICC_CALC_EXPRESSION.format(get_export_name(node)) #
1829
+ expression = get_rhombus_terms(node, processed_nodes, process=process)
1574
1830
  negate_expression = not_clean(expression)
1575
- if node.path is None :
1831
+ if node.path is None:
1576
1832
  if len(node.prev_nodes) == 1:
1577
1833
  node.path = list(node.prev_nodes)[0]
1578
1834
  elif len(node.prev_nodes) > 1:
1579
1835
  logger.critical(f"missing path for Rhombus {node.get_name()}")
1580
1836
  exit(1)
1581
1837
  prev_exp = get_node_expression(
1582
- node.path,
1583
- processed_nodes=processed_nodes,
1584
- get_overall_exp=get_overall_exp,
1585
- is_prev=True,
1586
- process=process)
1838
+ node.path, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, is_prev=True, process=process
1839
+ )
1587
1840
  if prev_exp and expression:
1588
1841
  expression = and_join([prev_exp, expression])
1589
- negate_expression = and_join([
1590
- prev_exp,
1591
- negate_expression
1592
- ])
1842
+ negate_expression = and_join([prev_exp, negate_expression])
1593
1843
 
1594
1844
  elif prev_exp:
1595
-
1845
+
1596
1846
  logger.error(f"useless rhombus {node.get_name()}")
1597
1847
  expression = prev_exp
1598
1848
  negate_expression = prev_exp
1599
1849
  logger.critical(f"Rhombus without expression {node.get_name()}")
1600
1850
  elif is_prev and issubclass(node.__class__, TriccNodeDisplayCalculateBase):
1601
1851
  expression = TriccOperation(TriccOperator.ISTRUE, [node])
1602
- elif hasattr(node, 'expression_reference') and isinstance(node.expression_reference, TriccOperation):
1852
+ elif hasattr(node, "expression_reference") and isinstance(node.expression_reference, TriccOperation):
1603
1853
  # if issubclass(node.__class__, TriccNodeDisplayCalculateBase):
1604
1854
  # expression = TriccOperation(
1605
1855
  # TriccOperator.CAST_NUMBER,
1606
1856
  # [node.expression_reference])
1607
- # else:
1608
- expression = node.expression_reference
1857
+ # else:
1858
+ expression = node.expression_reference
1609
1859
  elif is_prev and isinstance(node, TriccNodeSelectOption):
1610
1860
  if negate:
1611
1861
  negate_expression = get_selected_option_expression(node, negate)
1612
1862
  else:
1613
1863
  expression = get_selected_option_expression(node, negate)
1614
- #TODO remove that and manage it on the "Save" part
1864
+ # TODO remove that and manage it on the "Save" part
1615
1865
  elif is_prev and isinstance(node, TriccNodeSelectNotAvailable):
1616
- expression = TriccOperation(
1617
- TriccOperator.SELECTED,
1618
- [
1619
- node,
1620
- TriccStatic(1)
1621
- ]
1622
- )
1866
+ expression = TriccOperation(TriccOperator.SELECTED, [node, TriccStatic(1)])
1623
1867
  elif issubclass(node.__class__, TriccNodeCalculateBase):
1624
1868
  if negate:
1625
- negate_expression = get_calculation_terms(node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, negate=True, process=process)
1869
+ negate_expression = get_calculation_terms(
1870
+ node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, negate=True, process=process
1871
+ )
1626
1872
  else:
1627
- expression = get_calculation_terms(node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process)
1628
-
1629
- elif (not is_prev or not ONE_QUESTION_AT_A_TIME) and hasattr(node, 'relevance') and isinstance(node.relevance, (TriccOperation, TriccStatic)):
1630
- expression = node.relevance
1631
- elif ONE_QUESTION_AT_A_TIME and is_prev and not get_overall_exp and hasattr(node, 'required') and node.required:
1873
+ expression = get_calculation_terms(
1874
+ node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process
1875
+ )
1876
+
1877
+ elif (
1878
+ (not is_prev or not ONE_QUESTION_AT_A_TIME)
1879
+ and hasattr(node, "relevance")
1880
+ and isinstance(node.relevance, (TriccOperation, TriccStatic))
1881
+ ):
1882
+ expression = node.relevance
1883
+ elif ONE_QUESTION_AT_A_TIME and is_prev and not get_overall_exp and hasattr(node, "required") and node.required:
1632
1884
  expression = get_required_node_expression(node)
1633
-
1885
+
1634
1886
  if expression is None:
1635
- expression = get_prev_node_expression(node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process)
1636
- # in_node not in processed_nodes is need for calculates that can but run after the end of the activity
1637
- #if isinstance(node, TriccNodeActivitiy) and not prev:
1638
- # expression = get_applicability_expression(node, processed_nodes, process, expression)
1639
- # expression = get_prev_instance_skip_expression(node, processed_nodes, process, expression)
1640
- # expression = get_process_skip_expression(node, processed_nodes, process, expression)
1887
+ expression = get_prev_node_expression(
1888
+ node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process
1889
+ )
1890
+ # in_node not in processed_nodes is need for calculates that can but run after the end of the activity
1891
+ # if isinstance(node, TriccNodeActivitiy) and not prev:
1892
+ # expression = get_applicability_expression(node, processed_nodes, process, expression)
1893
+ # expression = get_prev_instance_skip_expression(node, processed_nodes, process, expression)
1894
+ # expression = get_process_skip_expression(node, processed_nodes, process, expression)
1641
1895
  if negate:
1642
1896
  if negate_expression is not None:
1643
1897
  return negate_expression
@@ -1648,64 +1902,50 @@ def get_node_expression( in_node, processed_nodes, get_overall_exp=False, is_pre
1648
1902
  # exit(1)
1649
1903
  else:
1650
1904
  return expression
1651
-
1905
+
1906
+
1652
1907
  def get_applicability_expression(node, processed_nodes, process, expression=None):
1653
- if isinstance(node.applicability,(TriccStatic,TriccOperation, TriccReference)):
1908
+ if isinstance(node.applicability, (TriccStatic, TriccOperation, TriccReference)):
1654
1909
  if expression:
1655
1910
  expression = and_join([node.applicability, expression])
1656
1911
  else:
1657
1912
  expression = node.applicability
1658
-
1913
+
1659
1914
  return expression
1660
-
1661
1915
 
1662
1916
 
1663
-
1664
-
1665
1917
  def get_prev_instance_skip_expression(node, processed_nodes, process, expression=None):
1666
1918
  if node.base_instance is not None:
1667
- activity = node
1668
1919
  expression_inputs = []
1669
- past_instances = [
1670
- n for n in processed_nodes if getattr(n.base_instance, 'id', None) == node.base_instance.id
1671
- ]
1920
+ past_instances = [n for n in processed_nodes if getattr(n.base_instance, "id", None) == node.base_instance.id]
1672
1921
  for past_instance in past_instances:
1673
1922
  add_sub_expression(
1674
- expression_inputs,
1923
+ expression_inputs,
1675
1924
  get_node_expression(
1676
- past_instance,
1677
- processed_nodes=processed_nodes,
1678
- get_overall_exp=True,
1679
- is_prev=True,
1680
- process=process
1681
- )
1925
+ past_instance, processed_nodes=processed_nodes, get_overall_exp=True, is_prev=True, process=process
1926
+ ),
1682
1927
  )
1683
1928
  if expression and expression_inputs:
1684
1929
  add_sub_expression(expression_inputs, expression)
1685
1930
  expression = nand_join(expression, or_join(expression_inputs))
1686
1931
  elif expression_inputs:
1687
- expression = negate_term(or_join(expression_inputs))
1932
+ expression = negate_term(or_join(expression_inputs))
1688
1933
  return expression
1689
1934
 
1690
1935
 
1691
1936
  # end def
1692
1937
  def get_process_skip_expression(node, processed_nodes, process, expression=None):
1693
- list_ends = OrderedSet(
1694
- filter(
1695
- lambda x: issubclass(x.__class__, TriccNodeEnd),
1696
- processed_nodes
1697
- )
1698
- )
1938
+ list_ends = OrderedSet(filter(lambda x: issubclass(x.__class__, TriccNodeEnd), processed_nodes))
1699
1939
  if list_ends:
1700
1940
  end_expressions = []
1701
1941
  f_end_expression = get_end_expression(list_ends)
1702
1942
  if f_end_expression:
1703
1943
  end_expressions.append(f_end_expression)
1704
- b_end_expression = get_end_expression(list_ends, 'pause')
1944
+ b_end_expression = get_end_expression(list_ends, "pause")
1705
1945
  if b_end_expression:
1706
- end_expressions.append(b_end_expression)
1946
+ end_expressions.append(b_end_expression)
1707
1947
  if process[0] in PROCESSES:
1708
- for p in PROCESSES[PROCESSES.index(process[0])+1:]:
1948
+ for p in PROCESSES[PROCESSES.index(process[0]) + 1:]:
1709
1949
  p_end_expression = get_end_expression(list_ends, p)
1710
1950
  if p_end_expression:
1711
1951
  end_expressions.append(p_end_expression)
@@ -1717,16 +1957,12 @@ def get_process_skip_expression(node, processed_nodes, process, expression=None)
1717
1957
  else:
1718
1958
  expression = and_join(end_expressions)
1719
1959
  return expression
1720
-
1960
+
1961
+
1721
1962
  def get_end_expression(processed_nodes, process=None):
1722
1963
  end_node = get_last_end_node(processed_nodes, process)
1723
1964
  if end_node:
1724
- return TriccOperation(
1725
- TriccOperator.ISNOTTRUE,
1726
- [end_node]
1727
- )
1728
-
1729
-
1965
+ return TriccOperation(TriccOperator.ISNOTTRUE, [end_node])
1730
1966
 
1731
1967
 
1732
1968
  def export_proposed_diags(activity, diags=None, **kwargs):
@@ -1736,11 +1972,10 @@ def export_proposed_diags(activity, diags=None, **kwargs):
1736
1972
  if isinstance(node, TriccNodeActivity):
1737
1973
  diags = export_proposed_diags(node, diags, **kwargs)
1738
1974
  if isinstance(node, TriccNodeProposedDiagnosis):
1739
- if node.last is not False\
1740
- and not any([diag.name == node.name for diag in diags]):
1741
- diags.append(node)
1975
+ if node.last is not False and not any([diag.name == node.name for diag in diags]):
1976
+ diags.append(node)
1742
1977
  return diags
1743
-
1978
+
1744
1979
 
1745
1980
  def get_accept_diagnostic_node(code, display, severity, priority, activity):
1746
1981
  node = TriccNodeAcceptDiagnostic(
@@ -1751,11 +1986,12 @@ def get_accept_diagnostic_node(code, display, severity, priority, activity):
1751
1986
  activity=activity,
1752
1987
  group=activity,
1753
1988
  severity=severity,
1754
- priority=priority
1989
+ priority=priority,
1755
1990
  )
1756
1991
  node.options = get_select_accept_reject_options(node, node.activity)
1757
1992
  return node
1758
1993
 
1994
+
1759
1995
  def get_diagnostic_node(code, display, severity, priority, activity):
1760
1996
  node = TriccNodeCalculate(
1761
1997
  id=generate_id("final." + code),
@@ -1764,51 +2000,48 @@ def get_diagnostic_node(code, display, severity, priority, activity):
1764
2000
  activity=activity,
1765
2001
  group=activity,
1766
2002
  priority=priority,
1767
- expression_reference=or_join([
1768
- TriccOperation(TriccOperator.ISTRUE, [TriccReference("pre_final." + code)]),
1769
- TriccOperation(
1770
- TriccOperator.SELECTED,
1771
- [TriccReference('tricc.manual.diag'), TriccStatic(code)]
1772
- )
1773
- ])
2003
+ expression_reference=or_join(
2004
+ [
2005
+ TriccOperation(TriccOperator.ISTRUE, [TriccReference("pre_final." + code)]),
2006
+ TriccOperation(TriccOperator.SELECTED, [TriccReference("tricc.manual.diag"), TriccStatic(code)]),
2007
+ ]
2008
+ ),
1774
2009
  )
1775
2010
  return node
1776
2011
 
2012
+
1777
2013
  def get_select_accept_reject_options(node, group):
1778
2014
  yes = TriccNodeSelectOption(
1779
- id = generate_id(f'accept{node.id}'),
1780
- name=f"{TRICC_TRUE_VALUE}",
1781
- label="Accept",
1782
- select = node,
1783
- group = group,
1784
- list_name = node.list_name
1785
- )
2015
+ id=generate_id(f"accept{node.id}"),
2016
+ name=f"{TRICC_TRUE_VALUE}",
2017
+ label="Accept",
2018
+ select=node,
2019
+ group=group,
2020
+ list_name=node.list_name,
2021
+ )
1786
2022
  no = TriccNodeSelectOption(
1787
- id = generate_id(f'reject{node.id}'),
1788
- name=f"{TRICC_FALSE_VALUE}",
1789
- label="Reject",
1790
- select = node,
1791
- group = group,
1792
- list_name = node.list_name
1793
- )
1794
- return {0:yes, 1:no }
2023
+ id=generate_id(f"reject{node.id}"),
2024
+ name=f"{TRICC_FALSE_VALUE}",
2025
+ label="Reject",
2026
+ select=node,
2027
+ group=group,
2028
+ list_name=node.list_name,
2029
+ )
2030
+ return {0: yes, 1: no}
2031
+
1795
2032
 
1796
2033
  def create_determine_diagnosis_activity(diags):
1797
2034
  start = TriccNodeMainStart(
1798
- id=generate_id('start.determine-diagnosis'),
1799
- name="start.determine-diagnosis",
1800
- process='determine-diagnosis'
2035
+ id=generate_id("start.determine-diagnosis"), name="start.determine-diagnosis", process="determine-diagnosis"
1801
2036
  )
1802
2037
 
1803
-
1804
2038
  activity = TriccNodeActivity(
1805
- id=generate_id('activity-determine-diagnosis'),
1806
- name='determine-diagnosis',
1807
- label='Diagnosis',
2039
+ id=generate_id("activity-determine-diagnosis"),
2040
+ name="determine-diagnosis",
2041
+ label="Classifications",
1808
2042
  root=start,
1809
2043
  )
1810
2044
 
1811
-
1812
2045
  start.activity = activity
1813
2046
  start.group = activity
1814
2047
  diags_conf = []
@@ -1818,17 +2051,16 @@ def create_determine_diagnosis_activity(diags):
1818
2051
  activity=activity,
1819
2052
  group=activity,
1820
2053
  )
1821
- activity.nodes[end.id]=end
1822
-
2054
+ activity.nodes[end.id] = end
2055
+
1823
2056
  f = TriccNodeSelectMultiple(
1824
2057
  name="tricc.manual.diag",
1825
- label="Add diagnosis",
1826
- list_name='manual_diag',
2058
+ label="Add classifications",
2059
+ list_name="manual_diag",
1827
2060
  id=generate_id("tricc.manual.diag"),
1828
2061
  activity=activity,
1829
2062
  group=activity,
1830
2063
  required=TriccStatic(False),
1831
-
1832
2064
  )
1833
2065
  for proposed in diags:
1834
2066
  d = get_accept_diagnostic_node(proposed.name, proposed.label, proposed.severity, proposed.priority, activity)
@@ -1837,14 +2069,12 @@ def create_determine_diagnosis_activity(diags):
1837
2069
  r = TriccNodeRhombus(
1838
2070
  path=start,
1839
2071
  id=generate_id(f"proposed-rhombus{proposed.id}"),
1840
- expression_reference=TriccOperation(
1841
- TriccOperator.ISTRUE,
1842
- [TriccReference(proposed.name)]
1843
- ),
2072
+ expression_reference=TriccOperation(TriccOperator.ISTRUE, [TriccReference(proposed.name)]),
1844
2073
  reference=[TriccReference(proposed.name)],
1845
2074
  activity=activity,
1846
2075
  priority=proposed.priority,
1847
- group=activity)
2076
+ group=activity,
2077
+ )
1848
2078
  activity.calculates.append(r)
1849
2079
  activity.calculates.append(c)
1850
2080
  set_prev_next_node(r, d, edge_only=False)
@@ -1852,11 +2082,11 @@ def create_determine_diagnosis_activity(diags):
1852
2082
  wait2 = get_activity_wait([activity.root], diags_conf, [f], edge_only=False)
1853
2083
  activity.nodes[d.options[0].id] = d.options[0]
1854
2084
  activity.nodes[d.options[1].id] = d.options[1]
1855
- activity.nodes[d.id]=d
1856
- activity.nodes[r.id]=r
1857
- activity.nodes[c.id]=c
1858
- activity.nodes[f.id]=f
1859
- activity.nodes[wait2.id]=wait2
2085
+ activity.nodes[d.id] = d
2086
+ activity.nodes[r.id] = r
2087
+ activity.nodes[c.id] = c
2088
+ activity.nodes[f.id] = f
2089
+ activity.nodes[wait2.id] = wait2
1860
2090
  # fallback
1861
2091
 
1862
2092
  options = [
@@ -1866,220 +2096,182 @@ def create_determine_diagnosis_activity(diags):
1866
2096
  label=d.label,
1867
2097
  list_name=f.list_name,
1868
2098
  relevance=d.activity.applicability,
1869
- select=f
1870
- ) for d in diags
2099
+ select=f,
2100
+ )
2101
+ for d in diags
1871
2102
  ]
1872
- f.options=dict(zip(range(0, len(options)), options))
1873
- activity.nodes[f.id]=f
2103
+ f.options = dict(zip(range(0, len(options)), options))
2104
+ activity.nodes[f.id] = f
1874
2105
  set_prev_next_node(f, end, edge_only=False)
1875
-
2106
+
1876
2107
  return activity
1877
-
1878
- def get_prev_node_expression( node, processed_nodes, get_overall_exp=False, excluded_name=None, process=None):
2108
+
2109
+
2110
+ def get_prev_node_expression(node, processed_nodes, get_overall_exp=False, excluded_name=None, process=None):
1879
2111
  expression = None
1880
2112
  if node is None:
1881
2113
  pass
1882
2114
  # when getting the prev node, we calculate the
1883
- if hasattr(node, 'expression_inputs') and len(node.expression_inputs) > 0:
2115
+ if hasattr(node, "expression_inputs") and len(node.expression_inputs) > 0:
1884
2116
  expression_inputs = node.expression_inputs
1885
2117
  expression_inputs = clean_or_list(expression_inputs)
1886
2118
  else:
1887
- expression_inputs = []
2119
+ expression_inputs = []
1888
2120
  prev_activities = {}
1889
2121
  for prev_node in node.prev_nodes:
1890
2122
  if prev_node.activity.id not in prev_activities:
1891
- prev_activities[prev_node.activity.id]=[]
2123
+ prev_activities[prev_node.activity.id] = []
1892
2124
  prev_activities[prev_node.activity.id].append(prev_node)
1893
-
2125
+
1894
2126
  for act_id in prev_activities:
1895
2127
  act_expression_inputs = []
1896
2128
  for prev_node in prev_activities[act_id]:
1897
- if excluded_name is None or prev_node != excluded_name or (
1898
- isinstance(excluded_name, str) and hasattr(prev_node, 'name') and prev_node.name != excluded_name): # or isinstance(prev_node, TriccNodeActivityEnd):
2129
+ if (
2130
+ excluded_name is None
2131
+ or prev_node != excluded_name
2132
+ or (
2133
+ # or isinstance(prev_node, TriccNodeActivityEnd):
2134
+ isinstance(excluded_name, str)
2135
+ and hasattr(prev_node, "name")
2136
+ and prev_node.name != excluded_name
2137
+ )
2138
+ ):
1899
2139
  # the rhombus should calculate only reference
1900
2140
  sub = get_node_expression(
1901
2141
  prev_node,
1902
2142
  processed_nodes=processed_nodes,
1903
2143
  get_overall_exp=get_overall_exp,
1904
2144
  is_prev=True,
1905
- process=process)
1906
- if isinstance(node, TriccNodeActivity) or get_overall_exp:
1907
- add_sub_expression(act_expression_inputs, sub )
2145
+ process=process,
2146
+ )
2147
+ if isinstance(node, TriccNodeActivity) or get_overall_exp:
2148
+ add_sub_expression(act_expression_inputs, sub)
1908
2149
  else:
1909
- add_sub_expression(expression_inputs, sub )
1910
-
2150
+ add_sub_expression(expression_inputs, sub)
2151
+
1911
2152
  if act_expression_inputs:
1912
2153
  act_sub = or_join(act_expression_inputs)
1913
- if act_sub == TriccStatic(True):
1914
- act_sub = get_node_expression(
2154
+ if act_sub == TriccStatic(True):
2155
+ act_sub = get_node_expression(
1915
2156
  prev_node.activity,
1916
2157
  processed_nodes=processed_nodes,
1917
2158
  get_overall_exp=True,
1918
2159
  is_prev=True,
1919
2160
  negate=False,
1920
- process=process
2161
+ process=process,
1921
2162
  )
1922
- add_sub_expression(expression_inputs, act_sub )
2163
+ add_sub_expression(expression_inputs, act_sub)
1923
2164
  # avoid void is there is not conditions to avoid looping too much itme
1924
2165
  # expression_inputs = clean_or_list(
1925
2166
  # [
1926
- # get_tricc_operation_operand(e)
1927
- # if isinstance(expression, TriccOperation)
1928
- # else e
2167
+ # get_tricc_operation_operand(e)
2168
+ # if isinstance(expression, TriccOperation)
2169
+ # else e
1929
2170
  # for e in expression_inputs])
1930
-
2171
+
1931
2172
  if expression_inputs:
1932
- expression = or_join(
1933
- expression_inputs
1934
- )
2173
+ expression = or_join(expression_inputs)
1935
2174
  # if isinstance(node, TriccNodeExclusive):
1936
2175
  # expression = TRICC_NEGATE.format(expression)
1937
- # only used for activityStart
2176
+ # only used for activityStart
1938
2177
  else:
1939
2178
  expression = TriccStatic(True)
1940
2179
  return expression
1941
2180
 
1942
- def get_activity_end_terms( node, processed_nodes, process=None):
2181
+
2182
+ def get_activity_end_terms(node, processed_nodes, process=None):
1943
2183
  end_nodes = node.get_end_nodes()
1944
2184
  expression_inputs = []
1945
2185
  for end_node in end_nodes:
1946
2186
  add_sub_expression(
1947
2187
  expression_inputs,
1948
2188
  get_node_expression(
1949
- end_node,
1950
- processed_nodes=processed_nodes,
1951
- get_overall_exp=False,
1952
- is_prev=True,
1953
- process=process))
2189
+ end_node, processed_nodes=processed_nodes, get_overall_exp=False, is_prev=True, process=process
2190
+ ),
2191
+ )
2192
+
2193
+ return or_join(expression_inputs)
1954
2194
 
1955
- return or_join(expression_inputs)
1956
2195
 
1957
- def get_count_terms( node, processed_nodes, get_overall_exp, negate=False, process=None):
2196
+ def get_count_terms(node, processed_nodes, get_overall_exp, negate=False, process=None):
1958
2197
  terms = []
1959
-
2198
+
1960
2199
  for prev_node in node.prev_nodes:
1961
- term = get_count_terms_details( prev_node, processed_nodes, get_overall_exp, negate, process)
2200
+ term = get_count_terms_details(prev_node, processed_nodes, get_overall_exp, negate, process)
1962
2201
  if term:
1963
2202
  terms.append(term)
1964
2203
  if len(terms) == 1:
1965
- return TriccOperation(
1966
- TriccOperator.CAST_NUMBER,
1967
- [terms[0]]
1968
- )
2204
+ return TriccOperation(TriccOperator.CAST_NUMBER, [terms[0]])
1969
2205
  elif len(terms) > 0:
1970
- return TriccOperation(
1971
- TriccOperator.PLUS,
1972
- [
1973
- TriccOperation(
1974
- TriccOperator.CAST_NUMBER,
1975
- [term]
1976
- ) for term in terms
1977
- ]
1978
- )
1979
-
1980
- def get_count_terms_details( prev_node, processed_nodes, get_overall_exp, negate=False, process=None):
1981
- operation_none = TriccOperation(
1982
- TriccOperator.SELECTED,
1983
- [
1984
- prev_node,
1985
- TriccStatic('opt_none')
1986
- ]
1987
- )
1988
- if isinstance(prev_node, TriccNodeSelectYesNo):
2206
+ return TriccOperation(TriccOperator.PLUS, [TriccOperation(TriccOperator.CAST_NUMBER, [term]) for term in terms])
2207
+
2208
+
2209
+ def get_count_terms_details(prev_node, processed_nodes, get_overall_exp, negate=False, process=None):
2210
+ operation_none = TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic("opt_none")])
2211
+ if isinstance(prev_node, TriccNodeSelectYesNo):
2212
+ return TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic(prev_node.options[0].name)])
2213
+ elif issubclass(prev_node.__class__, TriccNodeSelect):
2214
+ if negate:
2215
+ return
2216
+ # terms.append(TRICC_SELECT_MULTIPLE_CALC_NONE_EXPRESSION.format(get_export_name(prev_node)))
2217
+ else:
1989
2218
  return TriccOperation(
1990
- TriccOperator.SELECTED,
2219
+ TriccOperator.MINUS,
1991
2220
  [
1992
- prev_node,
1993
- TriccStatic(prev_node.options[0].name)
1994
- ]
2221
+ TriccOperation(TriccOperator.COUNT, [prev_node]),
2222
+ TriccOperation(TriccOperator.CAST_NUMBER, [operation_none]),
2223
+ ],
1995
2224
  )
1996
- elif issubclass(prev_node.__class__, TriccNodeSelect):
1997
- if negate:
1998
- return
1999
- #terms.append(TRICC_SELECT_MULTIPLE_CALC_NONE_EXPRESSION.format(get_export_name(prev_node)))
2000
- else:
2001
- return TriccOperation(
2002
- TriccOperator.MINUS,
2003
- [
2004
- TriccOperation(
2005
- TriccOperator.NATIVE,
2006
- [
2007
- 'count-selected',
2008
- prev_node
2009
- ]
2010
- ),TriccOperation(
2011
- TriccOperator.CAST_NUMBER,
2012
- [
2013
- operation_none
2014
- ]
2015
- )
2016
- ])
2017
- #terms.append(TRICC_SELECT_MULTIPLE_CALC_EXPRESSION.format(get_export_name(prev_node)))
2018
- elif isinstance(prev_node, (TriccNodeSelectNotAvailable)):
2225
+ # terms.append(TRICC_SELECT_MULTIPLE_CALC_EXPRESSION.format(get_export_name(prev_node)))
2226
+ elif isinstance(prev_node, (TriccNodeSelectNotAvailable)):
2227
+ return TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic("1")])
2228
+ # terms.append(TRICC_SELECTED_EXPRESSION.format(get_export_name(prev_node), '1'))
2229
+ elif isinstance(prev_node, TriccNodeSelectOption):
2230
+ return get_selected_option_expression(prev_node, negate)
2231
+ else:
2232
+ if negate:
2019
2233
  return TriccOperation(
2020
- TriccOperator.SELECTED,
2234
+ TriccOperator.CAST_NUMBER,
2021
2235
  [
2022
- prev_node,
2023
- TriccStatic('1')
2024
- ]
2025
- )
2026
- #terms.append(TRICC_SELECTED_EXPRESSION.format(get_export_name(prev_node), '1'))
2027
- elif isinstance(prev_node, TriccNodeSelectOption):
2028
- return get_selected_option_expression(prev_node, negate)
2029
- else:
2030
- if negate:
2031
- return TriccOperation(
2032
- TriccOperator.CAST_NUMBER,
2236
+ TriccOperation(
2237
+ TriccOperator.NATIVE,
2033
2238
  [
2034
2239
  TriccOperation(
2035
- TriccOperator.NATIVE,
2240
+ TriccOperator.CAST_NUMBER,
2036
2241
  [
2037
- TriccOperation(
2038
- TriccOperator.CAST_NUMBER,
2039
- [
2040
- get_node_expression(
2041
- prev_node,
2042
- processed_nodes=processed_nodes,
2043
- get_overall_exp=True,
2044
- is_prev=True,
2045
- process=process)
2046
- ]),
2047
- TriccStatic('0')
2048
- ]
2049
- )
2050
- ]
2242
+ get_node_expression(
2243
+ prev_node,
2244
+ processed_nodes=processed_nodes,
2245
+ get_overall_exp=True,
2246
+ is_prev=True,
2247
+ process=process,
2248
+ )
2249
+ ],
2250
+ ),
2251
+ TriccStatic("0"),
2252
+ ],
2051
2253
  )
2052
-
2053
- else:
2054
- return TriccOperation(
2055
- TriccOperator.CAST_NUMBER,
2056
- [
2057
- get_node_expression(
2058
- prev_node,
2059
- processed_nodes=processed_nodes,
2060
- get_overall_exp=True,
2061
- is_prev=True,
2062
- process=process)
2063
- ]
2254
+ ],
2255
+ )
2256
+
2257
+ else:
2258
+ return TriccOperation(
2259
+ TriccOperator.CAST_NUMBER,
2260
+ [
2261
+ get_node_expression(
2262
+ prev_node, processed_nodes=processed_nodes, get_overall_exp=True, is_prev=True, process=process
2064
2263
  )
2065
-
2066
-
2067
-
2068
- def get_add_terms( node, processed_nodes, get_overall_exp=False, negate=False, process=None):
2264
+ ],
2265
+ )
2266
+
2267
+
2268
+ def get_add_terms(node, processed_nodes, get_overall_exp=False, negate=False, process=None):
2069
2269
  if negate:
2070
2270
  logger.warning("negate not supported for Add node {}".format(node.get_name()))
2071
2271
  terms = []
2072
2272
  for prev_node in node.prev_nodes:
2073
2273
  if issubclass(prev_node, TriccNodeNumber) or isinstance(node, TriccNodeCount):
2074
- terms.append(
2075
- TriccOperation(
2076
- TriccOperator.COALESCE,
2077
- [
2078
- prev_node,
2079
- TriccStatic(0)
2080
- ]
2081
- )
2082
- )
2274
+ terms.append(TriccOperation(TriccOperator.COALESCE, [prev_node, TriccStatic(0)]))
2083
2275
  else:
2084
2276
  terms.append(
2085
2277
  TriccOperation(
@@ -2089,33 +2281,28 @@ def get_add_terms( node, processed_nodes, get_overall_exp=False, negate=False, p
2089
2281
  prev_node,
2090
2282
  processed_nodes=processed_nodes,
2091
2283
  get_overall_exp=True,
2092
- is_prev=True,
2093
- process=process)
2094
- ]
2284
+ is_prev=True,
2285
+ process=process,
2286
+ )
2287
+ ],
2095
2288
  )
2096
2289
  )
2097
2290
  if len(terms) > 0:
2098
2291
  operation = terms[0]
2099
2292
  if len(terms) > 1:
2100
2293
  for term in terms[1:]:
2101
- operation = TriccOperation(
2102
- TriccOperator.ADD,
2103
- [
2104
- operation,
2105
- term
2106
- ]
2107
- )
2294
+ operation = TriccOperation(TriccOperator.ADD, [operation, term])
2108
2295
  return operation
2109
-
2110
- def get_rhombus_terms( node, processed_nodes, get_overall_exp=False, negate=False, process=None):
2296
+
2297
+
2298
+ def get_rhombus_terms(node, processed_nodes, get_overall_exp=False, negate=False, process=None):
2111
2299
  expression = None
2112
2300
  left_term = None
2113
- operator = None
2114
2301
  if node.reference is not None:
2115
2302
  if isinstance(node.reference, set):
2116
2303
  node.reference = list(node.reference)
2117
2304
  # calcualte the expression only for select muzltiple and fake calculate
2118
- if issubclass(node.reference.__class__, (list,OrderedSet)):
2305
+ if issubclass(node.reference.__class__, (list, OrderedSet)):
2119
2306
  if node.expression_reference is None and len(node.reference) == 1:
2120
2307
  ref = node.reference[0]
2121
2308
  if issubclass(ref.__class__, TriccNodeBaseModel):
@@ -2123,81 +2310,79 @@ def get_rhombus_terms( node, processed_nodes, get_overall_exp=False, negate=Fals
2123
2310
  expression = get_activity_end_terms(ref, processed_nodes, process=process)
2124
2311
  elif issubclass(ref.__class__, TriccNodeFakeCalculateBase):
2125
2312
  expression = get_node_expression(
2126
- ref,
2127
- processed_nodes=processed_nodes,
2128
- get_overall_exp=True,
2129
- is_prev=True,
2130
- process=process
2313
+ ref, processed_nodes=processed_nodes, get_overall_exp=True, is_prev=True, process=process
2131
2314
  )
2132
2315
  else:
2133
2316
  expression = ref
2134
2317
  elif issubclass(ref.__class__, TriccReference):
2135
2318
  expression = ref
2136
2319
  else:
2137
- logger.critical('reference {0} was not found in the previous nodes of node {1}'.format(node.reference,
2138
- node.get_name()))
2320
+ logger.critical(
2321
+ "reference {0} was not found in the previous nodes of node {1}".format(
2322
+ node.reference, node.get_name()
2323
+ )
2324
+ )
2139
2325
  exit(1)
2140
- elif node.expression_reference is not None and node.expression_reference != '':
2326
+ elif node.expression_reference is not None and node.expression_reference != "":
2141
2327
  if isinstance(node.expression_reference, (TriccOperation, TriccReference, TriccStatic)):
2142
2328
  return node.expression_reference
2143
2329
  elif isinstance(node.expression_reference, str):
2144
2330
  expression = node.expression_reference.format(*get_list_names(node.reference))
2145
2331
  else:
2146
- logger.critical('expression_reference {0} unsuported type {1}'.format(node.expression_reference, node.expression_reference.__class__.__name__))
2332
+ logger.critical(
2333
+ "expression_reference {0} unsuported type {1}".format(
2334
+ node.expression_reference, node.expression_reference.__class__.__name__
2335
+ )
2336
+ )
2147
2337
  exit(1)
2148
2338
 
2149
2339
  else:
2150
2340
  logger.warning("missing expression for node {}".format(node.get_name()))
2151
2341
  else:
2152
- logger.critical('reference {0} is not a list {1}'.format(node.reference, node.get_name()))
2342
+ logger.critical("reference {0} is not a list {1}".format(node.reference, node.get_name()))
2153
2343
  exit(1)
2154
2344
  else:
2155
- logger.critical('reference empty for Rhombis {}'.format( node.get_name()))
2345
+ logger.critical("reference empty for Rhombis {}".format(node.get_name()))
2156
2346
  exit(1)
2157
2347
 
2158
2348
  if expression is not None:
2159
2349
  if isinstance(expression, (TriccOperation, TriccStatic)):
2160
2350
  return expression
2161
- elif issubclass(expression.__class__ , TriccNodeCalculateBase):
2351
+ elif issubclass(expression.__class__, TriccNodeCalculateBase):
2162
2352
  return TriccOperation(
2163
2353
  TriccOperator.CAST_NUMBER,
2164
2354
  [
2165
2355
  get_node_expression(
2166
- expression,
2167
- processed_nodes=processed_nodes,
2168
- get_overall_exp=True,
2169
- is_prev=True,
2170
- process=process
2356
+ expression, processed_nodes=processed_nodes, get_overall_exp=True, is_prev=True, process=process
2171
2357
  )
2172
- ])
2173
- elif issubclass(expression.__class__ , (TriccOperation) ):
2174
- return expression
2175
- elif issubclass(expression.__class__ , (TriccNodeDisplayModel, TriccReference)):
2176
- return TriccOperation(
2177
- TriccOperator.ISTRUE,
2178
- [
2179
- expression
2180
- ]
2358
+ ],
2181
2359
  )
2360
+ elif issubclass(expression.__class__, (TriccOperation)):
2361
+ return expression
2362
+ elif issubclass(expression.__class__, (TriccNodeDisplayModel, TriccReference)):
2363
+ return TriccOperation(TriccOperator.ISTRUE, [expression])
2182
2364
  else:
2183
2365
  if left_term is not None and re.search(" (+)|(-)|(or)|(and) ", expression):
2184
2366
  expression = "({0}){1}".format(expression, left_term)
2185
2367
  else:
2186
2368
  expression = "{0}{1}".format(expression, left_term)
2187
2369
  else:
2188
- logger.critical("Rhombus reference was not found for node {}, reference {}".format(
2189
- node.get_name(),
2190
- node.reference
2191
- ))
2370
+ logger.critical(
2371
+ "Rhombus reference was not found for node {}, reference {}".format(node.get_name(), node.reference)
2372
+ )
2192
2373
  exit(1)
2193
2374
 
2194
2375
  return expression
2376
+
2377
+
2195
2378
  # function that generate the calculation terms return by calculate node
2196
2379
  # @param node calculate node to assess
2197
2380
  # @param processed_nodes list of node already processed, importnat because only processed node could be use
2198
2381
  # @param get_overall_exp used when this funciton is called in the evaluation of another calculate
2199
2382
  # @param negate use to retriece the negation of a calculation
2200
- def get_calculation_terms( node, processed_nodes, get_overall_exp=False, negate=False, process=None):
2383
+
2384
+
2385
+ def get_calculation_terms(node, processed_nodes, get_overall_exp=False, negate=False, process=None):
2201
2386
  # returns something directly only if the negate is managed
2202
2387
  expression = None
2203
2388
  if isinstance(node, TriccNodeAdd):
@@ -2206,22 +2391,25 @@ def get_calculation_terms( node, processed_nodes, get_overall_exp=False, negate=
2206
2391
  return get_count_terms(node, False, negate, process=process)
2207
2392
  elif isinstance(node, TriccNodeRhombus):
2208
2393
  return get_rhombus_terms(
2209
- node,
2210
- processed_nodes=processed_nodes,
2211
- get_overall_exp=False,
2212
- negate=negate,
2213
- process=process
2394
+ node, processed_nodes=processed_nodes, get_overall_exp=False, negate=negate, process=process
2214
2395
  )
2215
- elif isinstance(node, ( TriccNodeWait)):
2396
+ elif isinstance(node, (TriccNodeWait)):
2216
2397
  # just use to force order of question
2217
2398
  expression = None
2218
- # in case of calulate expression evaluation, we need to get the relevance of the activity
2399
+ # in case of calulate expression evaluation, we need to get the relevance of the activity
2219
2400
  # because calculate are not the the activity group
2220
2401
  elif isinstance(node, (TriccNodeActivityStart)) and get_overall_exp:
2221
- expression = get_prev_node_expression(node.activity, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, negate=negate, process=process)
2402
+ expression = get_prev_node_expression(
2403
+ node.activity,
2404
+ processed_nodes=processed_nodes,
2405
+ get_overall_exp=get_overall_exp,
2406
+ negate=negate,
2407
+ process=process,
2408
+ )
2222
2409
  elif isinstance(node, (TriccNodeActivityStart, TriccNodeActivityEnd)):
2223
2410
  # the group have the relevance for the activity, not needed to replicate it
2224
- expression = None #return get_prev_node_expression(node.activity, processed_nodes, get_overall_exp=False, excluded_name=None)
2411
+ # return get_prev_node_expression(node.activity, processed_nodes, get_overall_exp=False, excluded_name=None)
2412
+ expression = None
2225
2413
  elif isinstance(node, TriccNodeExclusive):
2226
2414
  if len(node.prev_nodes) == 1:
2227
2415
  iterator = iter(node.prev_nodes)
@@ -2236,8 +2424,8 @@ def get_calculation_terms( node, processed_nodes, get_overall_exp=False, negate=
2236
2424
  get_overall_exp=True,
2237
2425
  is_prev=True,
2238
2426
  negate=True,
2239
- process=process
2240
- )
2427
+ process=process,
2428
+ )
2241
2429
  elif isinstance(node_to_negate, TriccNodeActivity):
2242
2430
  return get_node_expression(
2243
2431
  node_to_negate,
@@ -2245,36 +2433,45 @@ def get_calculation_terms( node, processed_nodes, get_overall_exp=False, negate=
2245
2433
  get_overall_exp=True,
2246
2434
  is_prev=True,
2247
2435
  negate=True,
2248
- process=process
2436
+ process=process,
2249
2437
  )
2250
2438
  else:
2251
- logger.critical(f"exclusive node {node.get_name()}\
2439
+ logger.critical(
2440
+ f"exclusive node {node.get_name()}\
2252
2441
  does not depend of a calculate but on\
2253
- {node_to_negate.__class__}::{node_to_negate.get_name()}")
2442
+ {node_to_negate.__class__}::{node_to_negate.get_name()}"
2443
+ )
2254
2444
 
2255
2445
  else:
2256
2446
  logger.critical("exclusive node {} has no ou too much parent".format(node.get_name()))
2257
-
2447
+
2258
2448
  if isinstance(node.expression_reference, (TriccOperation, TriccStatic)):
2259
2449
  expression = node.expression_reference
2260
- elif node.reference is not None and node.expression_reference is not None :
2261
- expression = get_prev_node_expression(node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process)
2450
+ elif node.reference is not None and node.expression_reference is not None:
2451
+ expression = get_prev_node_expression(
2452
+ node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process
2453
+ )
2262
2454
  ref_expression = node.expression_reference.format(*[get_export_name(ref) for ref in node.reference])
2263
- if expression is not None and expression != '':
2264
- expression = and_join([expression,ref_expression])
2455
+ if expression is not None and expression != "":
2456
+ expression = and_join([expression, ref_expression])
2265
2457
  else:
2266
2458
  expression = ref_expression
2267
2459
  elif expression is None:
2268
- expression = get_prev_node_expression(node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process)
2269
-
2460
+ expression = get_prev_node_expression(
2461
+ node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process
2462
+ )
2463
+
2270
2464
  # manage the generic negation
2271
2465
  if negate:
2272
-
2466
+
2273
2467
  return negate_term(expression)
2274
2468
  else:
2275
2469
  return expression
2276
-
2470
+
2471
+
2277
2472
  # Function that add element to array is not None or ''
2473
+
2474
+
2278
2475
  def add_sub_expression(array, sub):
2279
2476
  if isinstance(sub, (TriccOperation, TriccStatic)):
2280
2477
  not_sub = negate_term(sub)
@@ -2288,62 +2485,146 @@ def add_sub_expression(array, sub):
2288
2485
  pass
2289
2486
  # elif sub is None:
2290
2487
  # array.append(TriccStatic(True))
2291
-
2292
-
2293
2488
 
2294
2489
  # function that negate terms
2490
+
2491
+
2295
2492
  # @param expression to negate
2296
- def negate_term(expression):
2297
-
2298
- return not_clean(expression)
2299
2493
 
2300
2494
 
2495
+ def negate_term(expression):
2496
+
2497
+ return not_clean(expression)
2301
2498
 
2302
2499
 
2303
2500
  # if the node is "required" then we can take the fact that it has value for the next elements
2304
2501
  def get_required_node_expression(node):
2305
- return TriccOperation(
2306
- operator=TriccOperator.EXISTS,
2307
- reference=[
2308
- node
2309
- ]
2310
- )
2502
+ return TriccOperation(operator=TriccOperator.EXISTS, reference=[node])
2311
2503
 
2312
2504
 
2313
2505
  # Get a selected option
2314
2506
  def get_selected_option_expression(option_node, negate):
2315
-
2316
- selected = TriccOperation(
2317
- TriccOperator.SELECTED,
2318
- [
2319
- option_node.select,
2320
- TriccStatic(option_node.name)
2321
- ]
2322
- )
2323
-
2507
+ if isinstance(option_node.select, TriccNodeSelectOne):
2508
+ return get_selected_option_expression_single(option_node, negate)
2509
+ else:
2510
+ return get_selected_option_expression_multiple(option_node, negate)
2511
+
2512
+
2513
+ def get_selected_option_expression_single(option_node, negate):
2514
+
2515
+ if not negate:
2516
+ return TriccOperation(TriccOperator.EQUAL, [option_node.select, option_node])
2517
+
2518
+
2519
+ def get_selected_option_expression_multiple(option_node, negate):
2520
+
2521
+ selected = TriccOperation(TriccOperator.SELECTED, [option_node.select, option_node])
2522
+
2324
2523
  if negate:
2325
2524
  return TriccOperation(
2326
2525
  operator=TriccOperator.AND,
2327
2526
  resource=[
2328
- TriccOperation(
2329
- operator=TriccOperator.NOT,
2330
- resource=[
2331
- selected
2332
- ]
2333
- ),TriccOperation(
2334
- operator=TriccOperator.NATIVE,
2335
- resource=[
2336
- 'count-selected',
2337
- option_node.select
2338
- ]
2339
- )
2340
- ])
2341
-
2527
+ TriccOperation(operator=TriccOperator.NOT, resource=[selected]),
2528
+ TriccOperation(operator=TriccOperator.ISNOTNULL, resource=[option_node.select]),
2529
+ ],
2530
+ )
2531
+
2342
2532
  else:
2343
2533
  return selected
2344
2534
 
2345
2535
 
2346
-
2536
+ def generate_calculate(node, processed_nodes, **kwargs):
2537
+ # For calculations, set calculate in questionOptions
2538
+ # Check if node is ready to be processed (similar to XLS form strategy)
2539
+ if not is_ready_to_process(node, processed_nodes, strict=True):
2540
+ return False
2541
+
2542
+ # Process references to ensure dependencies are handled
2543
+ if not process_reference(
2544
+ node, processed_nodes, {}, replace_reference=True, codesystems=kwargs.get("codesystems", None)
2545
+ ):
2546
+ return False
2547
+
2548
+ if node not in processed_nodes:
2549
+ if kwargs.get("warn", True):
2550
+ logger.debug("generation of calculate for node {}".format(node.get_name()))
2551
+ if (
2552
+ hasattr(node, "expression")
2553
+ and (node.expression is None)
2554
+ and issubclass(node.__class__, TriccNodeCalculateBase)
2555
+ ):
2556
+ node.expression = get_node_expressions(
2557
+ node, processed_nodes, process=kwargs.get("process", "main ")
2558
+ )
2559
+ # continue walk
2560
+ if issubclass(
2561
+ node.__class__,
2562
+ (
2563
+ TriccNodeDisplayModel,
2564
+ TriccNodeDisplayCalculateBase,
2565
+ TriccNodeEnd,
2566
+ ),
2567
+ ):
2568
+ set_last_version_false(node, processed_nodes)
2569
+ return True
2347
2570
 
2348
2571
 
2572
+ def generate_base(node, processed_nodes, **kwargs):
2573
+ # Generate question for OpenMRS O3 schema
2574
+ # Handle activity nodes by processing their inner content
2575
+ # Check if node is ready to be processed (similar to XLS form strategy)
2576
+ if not is_ready_to_process(node, processed_nodes, strict=False):
2577
+ return False
2349
2578
 
2579
+ # Process references to ensure dependencies are handled
2580
+ if not process_reference(
2581
+ node, processed_nodes, {}, replace_reference=False, codesystems=kwargs.get("codesystems", None)
2582
+ ):
2583
+ return False
2584
+ if node not in processed_nodes:
2585
+ if issubclass(node.__class__, TriccRhombusMixIn) and isinstance(node.reference, str):
2586
+ logger.warning("node {} still using the reference string".format(node.get_name()))
2587
+ if issubclass(node.__class__, TriccNodeInputModel):
2588
+ # we don't overright if define in the diagram
2589
+ if node.constraint is None:
2590
+ if isinstance(node, TriccNodeSelectMultiple):
2591
+ node.constraint = or_join(
2592
+ [
2593
+ TriccOperation(
2594
+ TriccOperator.EQUAL,
2595
+ ["$this", TriccStatic("opt_none")],
2596
+ ),
2597
+ TriccOperation(
2598
+ TriccOperator.NOT,
2599
+ [
2600
+ TriccOperation(
2601
+ TriccOperator.SELECTED,
2602
+ ["$this", TriccStatic("opt_none")],
2603
+ )
2604
+ ],
2605
+ ),
2606
+ ]
2607
+ ) # '.=\'opt_none\' or not(selected(.,\'opt_none\'))'
2608
+ node.constraint_message = "**None** cannot be selected together with choice."
2609
+ elif node.tricc_type in (
2610
+ TriccNodeType.integer,
2611
+ TriccNodeType.decimal,
2612
+ ):
2613
+ constraints = []
2614
+ constraints_min = ""
2615
+ constraints_max = ""
2616
+ if node.min is not None and node.min != "":
2617
+ constraints.append(TriccOperation(TriccOperator.MORE_OR_EQUAL, ["$this", node.min]))
2618
+ constraints_min = "The minimun value is {0}.".format(node.min)
2619
+ if node.max is not None and node.max != "":
2620
+ constraints.append(TriccOperation(TriccOperator.LESS_OR_EQUAL, ["$this", node.max]))
2621
+ constraints_max = "The maximum value is {0}.".format(node.max)
2622
+ if len(constraints) > 1:
2623
+ node.constraint = TriccOperation(TriccOperator.AND, constraints)
2624
+ node.constraint_message = (constraints_min + " " + constraints_max).strip()
2625
+ elif len(constraints) == 1:
2626
+ node.constraint = constraints[0]
2627
+ node.constraint_message = (constraints_min + " " + constraints_max).strip()
2628
+ # continue walk
2629
+ return True
2630
+ return False