tricc-oo 1.6.26__py3-none-any.whl → 1.7.0.dev1__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.
@@ -56,9 +56,6 @@ from tricc_oo.converters.tricc_to_xls_form import get_list_names, get_export_nam
56
56
  logger = logging.getLogger("default")
57
57
  ONE_QUESTION_AT_A_TIME = False
58
58
 
59
- # Track the last group that was reordered to avoid unnecessary reordering
60
- _last_reordered_group = None
61
-
62
59
 
63
60
  def merge_node(from_node, to_node):
64
61
  if from_node.activity != to_node.activity:
@@ -124,10 +121,7 @@ def get_last_version(name, processed_nodes, _list=None):
124
121
  # node is the node to calculate
125
122
  # processed_nodes are the list of processed nodes
126
123
  def get_node_expressions(node, processed_nodes, process=None):
127
- get_overall_exp = issubclass(
128
- node.__class__,
129
- (TriccNodeDisplayCalculateBase, TriccNodeProposedDiagnosis, TriccNodeDiagnosis)
130
- ) and not isinstance(node, (TriccNodeDisplayBridge))
124
+ get_overall_exp = issubclass(node.__class__, (TriccNodeDisplayCalculateBase, TriccNodeProposedDiagnosis, TriccNodeDiagnosis)) and not isinstance(node, (TriccNodeDisplayBridge))
131
125
  expression = None
132
126
  # in case of recursive call processed_nodes will be None
133
127
  if processed_nodes is None or is_ready_to_process(node, processed_nodes=processed_nodes):
@@ -158,25 +152,19 @@ def set_last_version_false(node, processed_nodes):
158
152
  return last_version
159
153
 
160
154
 
161
- def get_version_inheritance(node, all_prev_versions, processed_nodes):
162
-
163
- # Updated to merge ALL previous versions, not just the last one
164
- # This ensures inheritance works even when intermediate activities weren't triggered
165
-
155
+ def get_version_inheritance(node, last_version, processed_nodes):
156
+ # FIXME this is for XLS form where only calculate are evaluated
157
+ # for a activity that is not triggered
166
158
  if not issubclass(node.__class__, (TriccNodeInputModel)):
167
159
  node.last = True
168
160
  if issubclass(node.__class__, (TriccNodeDisplayCalculateBase, TriccNodeEnd)) and node.name is not None:
169
161
  # logger.debug("set last to false for node {}
170
162
  # and add its link it to next one".format(last_used_calc.get_name()))
171
163
  if node.prev_nodes:
172
- # Set prev_next_node only with the immediate last version
173
- for pv in all_prev_versions:
174
- set_prev_next_node(pv, node)
164
+ set_prev_next_node(last_version, node)
175
165
  else:
176
166
  expression = node.expression or node.expression_reference or getattr(node, "relevance", None)
177
- # Merge with ALL previous versions, not just the last one
178
- if all_prev_versions:
179
- expression = merge_expressions(expression, *all_prev_versions)
167
+ expression = merge_expression(expression, last_version)
180
168
  if node.expression:
181
169
  node.expression = expression
182
170
  elif node.expression_reference:
@@ -185,25 +173,21 @@ def get_version_inheritance(node, all_prev_versions, processed_nodes):
185
173
  node.relevance = expression
186
174
  else:
187
175
  node.last = False
188
-
189
- # Create a calculate node that coalesces all previous saved values with the current node value
190
- calc_id = generate_id(f"save_{node.save}")
191
-
192
- # Build reference list with current node and all previous versions
193
- reference_list = [node] + (all_prev_versions if all_prev_versions else [])
194
176
 
