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