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