177
+ # Create a calculate node that coalesces the previous saved value with the current node value
178
+ calc_id = generate_id(f"save_{node.save}")
195
179
  calc = TriccNodeCalculate(
196
180
  id=calc_id,
197
181
  name=node.save,
198
182
  path_len=node.path_len + 1,
199
183
  expression_reference=TriccOperation(
200
184
  TriccOperator.COALESCE,
201
- reference_list,
185
+ [TriccReference(node.save), last_version],
202
186
  ),
203
- reference=reference_list,
187
+ reference=[TriccReference(n.name)],
204
188
  activity=node.activity,
205
189
  group=node.group,
206
- label=f"Save calculation for {node.label}",
190
+ label=f"Save calculation for {n.label}",
207
191
  last=True,
208
192
  )
209
193
  node.activity.nodes[calc.id] = calc
@@ -211,20 +195,18 @@ def get_version_inheritance(node, all_prev_versions, processed_nodes):
211
195
  # set_last_version_false(calc, processed_nodes)
212
196
  processed_nodes.add(calc)
213
197
  if issubclass(node.__class__, TriccNodeInputModel):
214
- # Coalesce with all previous versions
215
- coalesce_operands = ["$this"] + (all_prev_versions if all_prev_versions else [])
216
- node.expression = TriccOperation(TriccOperator.COALESCE, coalesce_operands)
198
+ node.expression = TriccOperation(TriccOperator.COALESCE, ["$this", last_version])
217
199
 
218
200
 
219
- def merge_expressions(expression, last_version, *argv):
201
+ def merge_expression(expression, last_version):
220
202
  datatype = expression.get_datatype()
221
203
  if datatype == "boolean":
222
- expression = or_join([TriccOperation(TriccOperator.ISTRUE, [last_version, *argv]), expression])
204
+ expression = or_join([TriccOperation(TriccOperator.ISTRUE, [last_version]), expression])
223
205
 
224
206
  elif datatype == "number":
225
- expression = TriccOperation(TriccOperator.PLUS, [last_version, *argv, expression])
207
+ expression = TriccOperation(TriccOperator.PLUS, [last_version, expression])
226
208
  else:
227
- expression = TriccOperation(TriccOperator.COALESCE, [expression, last_version, *argv])
209
+ expression = TriccOperation(TriccOperator.COALESCE, [last_version, expression])
228
210
  return expression
229
211
 
230
212
 
