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.
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.2.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 -308
  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.2.dist-info/LICENSE +0 -78
  59. tricc_oo-1.0.2.dist-info/METADATA +0 -229
  60. tricc_oo-1.0.2.dist-info/RECORD +0 -26
  61. tricc_oo-1.0.2.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
@@ -1,246 +0,0 @@
1
-
2
-
3
- import logging
4
- import os
5
- from copy import copy
6
-
7
- from tricc.converters.xml_to_tricc import create_activity
8
- from tricc.visitors.tricc import process_calculate
9
- from tricc.models.tricc import *
10
- from tricc.strategies.input.base_input_strategy import BaseInputStrategy
11
- from tricc.parsers.xml import read_drawio
12
- logger = logging.getLogger('default')
13
- class DrawioStrategy(BaseInputStrategy):
14
- processes = [
15
- 'triage',
16
- 'registration',
17
- 'emergency-care',
18
- 'local-urgent-care',
19
- 'actue-tertiary-care',
20
- 'history-and-physical',
21
- 'diagnostic-testing',
22
- 'determine-diagnosis',
23
- 'provide-counseling',
24
- 'dispense-medications',
25
- 'monitor-and-follow-up-of-patient',
26
- 'alerts-reminders-education',
27
- 'discharge-referral-of-patient',
28
- 'charge-for-service',
29
- 'record-and-report'
30
- ]
31
- def process_pages(self, start_page, pages):
32
- # create the graph
33
- self.linking_nodes(start_page.root, start_page, pages )
34
- # Save the calculate list [node]
35
- calculates = {}
36
- # save when a calcualte is used dict[name, Dict[id, node]]
37
- used_calculates = {}
38
-
39
- # save the node that are processed dict[id, node]
40
-
41
- # add save nodes and merge nodes
42
- stashed_node_func( start_page.root, process_calculate, used_calculates=used_calculates, calculates =calculates, recusive=False )
43
-
44
-
45
- logger.info("# check if all edges (arrow) where used")
46
- for key, page in pages.items():
47
- if page.unused_edges is not None and len(page.unused_edges)>0:
48
- logger.warning(
49
- "Page {0} has still {1}/{2} edges that were not used:"\
50
- .format(page.label, len(page.unused_edges) ,len(page.edges)))
51
- # refresh the edges (were remove by previous code)
52
- return pages
53
-
54
-
55
-
56
- def execute(self, in_filepath, media_path):
57
- files = []
58
- pages = {}
59
- diagrams = []
60
- start_pages= {}
61
- # read all pages
62
- logger.info("# Create the activities from diagram pages")
63
- if os.path.isdir(in_filepath):
64
- files = [f for f in os.listdir(in_filepath) if f.endswith('.drawio')]
65
- elif os.path.isfile(in_filepath):
66
- files = [in_filepath]
67
- else:
68
- logger.error(f"no input file found at {in_filepath}")
69
- exit()
70
- for file in files:
71
- diagrams += read_drawio(file)
72
-
73
- for diagram in diagrams:
74
- logger.info("Create the activity {0}".format(diagram.attrib.get('name')))
75
- page = create_activity(diagram, media_path)
76
- if page is not None:
77
- if page.root is not None:
78
- pages[page.id] = page
79
- if page.root.tricc_type == TriccNodeType.start:
80
- if 'main' not in start_pages and (page.root.process == 'main' or page.root.process is None):
81
- start_pages['main'] = page
82
- elif page.root.process is not None:
83
- if page.root.process not in start_pages:
84
- start_pages[page.root.process] = []
85
- start_pages[page.root.process].append(page)
86
- else:
87
- logger.warning(
88
- "Page {0} has a start node but there is already a start node in page {1}"\
89
- .format(page.label, start_page.label))
90
- logger.info("# Create the graph from the start node")
91
-
92
- app = self.execute_linked_process(start_pages,pages)
93
- if app:
94
- start_pages['main'] = app
95
- pages[app.id]= app
96
- pages = self.process_pages(app, pages)
97
-
98
- return start_pages, pages
99
- elif start_pages:
100
- for process in start_pages:
101
- if isinstance(start_pages[process], list):
102
- for page_to_process in start_pages[process]:
103
- pages = self.process_pages(page_to_process, pages)
104
- else:
105
- pages = self.process_pages(start_pages[process], pages)
106
- return start_pages, pages
107
-
108
- else:
109
- logger.warning("start page not found")
110
- # Q. how to handle graph output
111
- # hardlink with out edge: create a fake node
112
- # or should we always create that fake node
113
- # *** or should we enfore "next activity node" ****
114
- #
115
-
116
- # do the calculation, expression ...
117
-
118
-
119
-
120
- def linking_nodes(self,node, page, pages, processed_nodes = [], path = []):
121
- # get the edges that have that node as source
122
-
123
- node_edge = list(filter(lambda x: (x.source == node.id or x.source == node) , page.edges))
124
- node.activity = page
125
- #build current path
126
- current_path = path + [node.id]
127
- # don't stop the walkthroug by default
128
- logger.debug("linking node {0}".format(node.get_name()))
129
- #FIXME remove note
130
- if len(node_edge) == 0 and not issubclass(node.__class__, (TriccNodeCalculateBase, TriccNodeSelectOption,TriccNodeActivity, TriccNodeNote)):
131
- if issubclass(node.__class__, TriccNodeSelect):
132
- option_edge = list(filter(lambda x: (lambda y: x.source == y.id, node.options) , page.edges))
133
- if len(option_edge) == 0:
134
- logger.error("node {0} without edges out found in page {1}, full path {2}"\
135
- .format(node.get_name(), page.label, current_path))
136
- else:
137
- logger.error("node {0} without edges out found in page {1}, full path {2}"\
138
- .format(node.get_name(), page.label, current_path))
139
- exit()
140
- for edge in node_edge:
141
- #get target node
142
- if edge.target in page.nodes:
143
- target_node = page.nodes[edge.target]
144
- # link perv / next nodes
145
- # walk only if the target node was not processed already
146
- if target_node not in processed_nodes:
147
- if isinstance(target_node, TriccNodeActivity):
148
- self.linking_nodes(target_node.root, target_node, pages, processed_nodes, current_path)
149
- elif isinstance(target_node, TriccNodeGoTo):
150
- next_page = self.walkthrough_goto_node(target_node, page, pages, processed_nodes, current_path)
151
- #update reference
152
- #FIXME support reference str
153
- for n in page.nodes:
154
- sn = page.nodes[n]
155
- if issubclass(sn.__class__, TriccRhombusMixIn) and isinstance(sn.reference,list) and target_node in sn.reference:
156
- sn.reference.remove(target_node)
157
- sn.reference.append(next_page)
158
- # set next page as node to link the next_node of the activity
159
- if next_page is not None:
160
- target_node = next_page
161
- elif isinstance(target_node, TriccNodeLinkOut):
162
- link_out = self.walkthrough_link_out_node( target_node, page, pages, processed_nodes, current_path)
163
- if link_out is not None:
164
- target_node = link_out
165
- elif issubclass(target_node.__class__, TriccNodeSelect):
166
- for key, option in target_node.options.items():
167
- self.linking_nodes(option, page, pages, processed_nodes, current_path)
168
- if target_node not in processed_nodes:
169
- # don't save the link out because the real node is the page
170
- processed_nodes.append(target_node)
171
- self.linking_nodes(target_node, page, pages, processed_nodes, current_path)
172
- elif edge.target in current_path:
173
- logger.warning("possible loop detected for node {0} in page {1}; path:".format(node.get_name(), page.label))
174
- for node_id in current_path:
175
- node = get_node_from_list(processed_nodes,node_id)
176
- if node is not None:
177
- logger.warning(node.get_name())
178
- if isinstance(node, TriccNodeSelectNotAvailable):
179
- set_prev_next_node( node.options[0], target_node)
180
- else:
181
- set_prev_next_node( node, target_node)
182
- else:
183
- logger.warning("target not found {0} for node {1}".format(edge.target, node.get_name()))
184
- #page.edges.remove(edge)
185
-
186
-
187
-
188
- def walkthrough_goto_node(self,node, page, pages, processed_nodes, current_path):
189
- # find the page
190
- if node.link in pages:
191
- next_page = pages[node.link]
192
- # walk thought the next page
193
- max_instance = 1
194
- if node.instance == 0 or next_page.root.instance == 0:
195
- for other_page in next_page.instances.values():
196
- if int(other_page.instance) > int(max_instance):
197
- max_instance = other_page.instance
198
- #auto instance starts at 101
199
- next_page = next_page.make_instance(max(100,max_instance)+1)
200
- else:
201
- #return existing instance if any
202
- next_page = next_page.make_instance(node.instance)
203
- if next_page.id not in pages:
204
- pages[next_page.id]=next_page
205
- logger.debug("jumping to page {0}::{1} from {2}".format(next_page.label, next_page.instance, node.get_name()))
206
- if next_page not in processed_nodes:
207
- self.linking_nodes(next_page.root, next_page, pages, processed_nodes, current_path)
208
-
209
- replace_node(node, next_page, page)
210
-
211
- # continue on the initial page
212
- return next_page
213
- else:
214
- logger.warning("node {0} from page {1} doesnot have a valid link".format(node.label, page.label))
215
-
216
-
217
-
218
- def walkthrough_link_out_node(self,node, page, pages, processed_nodes, current_path):
219
- if node.reference is not None:
220
- link_in_list=[]
221
- link_in_page=None
222
- for page in pages:
223
- link_in_list += list(filter(lambda x: (x.name == node.reference) , page.nodes))
224
- #save the first page where a link is found to continue the walktrhough
225
- if len(link_in_list)>0 and link_in_page is None:
226
- link_in_page = page
227
- if len(link_in_list) == 0:
228
- logger.warning("link in {0} not found for link out {1} in page {2}"\
229
- .format(node.reference, node.name,page.label))
230
- elif len(link_in_list) > 1:
231
- logger.warning("more than one link in {0} found for link out {1} in page {2}"\
232
- .format(node.reference, node.name,page.label))
233
- else:
234
- # all good, only one target node found
235
- linked_target_node=link_in_list[0]
236
- # steal the edges
237
- replace_node(node, linked_target_node, page)
238
-
239
- if linked_target_node not in processed_nodes:
240
- self.linking_nodes(linked_target_node, link_in_page, pages, processed_nodes, current_path)
241
- return linked_target_node
242
- else:
243
- logger.warning("link out {0} in page {1} : reference not found"\
244
- .format(node.name,page.label))
245
-
246
-
@@ -1,168 +0,0 @@
1
-
2
- import json
3
- from types import SimpleNamespace
4
-
5
- from tricc.converters.mc_to_tricc import create_activity,build_relevance,fetch_reference,fetch_condition
6
- from tricc.models.tricc import *
7
- from tricc.strategies.input.base_input_strategy import BaseInputStrategy
8
-
9
- media_path = "./"
10
- class MedalCStrategy(BaseInputStrategy):
11
- def execute(self, in_filepath, media_path):
12
- f = open(in_filepath)
13
- js_full = json.load(f)
14
- pages = {}
15
- start_page=None
16
- js_fullorder = js_full['medal_r_json']['config']['full_order']
17
- js_nodes = js_full['medal_r_json']['nodes']
18
- js_final_diagnoses = js_full['medal_r_json']['final_diagnoses']
19
- js_diagnoses = js_full['medal_r_json']['diagnoses']
20
- js_diagrams = js_full['medal_r_json']['diagram']
21
-
22
- js_all = {**js_nodes, **js_diagnoses,**js_final_diagnoses }
23
- js_nodes['first_name'] = {
24
- "id":'first_name' ,
25
- "label": {
26
- "en": "First Name",
27
- "fr": "Prénom"
28
- },
29
- "type": "Question",
30
- "category": "patient_data",
31
- "value_format": "String"
32
- }
33
- js_nodes['last_name'] = {
34
- "id":'last_name' ,
35
- "label": {
36
- "en": "Last Name",
37
- "fr": "Nom de famille"
38
- },
39
- "type": "Question",
40
- "category": "patient_data",
41
- "value_format": "String"
42
- }
43
-
44
-
45
- js_nodes['birth_date'] = {
46
- "id":'birth_date' ,
47
- "label": {
48
- "en": "Date of birth",
49
- "fr": "Date de naissance"
50
- },
51
- "type": "Question",
52
- "category": "patient_data",
53
- "value_format": "Date"
54
- }
55
-
56
-
57
- is_first=True
58
- last_page = None
59
- for key, stage in js_fullorder.items():
60
- page = create_activity(stage, key, media_path, js_nodes, last_page)
61
- last_page = page
62
- pages[key]=page
63
- if is_first :
64
- start_page = page
65
- page.root.form_id=js_full['id']
66
- page.root.label=js_full['name']
67
- is_first = False
68
- all_nodes = [node for page in list(pages.values()) for node in page.nodes ]
69
- # add p_age
70
- brith_date_node = list(filter(lambda gp: gp.id == 'birth_date', all_nodes))[0]
71
- age_node = TriccNodeCalculate(
72
- name = 'p_age_day',
73
- reference = [brith_date_node],
74
- expression_reference = 'int((today()-date(${{{}}})))',
75
- id = 'p_age_day',
76
- activity = brith_date_node.activity,
77
- group = brith_date_node.activity
78
- )
79
- set_prev_next_node(brith_date_node,age_node)
80
- brith_date_node.activity.nodes.append(age_node)
81
- yi_node = TriccNodeRhombus(
82
- name = 'yi',
83
- reference = [age_node],
84
- expression_reference = '${{{}}}< 62',
85
- id = 'yi',
86
- activity = brith_date_node.activity,
87
- group = brith_date_node.activity
88
- )
89
- set_prev_next_node(age_node,yi_node)
90
- brith_date_node.activity.nodes.append(yi_node)
91
-
92
- child_node = TriccNodeExclusive(
93
- id = generate_id(),
94
- activity = brith_date_node.activity,
95
- group = brith_date_node.activity
96
- )
97
- set_prev_next_node(yi_node,child_node)
98
- brith_date_node.activity.nodes.append(child_node)
99
-
100
- # add the missing nodes
101
- all_nodes = [node for page in list(pages.values()) for node in page.nodes ]
102
- node_id_covered = [node.id for node in all_nodes ]
103
- mode_id_missing= list(filter(lambda key: key not in node_id_covered ,js_nodes))
104
- page = create_activity(mode_id_missing, "other_nodes", media_path, js_nodes, last_page)
105
- last_page = page
106
- pages["other_nodes"]=page
107
- # add the interogation logic
108
- all_nodes = [node for page in list(pages.values()) for node in page.nodes ]
109
- #fetch_reference(all_nodes)
110
- build_relevance(all_nodes, age_node, js_nodes)
111
-
112
- #fetch_condition(all_nodes,js_nodes)
113
- ## add the diagnostics
114
-
115
- page = create_activity(list(js_diagnoses.keys()), "diagnoses", media_path, js_diagnoses, last_page)
116
- last_page = page
117
- pages["diagnoses"]=page
118
- prefix = 'qual'
119
- #all_nodes = [*page.nodes, age_node, brith_date_node]
120
- all_nodes = [node for page in list(pages.values()) for node in page.nodes ]
121
-
122
- #fetch_reference(all_nodes,prefix=prefix)
123
- build_relevance(all_nodes, age_node, js_nodes,prefix=prefix)
124
- #fetch_condition(all_nodes,js_nodes,prefix=prefix)
125
- ## add the diagnostics
126
-
127
- prefix = 'diag'
128
- page = create_activity(list(js_final_diagnoses.keys()), "final_diagnoses", media_path, js_final_diagnoses, last_page)
129
- last_page = page
130
- pages["final_diagnoses"]=page
131
-
132
- #all_nodes = [*page.nodes, age_node, brith_date_node]
133
- all_nodes = [node for page in list(pages.values()) for node in page.nodes ]
134
-
135
- #fetch_reference(all_nodes,prefix=prefix)
136
- build_relevance(all_nodes, age_node, js_diagnoses,prefix=prefix)
137
- #fetch_condition(all_nodes,js_diagnoses,prefix=prefix)
138
-
139
-
140
-
141
- all_nodes = [node for page in list(pages.values()) for node in page.nodes ]
142
- all_group = [group for page in list(pages.values()) for group in page.groups ]
143
-
144
-
145
-
146
-
147
-
148
-
149
- ## all logic
150
- # all_nodes.extend([age_node,yi_node,child_node])
151
-
152
- older_groups = list(filter(lambda gp: gp.name == 'older', all_group))
153
- yi_groups = list(filter(lambda gp: gp.name == 'neonat', all_group))
154
-
155
-
156
- for gp in older_groups:
157
- set_prev_next_node(child_node,gp)
158
- for gp in yi_groups:
159
- set_prev_next_node(yi_node,gp)
160
-
161
- for page in pages.values():
162
- for node in page.nodes:
163
- if len(node.prev_nodes)==0 and len(node.next_nodes)==0:
164
- page.nodes.remove(node)
165
-
166
- return start_page, pages
167
-
168
-
@@ -1,92 +0,0 @@
1
- import abc
2
- import logging
3
- from tricc.models.tricc import stashed_node_func
4
-
5
-
6
- logger = logging.getLogger('default')
7
-
8
-
9
- class BaseOutPutStrategy:
10
- processes = ['main']
11
-
12
- output_path = None
13
- # list of supported processes for the strategy,
14
- # the order of the list will be apply
15
-
16
- def __init__(self, output_path):
17
- self.output_path = output_path
18
-
19
-
20
- def execute(self, start_pages, pages):
21
- if 'main' in start_pages:
22
- self.process_base(start_pages, pages=pages)
23
- else:
24
- logger.error("Main process required")
25
-
26
-
27
- logger.info("generate the relevance based on edges")
28
-
29
-
30
-
31
- # create relevance Expression
32
- self.process_relevance(start_pages, pages=pages)
33
- logger.info("generate the calculate based on edges")
34
-
35
- # create calculate Expression
36
- self.process_calculate(start_pages, pages=pages)
37
- logger.info("generate the export format")
38
- # create calculate Expression
39
- self.process_export(start_pages, pages=pages)
40
-
41
- logger.info("print the export")
42
- self.export(start_pages)
43
-
44
- ### walking function
45
- def process_base(self, start_pages, **kwargs):
46
- # for each node, check if condition is required issubclass(TriccNodeDisplayModel)
47
- # process name
48
- stashed_node_func(start_pages[self.processes[0]].root, self.generate_base, **{**self.get_kwargs(),**kwargs} )
49
- self.do_clean( **{**self.get_kwargs(),**kwargs})
50
-
51
- def process_relevance(self, start_pages, **kwargs):
52
-
53
- stashed_node_func(start_pages[self.processes[0]].root, self.generate_relevance, **{**self.get_kwargs(),**kwargs} )
54
- self.do_clean( **{**self.get_kwargs(),**kwargs})
55
-
56
- def process_calculate(self, start_pages, **kwargs):
57
- # call the strategy specific code
58
- stashed_node_func(start_pages[self.processes[0]].root, self.generate_calculate, **{**self.get_kwargs(),**kwargs} )
59
- self.do_clean(**{**self.get_kwargs(),**kwargs})
60
-
61
- def process_export(self, start_pages, **kwargs):
62
- stashed_node_func(start_pages[self.processes[0]].root, self.generate_export, **{**self.get_kwargs(),**kwargs} )
63
- self.do_clean(**{**self.get_kwargs(),**kwargs})
64
-
65
-
66
- # node function
67
- @abc.abstractmethod
68
- def generate_calculate(self, node, **kwargs ):
69
- pass
70
- @abc.abstractmethod
71
- def generate_base(self, node, **kwargs):
72
- pass
73
-
74
-
75
- @abc.abstractmethod
76
- def generate_relevance(self, node, **kwargs):
77
- pass
78
-
79
-
80
- @abc.abstractmethod
81
- def generate_export(self, node, **kwargs):
82
- pass
83
-
84
- @abc.abstractmethod
85
- def export(self, **kwargs):
86
- pass
87
-
88
- ## Utils
89
- def do_clean(self, **kwargs):
90
- pass
91
- def get_kwargs(self):
92
- return {}