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
tricc/parsers/xml.py DELETED
@@ -1,81 +0,0 @@
1
- from typing import List
2
-
3
- import lxml.etree as etree
4
-
5
-
6
- type_name = 'odk_type'
7
-
8
- def read_drawio(filepath):
9
-
10
- root = etree.parse(filepath)
11
- # import xml.etree.cElementTree as ET
12
- #with open(filepath) as f:
13
- #add a fake root so etree can work
14
- #it = itertools.chain('<root>', f, '</root>')
15
- #etree = ET.fromstringlist(it)
16
- #get all the pages
17
- diagram_list = root.findall('//diagram')
18
-
19
- return diagram_list
20
-
21
-
22
-
23
- def get_container_media(diagram, container_id):
24
- # get the edge
25
- return diagram.find(f".//object[@{type_name}='container_hint_media' and @id='{container_id}']")
26
- #get the image node
27
-
28
- def get_tricc_type(diagram, node_type, tricc_type):
29
- return diagram.find(f'.//{node_type}[@{type_name}="{str(tricc_type)}"]')
30
-
31
-
32
- def get_tricc_type_list(diagram, node_type, tricc_type=None, parent_id = None):
33
- tricc_type = str(tricc_type)
34
-
35
- parent_suffix = f"[@parent='{parent_id}']" if parent_id is not None else ''
36
- if isinstance(tricc_type, list):
37
- result = []
38
- for type_ in tricc_type:
39
- result += get_tricc_type_list(diagram, node_type, type_, parent_id)
40
- return list(set(result))
41
- if isinstance(node_type, list):
42
- result = []
43
- for type_ in node_type:
44
- result += get_tricc_type_list(diagram, type_, tricc_type, parent_id)
45
- return list(set(result))
46
- elif tricc_type is None:
47
- return list(diagram.findall(f'.//{node_type}[@{type_name}]{parent_suffix}'))
48
- else:
49
- return list(diagram.findall(f'.//{node_type}[@{type_name}="{tricc_type}"]{parent_suffix}'))
50
-
51
- def get_mxcell_parent_list(diagram, select_id, tricc_type =None, attrib = None):
52
- #get the mxcels
53
- if tricc_type is None:
54
- if attrib is not None:
55
- return diagram.findall(f".//mxCell[@parent='{select_id}']/..[@{attrib}]")
56
- else:
57
- return diagram.findall(f".//mxCell[@parent='{select_id}']")
58
- elif isinstance(tricc_type, List):
59
- result = []
60
- for type in tricc_type:
61
- result += get_mxcell_parent_list(diagram, select_id, type)
62
- return result
63
- else:
64
- return diagram.findall(f".//mxCell[@parent='{select_id}']/..[@{type_name}='{tricc_type}']")
65
-
66
- def get_mxcell(diagram, id):
67
- return diagram.find(f".//*[@id='{id}']")
68
-
69
- def get_edges_list(diagram):
70
- #return list(diagram.findall('.//mxCell[@edge][@source][@target]'))
71
- # to ensure source and target one can use this xpath above but better trigger a pydantic error if source/target are missing
72
- return list(set( diagram.findall('.//mxCell[@edge][@source]') + diagram.findall('.//mxCell[@edge][@target]')))
73
-
74
-
75
- def get_select_option_image(diagram, select_option_id):
76
- # get the edge
77
- edge=diagram.find(f".//mxCell[@edge and @target='{select_option_id}']")
78
- #get the image node
79
- if edge is not None and edge.attrib.get('source') is not None:
80
- return diagram.find(f".//mxCell[@id='{edge.attrib.get('source')}' and not(@{type_name}) and not(@edge)]")
81
-
@@ -1,364 +0,0 @@
1
-
2
-
3
- import logging
4
-
5
- from tricc.converters.tricc_to_xls_form import (TRICC_CALC_EXPRESSION,
6
- negate_term, VERSION_SEPARATOR,INSTANCE_SEPARATOR, get_export_name)
7
- from tricc.converters.utils import clean_name, remove_html
8
- from tricc.models.lang import SingletonLangClass
9
- from tricc.models.tricc import *
10
-
11
- logger = logging.getLogger('default')
12
-
13
- langs = SingletonLangClass()
14
-
15
-
16
- def start_group( cur_group, groups, df_survey, df_calculate, relevance = False, **kargs):
17
- name = get_export_name(cur_group)
18
-
19
- if name in groups:
20
- groups[name] += 1
21
- name = (name + "_" + str(groups[name]))
22
-
23
- else:
24
- groups[name] = 0
25
- is_activity = isinstance(cur_group,TriccNodeActivity)
26
- relevance = relevance and cur_group.relevance is not None and cur_group.relevance != ''
27
- group_calc_required = False and relevance and not is_activity and len(relevance)> 100
28
-
29
-
30
-
31
- relevance_expression = cur_group.relevance
32
- if not relevance:
33
- relevance_expression = ''
34
- #elif is_activity:
35
- # relevance_expression = TRICC_CALC_EXPRESSION.format(get_export_name(cur_group.root))
36
- elif group_calc_required:
37
- relevance_expression = TRICC_CALC_EXPRESSION.format("gcalc_" + name)
38
-
39
- ## group
40
- values = []
41
- for column in SURVEY_MAP:
42
- if column == 'type':
43
- values.append('begin group')
44
- elif column == 'name':
45
- values.append(name)
46
- elif column == 'appearance':
47
- values.append('field-list')
48
- elif column == 'relevance':
49
- values.append(relevance_expression)
50
- else:
51
- values.append(get_xfrom_trad(cur_group,column,SURVEY_MAP))
52
- df_survey.loc[len(df_survey)] = values
53
-
54
- ### calc
55
- if group_calc_required and len(df_calculate[df_calculate['name'] == "gcalc_" + name]) == 0:
56
- calc_values =[]
57
- for column in SURVEY_MAP:
58
- if column == 'type':
59
- calc_values.append('calculate')
60
- elif column == 'name':
61
- value = "gcalc_" + name
62
- calc_values.append(value)
63
- elif column == 'calculation':
64
- calc_values.append(get_attr_if_exists(cur_group,'relevance',SURVEY_MAP))
65
- elif column == 'relevance':
66
- calc_values.append('')
67
- else:
68
- calc_values.append(get_xfrom_trad(cur_group,column,SURVEY_MAP))
69
-
70
- df_calculate.loc[len(df_calculate)] = calc_values
71
-
72
-
73
-
74
- def end_group( cur_group, groups, df_survey, **kargs):
75
-
76
- values = []
77
- for column in SURVEY_MAP:
78
- if column == 'type':
79
- values.append('end group')
80
- elif column == 'relevance':
81
- values.append('')
82
- elif column in ('name'):
83
- value = (get_attr_if_exists(cur_group,column,SURVEY_MAP))
84
-
85
- if get_export_name(cur_group) in groups:
86
- value = (value + "_" + str(groups[get_export_name(cur_group)]))
87
- values.append(value)
88
- else:
89
- values.append(get_xfrom_trad(cur_group,column,SURVEY_MAP))
90
- df_survey.loc[len(df_survey)] = values
91
-
92
-
93
- # waltk thought the node,
94
- # if node has group, open the group (and parent group)
95
- # check process the next_node with the same group first, then process the other
96
-
97
- # if node has another group (not current) close the group
98
- # if node is an activity close the group
99
-
100
- # during tricc object building/ or par of the stategy
101
- # static calculte node with same name:
102
- # follow same approach as the dynamic
103
- # if reference not in used_saves
104
- # , then create calculate node reference_1 # and save is used_saves 'reference' : 1
105
- # else create calculate node reference_(used_saves['reference']+1) # and update used_saves['reference'] += 1
106
- # once done, walkthrough again and remame reference_(used_saves['reference']) to reference and create the other save
107
- ODK_TRICC_TYPE_MAP = { 'note':'note'
108
- ,'calculate':'calculate'
109
- ,'select_multiple':'select_multiple'
110
- ,'select_one':'select_one'
111
- ,'decimal':'decimal'
112
- ,'integer':'integer'
113
- ,'text':'text'
114
- ,'rhombus':'calculate'
115
- ,'goto':''#: start the linked activity within the target activity
116
- ,'start':''
117
- ,'activity_start':'calculate'
118
- ,'link_in':''
119
- ,'link_out':''
120
- ,'count':'calculate'
121
- ,'add':'calculate'
122
- ,'container_hint_media':''
123
- ,'activity':''
124
- ,'select_option':''
125
- ,'hint':''
126
- ,'help':''
127
- ,'exclusive':'calculate'
128
- ,'end':'calculate'
129
- ,'activity_end':'calculate'
130
- ,'edge':''
131
- ,'page':''
132
- ,'bridge':'calculate'
133
- ,'date':'date'
134
- }
135
-
136
- GROUP_TRICC_TYPE = [TriccNodeType.page,TriccNodeType.activity]
137
-
138
- SURVEY_MAP = {
139
- 'type':ODK_TRICC_TYPE_MAP, 'name':'name',
140
- **langs.get_trads_map('label'), **langs.get_trads_map('hint'),
141
- **langs.get_trads_map('help'), 'default':'default',
142
- 'appearance':'appearance', 'constraint':'constraint',
143
- **langs.get_trads_map('constraint_message'), 'relevance':'relevance',
144
- 'disabled':'disabled','required':'required',
145
- **langs.get_trads_map('required_message'), 'read only':'read only',
146
- 'calculation':'expression','repeat_count':'repeat_count','media::image':'image'
147
- }
148
- CHOICE_MAP = {'list_name':'list_name', 'value':'name', **langs.get_trads_map('label') }
149
-
150
-
151
- TRAD_MAP = ['label','constraint_message', 'required_message', 'hint', 'help']
152
-
153
- def get_xfrom_trad(node, column, maping, clean_html = False ):
154
- arr = column.split('::')
155
- column = arr[0]
156
- trad = arr[1] if len(arr)==2 else None
157
- value = get_attr_if_exists(node, column, maping)
158
- if clean_html and isinstance(value, str):
159
- value = remove_html(value)
160
- if column in TRAD_MAP:
161
- value = langs.get_trads(value, trad=trad)
162
-
163
- return value
164
-
165
-
166
-
167
-
168
- def get_attr_if_exists(node,column, map_array):
169
- if column in map_array:
170
- mapping = map_array[column]
171
- if isinstance(mapping, Dict) and node.tricc_type in map_array[column]:
172
- tricc_type = map_array[column][node.tricc_type]
173
- if tricc_type[:6] == "select":
174
- return tricc_type + " " + node.list_name
175
- else:
176
- return tricc_type
177
- elif hasattr(node, map_array[column]):
178
- value = getattr(node, map_array[column])
179
- if column == 'name':
180
- if issubclass(value.__class__, (TriccNodeBaseModel)):
181
- return get_export_name(value)
182
- else:
183
- return get_export_name(node)
184
- elif value is not None:
185
- return str(value) if not isinstance(value,dict) else value
186
- else:
187
- return ''
188
- else:
189
- return ''
190
- elif hasattr(node, column) and getattr(node, column) is not None:
191
- value = getattr(node, column)
192
- return str(value) if not isinstance(value,dict) else value
193
- else:
194
- return ''
195
-
196
-
197
- def generate_xls_form_export(node, processed_nodes, stashed_nodes, df_survey, df_choice,df_calculate, cur_group, **kargs):
198
- # check that all prev nodes were processed
199
- if is_ready_to_process(node,processed_nodes):
200
- if node not in processed_nodes :
201
- if node.group != cur_group and not isinstance(node,TriccNodeSelectOption) :
202
- return False
203
- logger.debug("printing node {}".format(node.get_name()))
204
- # clean stashed node when processed
205
- if node in stashed_nodes:
206
- stashed_nodes.remove(node)
207
- logger.debug("generate_xls_form_export: unstashing processed node{} ".format(node.get_name()))
208
- if issubclass(node.__class__, ( TriccNodeDisplayCalculateBase,TriccNodeDisplayModel)):
209
- if isinstance(node, TriccNodeSelectOption):
210
- values = []
211
- for column in CHOICE_MAP:
212
- values.append(get_xfrom_trad(node, column, CHOICE_MAP, True ))
213
- # add only if not existing
214
- if len(df_choice[(df_choice['list_name'] == node.list_name) & (df_choice['value'] == node.name)]) == 0:
215
- df_choice.loc[len(df_choice)] = values
216
- elif node.tricc_type in ODK_TRICC_TYPE_MAP and ODK_TRICC_TYPE_MAP[node.tricc_type] is not None:
217
- if ODK_TRICC_TYPE_MAP[node.tricc_type] =='calculate':
218
- values = []
219
- for column in SURVEY_MAP:
220
- if column == 'default' and issubclass(node.__class__, TriccNodeDisplayCalculateBase):
221
- values.append(0)
222
- else:
223
- values.append(get_xfrom_trad(node, column, SURVEY_MAP ))
224
- if len(df_calculate[df_calculate.name == get_export_name(node)])==0:
225
- df_calculate.loc[len(df_calculate)] = values
226
- else:
227
- logger.error("name {} found twice".format(node.name))
228
-
229
- elif ODK_TRICC_TYPE_MAP[node.tricc_type] !='':
230
- values = []
231
- for column in SURVEY_MAP:
232
- values.append(get_xfrom_trad(node,column,SURVEY_MAP))
233
- df_survey.loc[len(df_survey)] = values
234
- else:
235
- logger.warning("node {} have an unmapped type {}".format(node.get_name(),node.tricc_type))
236
- else:
237
- logger.warning("node {} have an unsupported type {}".format(node.get_name(),node.tricc_type))
238
- #continue walk °
239
- return True
240
- return False
241
-
242
-
243
- def get_diagnostic_line(node):
244
- label = langs.get_trads(node.label, force_dict =True)
245
- empty = langs.get_trads('', force_dict =True)
246
- return [
247
- 'select_one yes_no',
248
- "cond_"+get_export_name(node),
249
- *list(label.values()) ,
250
- *list(empty.values()) ,#hint
251
- *list(empty.values()) ,#help
252
- '',#default
253
- '',#'appearance', clean_name
254
- '',#'constraint',
255
- *list(empty.values()) ,#'constraint_message'
256
- TRICC_CALC_EXPRESSION.format(get_export_name(node)),#'relevance'
257
- '',#'disabled'
258
- '1',#'required'
259
- *list(empty.values()) ,#'required message'
260
- '',#'read only'
261
- '',#'expression'
262
- '',#'repeat_count'
263
- ''#'image'
264
- ]
265
-
266
- def get_diagnostic_start_group_line():
267
- label = langs.get_trads('List of diagnostics', force_dict =True)
268
- empty = langs.get_trads('', force_dict =True)
269
- return [
270
- 'begin group',
271
- "l_diag_list25",
272
- *list(label.values()) ,
273
- *list(empty.values()) ,#hint
274
- *list(empty.values()) ,#help
275
- '',#default
276
- 'field-list',#'appearance',
277
- '',#'constraint',
278
- *list(empty.values()) ,#'constraint_message'
279
- '',#'relevance'
280
- '',#'disabled'
281
- '',#'required'
282
- *list(empty.values()) ,#'required message'
283
- '',#'read only'
284
- '',#'expression'
285
- '',#'repeat_count'
286
- ''#'image'
287
- ]
288
-
289
- def get_diagnostic_add_line(diags, df_choice):
290
- for diag in diags:
291
- df_choice.loc[len(df_choice)] = [
292
- "tricc_diag_add",
293
- get_export_name(diag),
294
- *list(langs.get_trads(diag.label, True).values())
295
- ]
296
- label = langs.get_trads('Add a missing diagnostic', force_dict =True)
297
- empty = langs.get_trads('', force_dict =True)
298
- return [
299
- 'select_multiple tricc_diag_add',
300
- "new_diag",
301
- *list(label.values()) ,
302
- *list(empty.values()) ,#hint
303
- *list(empty.values()) ,#help
304
- '',#default
305
- 'minimal',#'appearance',
306
- '',#'constraint',
307
- *list(empty.values()) ,#'constraint_message',
308
- '',#'relevance'
309
- '',#'disabled'
310
- '',#'required'
311
- *list(empty.values()) ,#'required message'
312
- '',#'read only'
313
- '',#'expression'
314
- '',#'repeat_count'
315
- ''#'image'
316
- ]
317
-
318
- def get_diagnostic_none_line(diags):
319
- relevance = ''
320
- for diag in diags:
321
- relevance += TRICC_CALC_EXPRESSION.format(get_export_name(diag)) + " or "
322
- label = langs.get_trads('Aucun diagnostic trouvé par l\'outil mais cela ne veut pas dire que le patient est en bonne santé', force_dict =True)
323
- empty = langs.get_trads('', force_dict =True)
324
- return [
325
- 'note',
326
- "l_diag_none25",
327
- *list(label.values()) ,
328
- *list(empty.values()) ,
329
- *list(empty.values()) ,
330
- '',#default
331
- '',#'appearance',
332
- '',#'constraint',
333
- *list(empty.values()) ,
334
- negate_term(relevance[:-4]),#'relevance'
335
- '',#'disabled'
336
- '',#'required'
337
- *list(empty.values()) ,
338
- '',#'read only'
339
- '',#'expression'
340
- '',#'repeat_count'
341
- ''#'image' TRICC_NEGATE
342
- ]
343
-
344
- def get_diagnostic_stop_group_line():
345
- label = langs.get_trads('', force_dict =True)
346
- return [
347
- 'end group',
348
- "l_diag_list25",
349
- *list(label.values()) ,
350
- *list(label.values()) ,
351
- *list(label.values()) ,#help
352
- '',#default
353
- '',#'appearance',
354
- '',#'constraint',
355
- *list(label.values()) ,
356
- '',#'relevance'
357
- '',#'disabled'
358
- '',#'required'
359
- *list(label.values()) ,
360
- '',#'read only'
361
- '',#'expression'
362
- '',#'repeat_count'
363
- ''#'image'
364
- ]
@@ -1,80 +0,0 @@
1
- import abc
2
-
3
- from tricc.models.tricc import (
4
- stashed_node_func,
5
- TriccNodeMainStart,
6
- TriccNodeActivity,
7
- TriccEdge,
8
- )
9
- from tricc.converters.utils import generate_id
10
- from tricc.visitors.tricc import get_activity_wait
11
- from tricc.models.tricc import set_prev_next_node
12
- from itertools import chain
13
- import logging
14
-
15
- logger = logging.getLogger("default")
16
-
17
-
18
- class BaseInputStrategy:
19
- input_path = None
20
-
21
- processes = ["main"]
22
-
23
- def execute_linked_process(self, start_pages, pages):
24
- # create an overall activity only if not specified
25
- if "main" not in start_pages:
26
- # set the first proess as the first form the list
27
- if not self.processes[0] in start_pages:
28
- logger.error(
29
- f"MainStart without process or process in (None, main, {self.processes[0]}) mandatory or this strategy {self.__class__.__name__}"
30
- )
31
- # copie the first root process data to use it on the app level
32
- root_process = start_pages[self.processes[0]][0].root
33
- root = TriccNodeMainStart(
34
- id=generate_id(), form_id=root_process.form_id, label=root_process.label
35
- )
36
- # first sets of activities don't require wait node
37
- root.next_nodes = start_pages[self.processes[0]]
38
-
39
- nodes = {page.id: page for x in start_pages for page in start_pages[x]}
40
- nodes[root.id] = root
41
- app = TriccNodeActivity(
42
- id=generate_id(), name=root_process.name, root=root, nodes=nodes
43
- )
44
- root.activity = app
45
- # loop back to app to avoid None
46
- app.activity = app
47
- app.group = app
48
- # setting the activity/group to main
49
- for n in nodes.values():
50
- n.activity = app
51
- n.group = app
52
- # put a wait between group pf activities
53
- prev_process = start_pages[self.processes[0]]
54
- for p in prev_process:
55
- set_prev_next_node(root, p, edge_only=True)
56
- for process in self.processes[1:]:
57
- if process in start_pages:
58
- wait = get_activity_wait(
59
- [app.root],
60
- prev_process,
61
- start_pages[process],
62
- edge_only=True,
63
- activity=app,
64
- )
65
- app.nodes[wait.id] = wait
66
- prev_process = start_pages[process]
67
- # for p in prev_process:
68
- # set_prev_next_node(root,p)
69
-
70
- return app
71
- else:
72
- return start_pages["main"]
73
-
74
- def __init__(self, input_path):
75
- self.input_path = input_path
76
-
77
- ### walking function
78
- @abc.abstractmethod
79
- def execute(in_filepath, media_path):
80
- pass