tricc-oo 1.0.1__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.
Files changed (66) hide show
  1. tests/build.py +213 -0
  2. tests/test_cql.py +197 -0
  3. tests/to_ocl.py +51 -0
  4. {tricc → tricc_oo}/__init__.py +3 -1
  5. tricc_oo/converters/codesystem_to_ocl.py +169 -0
  6. tricc_oo/converters/cql/cqlLexer.py +822 -0
  7. tricc_oo/converters/cql/cqlListener.py +1632 -0
  8. tricc_oo/converters/cql/cqlParser.py +11204 -0
  9. tricc_oo/converters/cql/cqlVisitor.py +913 -0
  10. tricc_oo/converters/cql_to_operation.py +402 -0
  11. tricc_oo/converters/datadictionnary.py +115 -0
  12. tricc_oo/converters/drawio_type_map.py +222 -0
  13. tricc_oo/converters/tricc_to_xls_form.py +61 -0
  14. tricc_oo/converters/utils.py +65 -0
  15. tricc_oo/converters/xml_to_tricc.py +1003 -0
  16. tricc_oo/models/__init__.py +4 -0
  17. tricc_oo/models/base.py +732 -0
  18. tricc_oo/models/calculate.py +216 -0
  19. tricc_oo/models/ocl.py +281 -0
  20. tricc_oo/models/ordered_set.py +125 -0
  21. tricc_oo/models/tricc.py +418 -0
  22. tricc_oo/parsers/xml.py +138 -0
  23. tricc_oo/serializers/__init__.py +0 -0
  24. tricc_oo/serializers/xls_form.py +745 -0
  25. tricc_oo/strategies/__init__.py +0 -0
  26. tricc_oo/strategies/input/__init__.py +0 -0
  27. tricc_oo/strategies/input/base_input_strategy.py +111 -0
  28. tricc_oo/strategies/input/drawio.py +317 -0
  29. tricc_oo/strategies/output/base_output_strategy.py +148 -0
  30. tricc_oo/strategies/output/spice.py +365 -0
  31. tricc_oo/strategies/output/xls_form.py +697 -0
  32. tricc_oo/strategies/output/xlsform_cdss.py +189 -0
  33. tricc_oo/strategies/output/xlsform_cht.py +200 -0
  34. tricc_oo/strategies/output/xlsform_cht_hf.py +334 -0
  35. tricc_oo/visitors/__init__.py +0 -0
  36. tricc_oo/visitors/tricc.py +2198 -0
  37. tricc_oo/visitors/utils.py +17 -0
  38. tricc_oo/visitors/xform_pd.py +264 -0
  39. tricc_oo-1.4.15.dist-info/METADATA +219 -0
  40. tricc_oo-1.4.15.dist-info/RECORD +46 -0
  41. {tricc_oo-1.0.1.dist-info → tricc_oo-1.4.15.dist-info}/WHEEL +1 -1
  42. tricc_oo-1.4.15.dist-info/top_level.txt +2 -0
  43. tricc/converters/mc_to_tricc.py +0 -542
  44. tricc/converters/tricc_to_xls_form.py +0 -553
  45. tricc/converters/utils.py +0 -44
  46. tricc/converters/xml_to_tricc.py +0 -740
  47. tricc/models/tricc.py +0 -1093
  48. tricc/parsers/xml.py +0 -81
  49. tricc/serializers/xls_form.py +0 -364
  50. tricc/strategies/input/base_input_strategy.py +0 -80
  51. tricc/strategies/input/drawio.py +0 -246
  52. tricc/strategies/input/medalcreator.py +0 -168
  53. tricc/strategies/output/base_output_strategy.py +0 -92
  54. tricc/strategies/output/xls_form.py +0 -194
  55. tricc/strategies/output/xlsform_cdss.py +0 -46
  56. tricc/strategies/output/xlsform_cht.py +0 -106
  57. tricc/visitors/tricc.py +0 -375
  58. tricc_oo-1.0.1.dist-info/LICENSE +0 -78
  59. tricc_oo-1.0.1.dist-info/METADATA +0 -229
  60. tricc_oo-1.0.1.dist-info/RECORD +0 -26
  61. tricc_oo-1.0.1.dist-info/top_level.txt +0 -2
  62. venv/bin/vba_extract.py +0 -78
  63. {tricc → tricc_oo}/converters/__init__.py +0 -0
  64. {tricc → tricc_oo}/models/lang.py +0 -0
  65. {tricc/serializers → tricc_oo/parsers}/__init__.py +0 -0
  66. {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')