tricc-oo 1.5.22__py3-none-any.whl → 1.5.24__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tests/build.py +17 -23
- tests/test_cql.py +37 -108
- 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 +125 -123
- tricc_oo/converters/datadictionnary.py +45 -54
- tricc_oo/converters/drawio_type_map.py +143 -61
- tricc_oo/converters/tricc_to_xls_form.py +14 -24
- tricc_oo/converters/utils.py +3 -3
- tricc_oo/converters/xml_to_tricc.py +286 -231
- tricc_oo/models/__init__.py +2 -1
- tricc_oo/models/base.py +300 -308
- tricc_oo/models/calculate.py +63 -49
- 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 +145 -89
- tricc_oo/parsers/xml.py +15 -30
- tricc_oo/serializers/planuml.py +4 -6
- tricc_oo/serializers/xls_form.py +81 -135
- 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 +142 -67
- 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 +647 -0
- tricc_oo/strategies/output/spice.py +106 -127
- tricc_oo/strategies/output/xls_form.py +263 -222
- tricc_oo/strategies/output/xlsform_cdss.py +623 -142
- tricc_oo/strategies/output/xlsform_cht.py +108 -115
- tricc_oo/strategies/output/xlsform_cht_hf.py +13 -24
- tricc_oo/visitors/tricc.py +1297 -1016
- tricc_oo/visitors/utils.py +16 -16
- tricc_oo/visitors/xform_pd.py +91 -89
- {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.24.dist-info}/METADATA +127 -84
- tricc_oo-1.5.24.dist-info/RECORD +50 -0
- tricc_oo-1.5.24.dist-info/licenses/LICENSE +373 -0
- tricc_oo-1.5.22.dist-info/RECORD +0 -46
- {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.24.dist-info}/WHEEL +0 -0
- {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.24.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
3
|
import logging
|
|
4
|
-
from collections import OrderedDict
|
|
5
|
-
from pydantic import BaseModel
|
|
6
4
|
from tricc_oo.models import (
|
|
7
|
-
TriccOperation,
|
|
8
|
-
TriccOperator,
|
|
9
5
|
TriccNodeSelect,
|
|
10
6
|
TriccNodeSelectOne,
|
|
11
7
|
TriccNodeAcceptDiagnostic,
|
|
@@ -17,7 +13,7 @@ from tricc_oo.models import (
|
|
|
17
13
|
OrderedSet,
|
|
18
14
|
TriccNodeNote,
|
|
19
15
|
TriccNodeDiagnosis,
|
|
20
|
-
TriccNodeSelectOption
|
|
16
|
+
TriccNodeSelectOption,
|
|
21
17
|
)
|
|
22
18
|
|
|
23
19
|
from tricc_oo.converters.datadictionnary import lookup_codesystems_code
|
|
@@ -27,58 +23,51 @@ from tricc_oo.visitors.tricc import (
|
|
|
27
23
|
walktrhough_tricc_node_processed_stached,
|
|
28
24
|
is_ready_to_process,
|
|
29
25
|
process_reference,
|
|
30
|
-
get_node_expressions
|
|
31
26
|
)
|
|
32
27
|
|
|
33
28
|
from tricc_oo.strategies.output.base_output_strategy import BaseOutPutStrategy
|
|
34
29
|
|
|
35
30
|
logger = logging.getLogger("default")
|
|
36
31
|
|
|
37
|
-
|
|
38
|
-
|
|
39
32
|
|
|
40
|
-
|
|
41
|
-
class spiceCondition():
|
|
33
|
+
class spiceCondition:
|
|
42
34
|
eq: str = None
|
|
43
35
|
targetId: str = None
|
|
44
|
-
visibility: str =
|
|
45
|
-
|
|
46
|
-
def __init__(self, eq=None, targetId=None, visibility=
|
|
36
|
+
visibility: str = "visible" # other option gone
|
|
37
|
+
|
|
38
|
+
def __init__(self, eq=None, targetId=None, visibility="visible"):
|
|
47
39
|
self.eq = eq
|
|
48
40
|
self.targetId = targetId
|
|
49
41
|
self.visibility = visibility
|
|
50
42
|
|
|
51
|
-
|
|
52
43
|
def __repr__(self):
|
|
53
44
|
self.__str__()
|
|
45
|
+
|
|
54
46
|
def to_dict(self):
|
|
55
47
|
# Create a dictionary with only the required attributes
|
|
56
|
-
return {
|
|
57
|
-
"eq": self.eq,
|
|
58
|
-
"targetId": self.targetId,
|
|
59
|
-
"visibility": self.visibility
|
|
60
|
-
}
|
|
48
|
+
return {"eq": self.eq, "targetId": self.targetId, "visibility": self.visibility}
|
|
61
49
|
|
|
62
50
|
|
|
63
|
-
class spiceOption
|
|
51
|
+
class spiceOption:
|
|
64
52
|
id: str = None
|
|
65
53
|
name: str = None
|
|
54
|
+
|
|
66
55
|
def __init__(self, id=None, name=None):
|
|
67
56
|
self.id = id
|
|
68
57
|
self.name = name
|
|
69
58
|
|
|
70
|
-
|
|
71
59
|
def __repr__(self):
|
|
72
60
|
self.__str__()
|
|
73
|
-
|
|
61
|
+
|
|
74
62
|
def to_dict(self):
|
|
75
63
|
# Create a dictionary with only the required attributes
|
|
76
64
|
return {
|
|
77
65
|
"id": self.id,
|
|
78
66
|
"name": self.name,
|
|
79
67
|
}
|
|
80
|
-
|
|
81
|
-
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class SpiceQuestion:
|
|
82
71
|
condition: list = []
|
|
83
72
|
errorMessage: str = None
|
|
84
73
|
family: str = None
|
|
@@ -92,180 +81,171 @@ class SpiceQuestion():
|
|
|
92
81
|
isBooleanAnswer: bool = False
|
|
93
82
|
isSummary: str = None
|
|
94
83
|
optionsList: list = []
|
|
95
|
-
optionType: str =
|
|
84
|
+
optionType: str = "boolean"
|
|
96
85
|
orderId: str = None
|
|
97
86
|
readOnly: bool = True
|
|
98
87
|
title: str = None
|
|
99
88
|
viewType: str = None
|
|
100
|
-
isInfo: str =
|
|
101
|
-
visibility: str =
|
|
89
|
+
isInfo: str = "gone"
|
|
90
|
+
visibility: str = "visible"
|
|
102
91
|
noOfDays: int = None
|
|
103
|
-
|
|
92
|
+
|
|
104
93
|
def to_dict(self):
|
|
105
94
|
"""
|
|
106
95
|
Returns a dictionary representation of the object,
|
|
107
96
|
including only attributes that are not None or empty lists.
|
|
108
97
|
"""
|
|
109
|
-
return {
|
|
110
|
-
|
|
111
|
-
if value is not None and value != []
|
|
112
|
-
}
|
|
113
|
-
|
|
98
|
+
return {key: value for key, value in self.__dict__.items() if value is not None and value != []}
|
|
99
|
+
|
|
114
100
|
|
|
115
101
|
def get_node_options(node):
|
|
116
|
-
options =
|
|
102
|
+
options = []
|
|
117
103
|
if isinstance(node, TriccNodeSelect):
|
|
118
|
-
for k,o in node.options.items():
|
|
119
|
-
options.append(
|
|
120
|
-
spiceOption(
|
|
121
|
-
id=o.name,
|
|
122
|
-
name=o.label
|
|
123
|
-
).to_dict()
|
|
124
|
-
)
|
|
104
|
+
for k, o in node.options.items():
|
|
105
|
+
options.append(spiceOption(id=o.name, name=o.label).to_dict())
|
|
125
106
|
return options
|
|
126
|
-
|
|
107
|
+
|
|
108
|
+
|
|
127
109
|
def get_node_conditions(node):
|
|
128
|
-
conditions =
|
|
110
|
+
conditions = []
|
|
129
111
|
if isinstance(node, TriccNodeSelect):
|
|
130
|
-
for k,o in node.options.items():
|
|
112
|
+
for k, o in node.options.items():
|
|
131
113
|
for n in o.next_nodes:
|
|
132
114
|
conditions.append(
|
|
133
115
|
spiceCondition(
|
|
134
116
|
eq=o.name,
|
|
135
117
|
targetId=n.name,
|
|
136
|
-
visibility=
|
|
118
|
+
visibility="visible", # other option gone
|
|
137
119
|
).to_dict()
|
|
138
120
|
)
|
|
139
121
|
return conditions
|
|
140
|
-
|
|
122
|
+
|
|
123
|
+
|
|
141
124
|
def get_option_type(node):
|
|
142
125
|
if isinstance(node, (TriccNodeSelectYesNo, TriccNodeAcceptDiagnostic)):
|
|
143
|
-
return
|
|
126
|
+
return "boolean"
|
|
144
127
|
elif isinstance(node, TriccNodeSelect):
|
|
145
|
-
#FIXME no other value than boolean found
|
|
146
|
-
return
|
|
128
|
+
# FIXME no other value than boolean found
|
|
129
|
+
return "string"
|
|
130
|
+
|
|
147
131
|
|
|
148
132
|
def get_node_view_type(node, concept):
|
|
149
133
|
if isinstance(node, TriccNodeSelectOne):
|
|
150
|
-
return
|
|
134
|
+
return "SingleSelectionView"
|
|
151
135
|
elif isinstance(node, TriccNodeSelectMultiple):
|
|
152
|
-
#FIXME
|
|
153
|
-
return
|
|
136
|
+
# FIXME
|
|
137
|
+
return "Spinner"
|
|
154
138
|
elif isinstance(node, TriccNodeText):
|
|
155
|
-
return
|
|
156
|
-
elif is_no_of_day(node,concept):
|
|
157
|
-
return
|
|
139
|
+
return "EditText"
|
|
140
|
+
elif is_no_of_day(node, concept):
|
|
141
|
+
return "NoOfDaysView"
|
|
158
142
|
elif isinstance(node, TriccNodeNote):
|
|
159
|
-
#FIXME
|
|
160
|
-
return
|
|
143
|
+
# FIXME
|
|
144
|
+
return "InformationLabel"
|
|
161
145
|
elif isinstance(node, TriccNodeDiagnosis):
|
|
162
|
-
#FIXME
|
|
163
|
-
return
|
|
164
|
-
|
|
146
|
+
# FIXME
|
|
147
|
+
return "InformationLabel"
|
|
148
|
+
|
|
165
149
|
|
|
166
|
-
|
|
167
|
-
|
|
168
150
|
def is_no_of_day(node, concept):
|
|
169
151
|
return (
|
|
170
|
-
isinstance(node, TriccNodeInteger)
|
|
152
|
+
isinstance(node, TriccNodeInteger)
|
|
171
153
|
and concept
|
|
172
|
-
and any(
|
|
173
|
-
[
|
|
174
|
-
True for p in concept.property
|
|
175
|
-
if p.valueString == 'nbDays' and p.code == 'archetype'
|
|
176
|
-
]
|
|
177
|
-
)
|
|
154
|
+
and any([True for p in concept.property if p.valueString == "nbDays" and p.code == "archetype"])
|
|
178
155
|
)
|
|
179
|
-
|
|
156
|
+
|
|
157
|
+
|
|
180
158
|
def to_spice_question(node, codesystems):
|
|
181
159
|
concept = lookup_codesystems_code(codesystems, node.name)
|
|
182
|
-
view_type = get_node_view_type(node,concept)
|
|
160
|
+
view_type = get_node_view_type(node, concept)
|
|
183
161
|
if view_type:
|
|
184
|
-
|
|
162
|
+
|
|
185
163
|
q = SpiceQuestion()
|
|
186
|
-
q.condition=get_node_conditions(node)
|
|
187
|
-
q.errorMessage=getattr(node,
|
|
188
|
-
q.family= (node.group or node.activity).name
|
|
189
|
-
q.titleSummary= (node.group or node.activity).label
|
|
190
|
-
q.fieldName= node.label
|
|
191
|
-
q.isEnabled= True
|
|
192
|
-
q.isMandatory= True
|
|
193
|
-
q.isNeededDefault= True
|
|
194
|
-
q.isBooleanAnswer= isinstance(node, TriccNodeSelectYesNo)
|
|
195
|
-
q.isSummary=
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
q.
|
|
201
|
-
q.
|
|
202
|
-
q.
|
|
164
|
+
q.condition = get_node_conditions(node)
|
|
165
|
+
q.errorMessage = getattr(node, "constraint_message", None)
|
|
166
|
+
q.family = (node.group or node.activity).name
|
|
167
|
+
q.titleSummary = (node.group or node.activity).label
|
|
168
|
+
q.fieldName = node.label
|
|
169
|
+
q.isEnabled = True
|
|
170
|
+
q.isMandatory = True
|
|
171
|
+
q.isNeededDefault = True
|
|
172
|
+
q.isBooleanAnswer = isinstance(node, TriccNodeSelectYesNo)
|
|
173
|
+
q.isSummary = (
|
|
174
|
+
any([True for p in concept.property if p.valueBoolean is True and p.code == "isSummary"])
|
|
175
|
+
if concept and concept.property
|
|
176
|
+
else None
|
|
177
|
+
)
|
|
178
|
+
q.optionsList = get_node_options(node)
|
|
179
|
+
q.optionType = get_option_type(node)
|
|
180
|
+
q.orderId = node.path_len
|
|
181
|
+
q.readOnly = isinstance(node, TriccNodeNote)
|
|
182
|
+
q.title = node.label
|
|
183
|
+
q.isInfo = "gone"
|
|
184
|
+
q.visibility = "gone" if node.prev_nodes else "visible"
|
|
203
185
|
q.viewType = view_type
|
|
204
186
|
q.noOfDays = node.default if is_no_of_day(node, concept) else None
|
|
205
187
|
return q
|
|
206
188
|
elif not isinstance(node, TriccNodeSelectOption):
|
|
207
189
|
logger.warning(f"unsuported question type {node.get_name()} ")
|
|
208
190
|
|
|
209
|
-
|
|
210
191
|
|
|
211
192
|
class SpiceStrategy(BaseOutPutStrategy):
|
|
212
193
|
form_layout = []
|
|
213
194
|
groups = []
|
|
195
|
+
|
|
214
196
|
def __init__(self, project, output_path):
|
|
215
197
|
super().__init__(project, output_path)
|
|
216
198
|
self.form_layout = []
|
|
217
199
|
self.groups = []
|
|
218
200
|
|
|
219
|
-
|
|
220
201
|
def process_base(self, start_pages, **kwargs):
|
|
221
202
|
# for each node, check if condition is required issubclass(TriccNodeDisplayModel)
|
|
222
203
|
# process name
|
|
223
204
|
pass
|
|
224
|
-
|
|
205
|
+
|
|
225
206
|
def process_relevance(self, start_pages, **kwargs):
|
|
226
|
-
|
|
207
|
+
|
|
227
208
|
pass
|
|
228
|
-
|
|
209
|
+
|
|
229
210
|
def process_calculate(self, start_pages, **kwargs):
|
|
230
211
|
# call the strategy specific code
|
|
231
212
|
pass
|
|
232
|
-
|
|
233
213
|
|
|
234
214
|
def do_clean(self):
|
|
235
215
|
self.form_layout = []
|
|
236
216
|
self.groups = []
|
|
237
217
|
|
|
238
|
-
|
|
239
218
|
def get_kwargs(self):
|
|
240
219
|
return {
|
|
241
220
|
"form_layout": self.form_layout,
|
|
242
221
|
"group": self.groups,
|
|
243
|
-
|
|
244
222
|
}
|
|
245
223
|
|
|
246
224
|
def generate_export(self, node, processed_nodes, calculates, **kwargs):
|
|
247
225
|
# Export logic to JSON format
|
|
248
|
-
if is_ready_to_process(node,processed_nodes, strict=True) and process_reference(
|
|
249
|
-
|
|
226
|
+
if is_ready_to_process(node, processed_nodes, strict=True) and process_reference(
|
|
227
|
+
node,
|
|
228
|
+
processed_nodes,
|
|
229
|
+
calculates,
|
|
230
|
+
replace_reference=False,
|
|
231
|
+
codesystems=kwargs.get("codesystems", None),
|
|
232
|
+
):
|
|
233
|
+
if node not in processed_nodes:
|
|
250
234
|
self.start_group(cur_group=node.group or node.activity)
|
|
251
235
|
if not isinstance(node, TriccNodeActivity):
|
|
252
236
|
q = to_spice_question(node, self.project.code_systems)
|
|
253
237
|
if q:
|
|
254
|
-
self.form_layout.append(
|
|
255
|
-
q.to_dict()
|
|
256
|
-
)
|
|
238
|
+
self.form_layout.append(q.to_dict())
|
|
257
239
|
return True
|
|
258
240
|
|
|
259
241
|
def export(self, start_pages, version):
|
|
260
242
|
# Save the JSON output to a file
|
|
261
243
|
file_name = f"{start_pages['main'].root.form_id}.json"
|
|
262
244
|
output_path = os.path.join(self.output_path, file_name)
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
with open(output_path, 'w') as json_file:
|
|
245
|
+
|
|
246
|
+
with open(output_path, "w") as json_file:
|
|
267
247
|
json.dump({"formLayout": self.form_layout}, json_file, indent=4)
|
|
268
|
-
|
|
248
|
+
|
|
269
249
|
logger.info(f"JSON form exported to {output_path}")
|
|
270
250
|
|
|
271
251
|
def process_export(self, start_pages, **kwargs):
|
|
@@ -276,15 +256,14 @@ class SpiceStrategy(BaseOutPutStrategy):
|
|
|
276
256
|
if cur_group.get_name() not in self.groups:
|
|
277
257
|
self.groups.append(cur_group.get_name())
|
|
278
258
|
self.form_layout.append(
|
|
279
|
-
|
|
259
|
+
{
|
|
280
260
|
"familyOrder": len(self.groups),
|
|
281
261
|
"id": cur_group.name,
|
|
282
262
|
"title": cur_group.label,
|
|
283
|
-
"viewType": "CardView"
|
|
263
|
+
"viewType": "CardView",
|
|
284
264
|
}
|
|
285
265
|
)
|
|
286
266
|
|
|
287
|
-
|
|
288
267
|
def activity_export(self, activity, processed_nodes=OrderedSet(), **kwargs):
|
|
289
268
|
stashed_nodes = OrderedSet()
|
|
290
269
|
calculates = []
|
|
@@ -292,7 +271,7 @@ class SpiceStrategy(BaseOutPutStrategy):
|
|
|
292
271
|
|
|
293
272
|
path_len = 0
|
|
294
273
|
# keep the vesrions on the group id, max version
|
|
295
|
-
|
|
274
|
+
|
|
296
275
|
self.start_group(cur_group)
|
|
297
276
|
walktrhough_tricc_node_processed_stached(
|
|
298
277
|
activity.root,
|
|
@@ -301,10 +280,10 @@ class SpiceStrategy(BaseOutPutStrategy):
|
|
|
301
280
|
stashed_nodes,
|
|
302
281
|
path_len,
|
|
303
282
|
cur_group=activity.root.group,
|
|
304
|
-
calculates
|
|
305
|
-
**self.get_kwargs()
|
|
283
|
+
calculates=calculates,
|
|
284
|
+
**self.get_kwargs(),
|
|
306
285
|
)
|
|
307
|
-
|
|
286
|
+
# MANAGE STASHED NODES
|
|
308
287
|
prev_stashed_nodes = stashed_nodes.copy()
|
|
309
288
|
loop_count = 0
|
|
310
289
|
len_prev_processed_nodes = 0
|
|
@@ -338,28 +317,28 @@ class SpiceStrategy(BaseOutPutStrategy):
|
|
|
338
317
|
processed_nodes,
|
|
339
318
|
stashed_nodes,
|
|
340
319
|
path_len,
|
|
341
|
-
groups=groups,
|
|
342
320
|
cur_group=s_node.group,
|
|
343
|
-
calculates
|
|
344
|
-
**self.get_kwargs()
|
|
321
|
+
calculates=calculates,
|
|
322
|
+
**self.get_kwargs(),
|
|
345
323
|
)
|
|
346
|
-
|
|
324
|
+
|
|
347
325
|
return processed_nodes
|
|
348
326
|
|
|
349
327
|
# Handle stashed nodes (if needed)
|
|
328
|
+
|
|
350
329
|
def tricc_operation_equal(self, ref_expressions):
|
|
351
330
|
return {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
331
|
+
"eq": str(ref_expressions[1]),
|
|
332
|
+
"targetId": str(ref_expressions[0]),
|
|
333
|
+
"visibility": "visible",
|
|
355
334
|
}
|
|
356
335
|
|
|
357
336
|
def tricc_operation_in(self, ref_expressions):
|
|
358
337
|
return {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
338
|
+
"eq": str(ref_expressions[0]),
|
|
339
|
+
"targetId": str(ref_expressions[1]),
|
|
340
|
+
"visibility": "visible",
|
|
362
341
|
}
|
|
363
|
-
|
|
364
|
-
def tricc_operation_in(self, ref_expressions):
|
|
365
|
-
|
|
342
|
+
|
|
343
|
+
# def tricc_operation_in(self, ref_expressions):
|
|
344
|
+
# return ref_expressions[0].replace("visible", "gone")
|