@@ -251,14 +233,8 @@ def load_calculate(
251
233
  # tricc diagnostic have the same name as proposed diag but will be serialised with different names
252
234
 
253
235
  last_version = set_last_version_false(node, processed_nodes)
254
- # Get all previous versions from processed_nodes, not just the last one
255
- node_name = node.name if not isinstance(node, TriccNodeEnd) else node.get_reference()
256
- all_prev_versions = get_versions(node_name, processed_nodes)
257
- # Exclude the current node itself
258
- all_prev_versions = [v for v in all_prev_versions if v != node]
259
-
260
236
  if last_version:
261
- get_version_inheritance(node, all_prev_versions, processed_nodes)
237
+ last_version = get_version_inheritance(node, last_version, processed_nodes)
262
238
 
263
239
  generate_calculates(node, calculates, used_calculates, processed_nodes=processed_nodes, process=process)
264
240
 
@@ -426,11 +402,6 @@ def get_bridge_path(prev_nodes, node=None, edge_only=False):
426
402
  calc = TriccNodeDisplayBridge(**data)
427
403
  else:
428
404
  calc = TriccNodeBridge(**data)
429
- if node:
430
- priority = getattr(node, 'priority', None)
431
- if priority:
432
- calc.priority = priority
433
-
434
405
  return calc
435
406
 
436
407
 
@@ -558,7 +529,7 @@ def generate_calculates(node, calculates, used_calculates, processed_nodes, proc
558
529
  node.activity.calculates.append(calc_node)
559
530
  last_version = set_last_version_false(calc_node, processed_nodes)
560
531
  if last_version:
561
- calc_node.expression = merge_expressions(calc_node.expression, last_version)
532
+ calc_node.expression = merge_expression(calc_node.expression, last_version)
562
533
  processed_nodes.add(calc_node)
563
534
  logger.debug(
564
535
  "generate_save_calculate:{}:{} as {}".format(
@@ -591,7 +562,7 @@ def generate_calculates(node, calculates, used_calculates, processed_nodes, proc
591
562
  node.activity.calculates.append(calc_node)
592
563
  last_version = set_last_version_false(calc_node, processed_nodes)
593
564
  if last_version:
594
- calc_node.expression = merge_expressions(calc_node.expression, last_version)
565
+ calc_node.expression = merge_expression(calc_node.expression, last_version)
595
566
  processed_nodes.add(calc_node)
596
567
  list_calc.append(calc_node)
597
568
  node.activity.nodes[calc_node.id] = calc_node
@@ -831,7 +802,7 @@ def process_operation_reference(
831
802
  operation,
832
803
  node,
833
804
  processed_nodes,
834
- calculates=None,
805
+ calculates,
835
806
  used_calculates=None,
836
807
  replace_reference=False,
837
808
  warn=False,
@@ -994,7 +965,6 @@ def walktrhough_tricc_node_processed_stached(
994
965
  warn=False,
995
966
  node_path=[],
996
967
  process=None,
997
- loop_count=0,
998
968
  **kwargs,
999
969
  ):
1000
970
  ended_activity = False
@@ -1160,10 +1130,7 @@ def walktrhough_tricc_node_processed_stached(
1160
1130
  if nn not in stashed_nodes:
1161
1131
  stashed_nodes.insert_at_top(nn)
1162
1132
  if not recursive:
1163
- global _last_reordered_group
1164
- if _last_reordered_group != node.group:
1165
- reorder_node_list(stashed_nodes, node.group, processed_nodes)
1166
- _last_reordered_group = node.group
1133
+ reorder_node_list(stashed_nodes, node.group, processed_nodes)
1167
1134
 
1168
1135
  else:
1169
1136
  if prev_process and process and prev_process != process[0]:
@@ -1310,7 +1277,7 @@ def stashed_node_func(node, callback, recursive=False, **kwargs):
1310
1277
 
1311
1278
 
1312
1279
  # check if the all the prev nodes are processed
1313
- def is_ready_to_process(in_node, processed_nodes, strict=True, local=False, loop_count=0):
1280
+ def is_ready_to_process(in_node, processed_nodes, strict=True, local=False):
1314
1281
  if isinstance(in_node, TriccNodeSelectOption):
1315
1282
  node = in_node.select
1316
1283
  elif isinstance(in_node, (TriccNodeActivityStart, TriccNodeMainStart)):
@@ -1321,38 +1288,36 @@ def is_ready_to_process(in_node, processed_nodes, strict=True, local=False, loop
1321
1288
  if hasattr(node, "prev_nodes"):
1322
1289
  # ensure the previous node of the select are processed, not the option prev nodes
1323
1290
  for prev_node in node.prev_nodes:
1324
- if is_prev_processed(prev_node, node, processed_nodes, local, loop_count) is False:
1291
+ if is_prev_processed(prev_node, node, processed_nodes, local) is False:
1325
1292
  return False
1326
1293
  return True
1327
1294
 
1328
1295
 
1329
- def is_prev_processed(prev_node, node, processed_nodes, local, loop_count=0):
1296
+ def is_prev_processed(prev_node, node, processed_nodes, local):
1330
1297
  if hasattr(prev_node, "select"):
1331
- return is_prev_processed(prev_node.select, node, processed_nodes, local, loop_count)
1298
+ return is_prev_processed(prev_node.select, node, processed_nodes, local)
1332
1299
  if prev_node not in processed_nodes and (not local):
1333
- # Only log detailed failures when we suspect dependency loops (loop_count > 5)
1334
- if loop_count > 5:
1335
- if isinstance(prev_node, TriccNodeExclusive):
1336
- iterator = iter(prev_node.prev_nodes)
1337
- p_n_node = next(iterator)
1338
- logger.debug(
1339
- "is_ready_to_process:failed:via_excl: {} - {} > {} {}:{}".format(
1340
- get_data_for_log(p_n_node), prev_node.get_name(), node.__class__, node.get_name(), node.instance
1341
- )
1342
- )
1343
-
1344
- else:
1345
- logger.debug(
1346
- "is_ready_to_process:failed: {} -> {} {}:{}".format(
1347
- get_data_for_log(prev_node), node.__class__, node.get_name(), node.instance
1348
- )
1300
+ if isinstance(prev_node, TriccNodeExclusive):
1301
+ iterator = iter(prev_node.prev_nodes)
1302
+ p_n_node = next(iterator)
1303
+ logger.debug(
1304
+ "is_ready_to_process:failed:via_excl: {} - {} > {} {}:{}".format(
1305
+ get_data_for_log(p_n_node), prev_node.get_name(), node.__class__, node.get_name(), node.instance
1349
1306
  )
1307
+ )
1350
1308
 
1309
+ else:
1351
1310
  logger.debug(
1352
- "prev node node {}:{} for node {} not in processed".format(
1353
- prev_node.__class__, prev_node.get_name(), node.get_name()
1311
+ "is_ready_to_process:failed: {} -> {} {}:{}".format(
1312
+ get_data_for_log(prev_node), node.__class__, node.get_name(), node.instance
1354
1313
  )
1355
1314
  )
1315
+
1316
+ logger.debug(
1317
+ "prev node node {}:{} for node {} not in processed".format(
1318
+ prev_node.__class__, prev_node.get_name(), node.get_name()
1319
+ )
1320
+ )
1356
1321
  return False
1357
1322
  return True
1358
1323
 
@@ -1767,36 +1732,28 @@ def replace_next_node(prev_node, next_node, old_node):
1767
1732
 
1768
1733
 
1769
1734
  # Priority constants
1770
- SAME_GROUP_PRIORITY = 70
1771
- PARENT_GROUP_PRIORITY = 60
1772
- ACTIVE_ACTIVITY_PRIORITY = 50
1773
- NON_START_ACTIVITY_PRIORITY = 40
1774
- ACTIVE_ACTIVITY_LOWER_PRIORITY = 30
1775
- FLOW_CALCULATE_NODE_PRIORITY_TOP_UP = 3
1776
- RHOMBUS_PRIORITY_TO_UP = 3
1777
-
1778
-
1735
+ SAME_GROUP_PRIORITY = 7000
1736
+ PARENT_GROUP_PRIORITY = 6000
1737
+ ACTIVE_ACTIVITY_PRIORITY = 5000
1738
+ NON_START_ACTIVITY_PRIORITY = 4000
1739
+ ACTIVE_ACTIVITY_LOWER_PRIORITY = 3000
1740
+ RHOMBUS_PRIORITY = 1000
1741
+ DEFAULT_PRIORITY = 2000
1742
+
1743
+
1779
1744
  def reorder_node_list(node_list, group, processed_nodes):
1780
1745
  # Cache active activities for O(1) lookup
1781
1746
  active_activities = {n.activity for n in processed_nodes}
1782
- MAP_PRIORITIES = {}
1783
- def get_priority(node):
1784
- if node.id in MAP_PRIORITIES:
1785
- return MAP_PRIORITIES[node.id]
1786
- if isinstance(node, (TriccNodeActivityStart, TriccNodeMainStart)):
1787
- return get_priority(node.activity)
1788
- if isinstance(node, (TriccNodeSelectOption)):
1789
- return get_priority(node.select)
1790
1747
 
1748
+ def get_priority(node):
1791
1749
  # Cache attributes to avoid repeated getattr calls
1792
- explicit_priority = getattr(node, "priority", None)
1793
- priority = int(explicit_priority or 0)
1750
+ priority = int(getattr(node, "priority", 0) or 0)
1794
1751
  node_group = getattr(node, "group", None)
1795
1752
  activity = getattr(node, "activity", None)
1796
1753
 
1797
1754
  # Check for same group
1798
1755
  if group is not None and node_group and node_group.id == group.id:
1799
- priority += SAME_GROUP_PRIORITY
1756
+ priority += SAME_GROUP_PRIORITY
1800
1757
  # Check for parent group
1801
1758
  elif hasattr(group, "group") and group.group and node_group and node_group.id == group.group.id:
1802
1759
  priority += PARENT_GROUP_PRIORITY
@@ -1810,21 +1767,11 @@ def reorder_node_list(node_list, group, processed_nodes):
1810
1767
  elif activity and activity in active_activities:
1811
1768
  priority += ACTIVE_ACTIVITY_LOWER_PRIORITY
1812
1769
  # Check for rhombus nodes
1813
-
1814
-
1815
- if (
1816
- issubclass(node.__class__, TriccNodeDisplayCalculateBase) or
1817
- isinstance(node, TriccNodeEnd)
1818
- ) and not isinstance(node, TriccNodeActivityEnd) and hasattr(node, 'prev_nodes') and len(node.prev_nodes) > 0:
1819
- priority += FLOW_CALCULATE_NODE_PRIORITY_TOP_UP
1820
1770
  elif issubclass(node.__class__, TriccRhombusMixIn):
1821
- priority += RHOMBUS_PRIORITY_TO_UP
1771
+ priority += RHOMBUS_PRIORITY
1772
+ else:
1773
+ priority += DEFAULT_PRIORITY
1822
1774
 
1823
- if node.prev_nodes and not explicit_priority and not isinstance(node, TriccNodeMainStart):
1824
- priority = max(priority, *[get_priority(p) for p in node.prev_nodes])
1825
-
1826
- MAP_PRIORITIES[node.id] = priority
1827
-
1828
1775
  return priority
1829
1776
 
1830
1777
  # Sort in place, highest priority first
@@ -2020,7 +1967,7 @@ def get_prev_instance_skip_expression(node, processed_nodes, process, expression
2020
1967
 
2021
1968
  # end def
2022
1969
  def get_process_skip_expression(node, processed_nodes, process, expression=None):
2023
- list_ends = [x for x in processed_nodes if isinstance(x, TriccNodeEnd)]
1970
+ list_ends = OrderedSet(filter(lambda x: issubclass(x.__class__, TriccNodeEnd), processed_nodes))
2024
1971
  if list_ends:
2025
1972
  end_expressions = []
2026
1973
  f_end_expression = get_end_expression(list_ends)
@@ -2029,11 +1976,8 @@ def get_process_skip_expression(node, processed_nodes, process, expression=None)
2029
1976
  b_end_expression = get_end_expression(list_ends, "pause")
2030
1977
  if b_end_expression:
2031
1978
  end_expressions.append(b_end_expression)
2032
- process_index = None
2033
- if process and process[0] in PROCESSES:
2034
- process_index = PROCESSES.index(process[0])
2035
- if process_index is not None:
2036
- for p in PROCESSES[process_index + 1:]:
1979
+ if process[0] in PROCESSES:
1980
+ for p in PROCESSES[PROCESSES.index(process[0]) + 1:]:
2037
1981
  p_end_expression = get_end_expression(list_ends, p)
2038
1982
  if p_end_expression:
2039
1983
  end_expressions.append(p_end_expression)
@@ -2080,7 +2024,7 @@ def get_accept_diagnostic_node(code, display, severity, priority, activity):
2080
2024
  return node
2081
2025
 
2082
2026
 
2083
- def get_diagnostic_node(code, display, severity, priority, activity, option):
2027
+ def get_diagnostic_node(code, display, severity, priority, activity):
2084
2028
  node = TriccNodeCalculate(
2085
2029
  id=generate_id("final." + code),
2086
2030
  name="final." + code,
@@ -2091,7 +2035,7 @@ def get_diagnostic_node(code, display, severity, priority, activity, option):
2091
2035
  expression_reference=or_join(
2092
2036
  [
2093
2037
  TriccOperation(TriccOperator.ISTRUE, [TriccReference("pre_final." + code)]),
2094
- TriccOperation(TriccOperator.SELECTED, [TriccReference("tricc.manual.diag"), TriccStatic(option)]),
2038
+ TriccOperation(TriccOperator.SELECTED, [TriccReference("tricc.manual.diag"), TriccStatic(code)]),
2095
2039
  ]
2096
2040
  ),
2097
2041
  )
@@ -2150,19 +2094,9 @@ def create_determine_diagnosis_activity(diags):
2150
2094
  group=activity,
2151
2095
  required=TriccStatic(False),
2152
2096
  )
2153
- options = []
2154
2097
  for proposed in diags:
2155
- option = TriccNodeSelectOption(
2156
- id=generate_id(proposed.name),
2157
- name=proposed.name,
2158
- label=proposed.label,
2159
- list_name=f.list_name,
2160
- relevance=proposed.activity.applicability,
2161
- select=f,
2162
- )
2163
- options.append(option)
2164
2098
  d = get_accept_diagnostic_node(proposed.name, proposed.label, proposed.severity, proposed.priority, activity)
2165
- c = get_diagnostic_node(proposed.name, proposed.label, proposed.severity, proposed.priority, activity, option)
2099
+ c = get_diagnostic_node(proposed.name, proposed.label, proposed.severity, proposed.priority, activity)
2166
2100
  diags_conf.append(d)
2167
2101
  r = TriccNodeRhombus(
2168
2102
  path=start,
@@ -2187,6 +2121,17 @@ def create_determine_diagnosis_activity(diags):
2187
2121
  activity.nodes[wait2.id] = wait2
2188
2122
  # fallback
2189
2123
 
2124
+ options = [
2125
+ TriccNodeSelectOption(
2126
+ id=generate_id(d.name),
2127
+ name=d.name,
2128
+ label=d.label,
2129
+ list_name=f.list_name,
2130
+ relevance=d.activity.applicability,
2131
+ select=f,
2132
+ )
2133
+ for d in diags
2134
+ ]
2190
2135
  f.options = dict(zip(range(0, len(options)), options))
2191
2136
  activity.nodes[f.id] = f
2192
2137
  set_prev_next_node(f, end, edge_only=False)
@@ -2212,9 +2157,7 @@ def get_prev_node_expression(node, processed_nodes, get_overall_exp=False, exclu
2212
2157
 
2213
2158
  for act_id in prev_activities:
2214
2159
  act_expression_inputs = []
2215
- none_sequence_defined_prev_node = False
2216
2160
  for prev_node in prev_activities[act_id]:
2217
- none_sequence_defined_prev_node = none_sequence_defined_prev_node or not prev_node.is_sequence_defined
2218
2161
  if (
2219
2162
  excluded_name is None
2220
2163
  or prev_node != excluded_name
@@ -2241,7 +2184,8 @@ def get_prev_node_expression(node, processed_nodes, get_overall_exp=False, exclu
2241
2184
  if act_expression_inputs:
2242
2185
  act_sub = or_join(act_expression_inputs)
2243
2186
  # if there is condition fallback on the calling activity condition
2244
- act_relevance = get_node_expression(
2187
+ if act_sub == TriccStatic(True):
2188
+ act_sub = get_node_expression(
2245
2189
  prev_node.activity,
2246
2190
  processed_nodes=processed_nodes,
2247
2191
  get_overall_exp=get_overall_exp,
@@ -2249,25 +2193,6 @@ def get_prev_node_expression(node, processed_nodes, get_overall_exp=False, exclu
2249
2193
  negate=False,
2250
2194
  process=process,
2251
2195
  )
2252
- if act_sub == TriccStatic(True):
2253
- act_sub = act_relevance
2254
- elif act_relevance != TriccStatic(True) and none_sequence_defined_prev_node:
2255
- # For nodes with is_sequence_defined = False, AND the activity relevance with the prev expression
2256
- # activity_relevance = get_node_expression(
2257
- # prev_node.activity,
2258
- # processed_nodes=processed_nodes,
2259
- # get_overall_exp=get_overall_exp,
2260
- # is_prev=True,
2261
- # negate=False,
2262
- # process=process,
2263
- # )
2264
- act_sub = and_join([
2265
- TriccOperation(
2266
- TriccOperator.ISTRUE,
2267
- [prev_node.activity.root]
2268
- ),
2269
- act_sub
2270
- ])
2271
2196
  add_sub_expression(expression_inputs, act_sub)
2272
2197
  # avoid void is there is not conditions to avoid looping too much itme
2273
2198
  # expression_inputs = clean_or_list(
@@ -2314,27 +2239,10 @@ def get_count_terms(node, processed_nodes, get_overall_exp, negate=False, proces
2314
2239
  return TriccOperation(TriccOperator.PLUS, [TriccOperation(TriccOperator.CAST_NUMBER, [term]) for term in terms])
2315
2240
 
2316
2241
 
2317
- def get_none_option(node):
2318
- if hasattr(node, "options"):
2319
- for opt in node.options.values():
2320
- if opt.name == "opt_none":
2321
- return opt
2322
- return None
2323
-
2324
-
2325
2242
  def get_count_terms_details(prev_node, processed_nodes, get_overall_exp, negate=False, process=None):
2326
- opt_none = get_none_option(prev_node)
2327
- if opt_none:
2328
- if isinstance(opt_none, str):
2329
- operation_none = TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic(opt_none)])
2330
- elif issubclass(opt_none.__class__, TriccBaseModel):
2331
- operation_none = TriccOperation(TriccOperator.SELECTED, [prev_node, opt_none])
2332
- else:
2333
- logger.critical(f"unexpected none option value {opt_none}")
2334
- else:
2335
- operation_none = TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic("opt_none")])
2243
+ operation_none = TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic("opt_none")])
2336
2244
  if isinstance(prev_node, TriccNodeSelectYesNo):
2337
- return TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic(prev_node.options[0])])
2245
+ return TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic(prev_node.options[0].name)])
2338
2246
  elif issubclass(prev_node.__class__, TriccNodeSelect):
2339
2247
  if negate:
2340
2248
  return
@@ -2384,11 +2292,7 @@ def get_count_terms_details(prev_node, processed_nodes, get_overall_exp, negate=
2384
2292
  TriccOperator.CAST_NUMBER,
2385
2293
  [
2386
2294
  get_node_expression(
2387
- prev_node,
2388
- processed_nodes=processed_nodes,
2389
- get_overall_exp=get_overall_exp,
2390
- is_prev=True,
2391
- process=process
2295
+ prev_node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, is_prev=True, process=process
2392
2296
  )
2393
2297
  ],
2394
2298
  )
@@ -2579,6 +2483,15 @@ def get_calculation_terms(node, processed_nodes, get_overall_exp=False, negate=F
2579
2483
 
2580
2484
  if isinstance(node.expression_reference, (TriccOperation, TriccStatic)):
2581
2485
  expression = node.expression_reference
2486
+ elif node.reference is not None and node.expression_reference is not None:
2487
+ expression = get_prev_node_expression(
2488
+ node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process
2489
+ )
2490
+ ref_expression = node.expression_reference.format(*[get_export_name(ref) for ref in node.reference])
2491
+ if expression is not None and expression != "":
2492
+ expression = and_join([expression, ref_expression])
2493
+ else:
2494
+ expression = ref_expression
2582
2495
  elif expression is None:
2583
2496
  expression = get_prev_node_expression(
2584
2497
  node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process
@@ -2641,13 +2554,16 @@ def get_selected_option_expression_single(option_node, negate):
2641
2554
 
2642
2555
  def get_selected_option_expression_multiple(option_node, negate):
2643
2556
 
2644
- selected = TriccOperation(TriccOperator.SELECTED, [option_node.select, TriccStatic(option_node)])
2557
+ selected = TriccOperation(TriccOperator.SELECTED, [option_node.select, option_node])
2645
2558
 
2646
2559
  if negate:
2647
- return and_join([
2560
+ return TriccOperation(
2561
+ operator=TriccOperator.AND,
2562
+ resource=[
2648
2563
  TriccOperation(operator=TriccOperator.NOT, resource=[selected]),
2649
2564
  TriccOperation(operator=TriccOperator.ISNOTNULL, resource=[option_node.select]),
2650
- ])
2565
+ ],
2566
+ )
2651
2567
 
2652
2568
  else:
2653
2569
  return selected
@@ -2668,12 +2584,6 @@ def generate_calculate(node, processed_nodes, **kwargs):
2668
2584
  if node not in processed_nodes:
2669
2585
  if kwargs.get("warn", True):
2670
2586
  logger.debug("generation of calculate for node {}".format(node.get_name()))
2671
-
2672
- # Set is_sequence_defined for calculate nodes based on dependencies
2673
- if issubclass(node.__class__, TriccNodeCalculateBase):
2674
- # Calculate node is sequence defined if ALL prev_nodes have is_sequence_defined = True
2675
- node.is_sequence_defined = all(prev_node.is_sequence_defined for prev_node in node.prev_nodes)
2676
-
2677
2587
  if (
2678
2588
  hasattr(node, "expression")
2679
2589
  and (node.expression is None)
@@ -2714,26 +2624,24 @@ def generate_base(node, processed_nodes, **kwargs):
2714
2624
  # we don't overright if define in the diagram
2715
2625
  if node.constraint is None:
2716
2626
  if isinstance(node, TriccNodeSelectMultiple):
2717
- none_opt = get_none_option(node)
2718
- if none_opt:
2719
- node.constraint = or_join(
2720
- [
2721
- TriccOperation(
2722
- TriccOperator.EQUAL,
2723
- ["$this", TriccStatic(none_opt)],
2724
- ),
2725
- TriccOperation(
2726
- TriccOperator.NOT,
2727
- [
2728
- TriccOperation(
2729
- TriccOperator.SELECTED,
2730
- ["$this", TriccStatic(none_opt)],
2731
- )
2732
- ],
2733
- ),
2734
- ]
2735
- ) # '.=\'opt_none\' or not(selected(.,\'opt_none\'))'
2736
- node.constraint_message = "**None** cannot be selected together with choice."
2627
+ node.constraint = or_join(
2628
+ [
2629
+ TriccOperation(
2630
+ TriccOperator.EQUAL,
2631
+ ["$this", TriccStatic("opt_none")],
2632
+ ),
2633
+ TriccOperation(
2634
+ TriccOperator.NOT,
2635
+ [
2636
+ TriccOperation(
2637
+ TriccOperator.SELECTED,
2638
+ ["$this", TriccStatic("opt_none")],
2639
+ )
2640
+ ],
2641
+ ),
2642
+ ]
2643
+ ) # '.=\'opt_none\' or not(selected(.,\'opt_none\'))'
2644
+ node.constraint_message = "**None** cannot be selected together with choice."
2737
2645
  elif node.tricc_type in (
2738
2646
  TriccNodeType.integer,
2739
2647
  TriccNodeType.decimal,
@@ -2758,7 +2666,7 @@ def generate_base(node, processed_nodes, **kwargs):
2758
2666
  )
2759
2667
  constraints_max = "The maximum value is {0}.".format(node.max)
2760
2668
  if len(constraints) > 1:
2761
- node.constraint = and_join(constraints)
2669
+ node.constraint = TriccOperation(TriccOperator.AND, constraints)
2762
2670
  node.constraint_message = (constraints_min + " " + constraints_max).strip()
2763
2671
  elif len(constraints) == 1:
2764
2672
  node.constraint = constraints[0]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tricc-oo
3
- Version: 1.6.26
3
+ Version: 1.7.0.dev1
4
4
  Summary: Python library that converts CDSS L2 in L3
5
5
  Project-URL: Homepage, https://github.com/SwissTPH/tricc
6
6
  Project-URL: Issues, https://github.com/SwissTPH/tricc/issues