tricc-oo 1.5.26__py3-none-any.whl → 1.6.14__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 CHANGED
@@ -6,6 +6,7 @@ from tricc_oo.strategies.output.xls_form import XLSFormStrategy # noqa: F401
6
6
  from tricc_oo.strategies.output.openmrs_form import OpenMRSStrategy # noqa: F401
7
7
  from tricc_oo.strategies.output.fhir_form import FHIRStrategy # noqa: F401
8
8
  from tricc_oo.strategies.output.html_form import HTMLStrategy # noqa: F401
9
+ from tricc_oo.strategies.output.dhis2_form import DHIS2Strategy # noqa: F401
9
10
  from tricc_oo.strategies.input.drawio import DrawioStrategy # noqa: F401
10
11
  import getopt
11
12
  import logging
@@ -31,16 +31,16 @@ def extract_properties_metadata(fhir_cs: CodeSystem) -> Dict[str, Dict]:
31
31
 
32
32
  property_types[prop.code] = {
33
33
  "name": prop.code,
34
- "datatype": ocl_type,
34
+ "dataType": ocl_type,
35
35
  "description": prop.description if hasattr(prop, "description") else "",
36
36
  }
37
37
  return property_types
38
38
 
39
39
 
40
40
  def get_fhir_concept_datatype(concept):
41
- datatype = extract_concept_properties(concept, ["datatype"])
41
+ datatype = extract_concept_properties(concept, ["dataType"])
42
42
  if datatype:
43
- return datatype["datatype"]
43
+ return datatype["dataType"]
44
44
  else:
45
45
  return OclConstants.DATA_TYPE_NONE
46
46
 
@@ -84,7 +84,7 @@ def get_attributes_from_concept_properties(concept, property_types: Dict) -> Lis
84
84
  "type": "Attribute",
85
85
  "attribute_type": code,
86
86
  "value": value,
87
- "value_type": property_types[code]["datatype"],
87
+ "value_type": property_types[code]["dataType"],
88
88
  }
89
89
  )
90
90
  return attributes
@@ -103,7 +103,7 @@ def check_and_add_concept(code_system: CodeSystem, code: str, display: str, attr
103
103
  # TODO support other type of Codesystem Concept Property Value
104
104
  existing_attributes
105
105
  if p.valueString != v:
106
- logger.warning(f"conflicting value for property {k}: {p.valueString} != {v}")
106
+ logger.warning(f"conflicting value for concept `{concept.code}` property ` {k}`: {p.valueString} != {v}")
107
107
  if not existing_attributes:
108
108
  new_concept.property.append(CodeSystemConceptProperty(code=k, valueString=v))
109
109
 
@@ -47,7 +47,7 @@ TYPE_MAP = {
47
47
  },
48
48
  TriccNodeType.note: {
49
49
  "objects": ["UserObject", "object"],
50
- "attributes": ["relevance", "priority", "context_type"],
50
+ "attributes": ["relevance", "priority", "concept_type"],
51
51
  "mandatory_attributes": ["label", "name"],
52
52
  "model": TriccNodeNote,
53
53
  },
@@ -76,7 +76,7 @@ TYPE_MAP = {
76
76
  "priority",
77
77
  "trigger",
78
78
  "default",
79
- "context_type",
79
+ "concept_type",
80
80
  ],
81
81
  "mandatory_attributes": ["label", "name", "list_name"],
82
82
  "model": TriccNodeSelectOne,
@@ -94,7 +94,7 @@ TYPE_MAP = {
94
94
  "priority",
95
95
  "trigger",
96
96
  "default",
97
- "context_type",
97
+ "concept_type",
98
98
  ],
99
99
  "mandatory_attributes": ["label", "name", "list_name"],
100
100
  "model": TriccNodeSelectMultiple,
@@ -112,7 +112,7 @@ TYPE_MAP = {
112
112
  "priority",
113
113
  "trigger",
114
114
  "default",
115
- "context_type",
115
+ "concept_type",
116
116
  ],
117
117
  "mandatory_attributes": ["label", "name"],
118
118
  "model": TriccNodeDecimal,
@@ -130,7 +130,7 @@ TYPE_MAP = {
130
130
  "priority",
131
131
  "trigger",
132
132
  "default",
133
- "context_type",
133
+ "concept_type",
134
134
  ],
135
135
  "mandatory_attributes": ["label", "name"],
136
136
  "model": TriccNodeInteger,
@@ -145,7 +145,7 @@ TYPE_MAP = {
145
145
  "default",
146
146
  "constraint",
147
147
  "constraint_message",
148
- "context_type",
148
+ "concept_type",
149
149
  ],
150
150
  "mandatory_attributes": ["label", "name"],
151
151
  "model": TriccNodeText,
@@ -160,7 +160,7 @@ TYPE_MAP = {
160
160
  "default",
161
161
  "constraint",
162
162
  "constraint_message",
163
- "context_type",
163
+ "concept_type",
164
164
  ],
165
165
  "mandatory_attributes": ["label", "name"],
166
166
  "model": TriccNodeDate,
@@ -183,7 +183,7 @@ TYPE_MAP = {
183
183
  "save",
184
184
  "reference",
185
185
  "trigger",
186
- "context_type",
186
+ "concept_type",
187
187
  "remote_reference",
188
188
  ],
189
189
  "mandatory_attributes": ["name", "label"],
@@ -217,7 +217,7 @@ TYPE_MAP = {
217
217
  },
218
218
  TriccNodeType.not_available: {
219
219
  "objects": ["UserObject", "object"],
220
- "attributes": ["context_type"],
220
+ "attributes": ["concept_type"],
221
221
  "mandatory_attributes": ["label", "name", "list_name"],
222
222
  "model": TriccNodeSelectNotAvailable,
223
223
  },
@@ -233,7 +233,7 @@ TYPE_MAP = {
233
233
  "priority",
234
234
  "trigger",
235
235
  "default",
236
- "context_type",
236
+ "concept_type",
237
237
  ],
238
238
  "mandatory_attributes": ["label", "name", "list_name"],
239
239
  "model": TriccNodeSelectYesNo,
@@ -295,7 +295,7 @@ TYPE_MAP = {
295
295
  },
296
296
  TriccNodeType.input: {
297
297
  "objects": ["UserObject", "object"],
298
- "attributes": ["save", "reference", "datatype", "context_type"],
298
+ "attributes": ["save", "reference", "data_type", "concept_type"],
299
299
  "mandatory_attributes": ["name", "label"],
300
300
  "model": TriccNodeInput,
301
301
  },
@@ -1,6 +1,6 @@
1
1
  import logging
2
- from tricc_oo.converters.utils import clean_name, clean_str
3
- from tricc_oo.models.tricc import TriccNodeSelectOption, TRICC_TRUE_VALUE, TRICC_FALSE_VALUE
2
+ from tricc_oo.converters.utils import clean_name
3
+ from tricc_oo.models.tricc import TriccNodeSelectOption, TRICC_TRUE_VALUE, TRICC_FALSE_VALUE, TriccNodeActivity
4
4
  from tricc_oo.models.calculate import TriccNodeInput
5
5
  from tricc_oo.models.base import TriccNodeBaseModel, TriccStatic, TriccReference
6
6
 
@@ -36,13 +36,15 @@ def get_export_name(node, replace_dots=True):
36
36
  elif isinstance(node, bool):
37
37
  return BOOLEAN_MAP[str(TRICC_TRUE_VALUE)] if node else BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]
38
38
  elif isinstance(node, TriccReference):
39
- logger.warning(f"Reference {node.value} use in export, bad serialiuation probable")
39
+ logger.warning(f"Reference {node.value} use in export, bad serialization probable")
40
40
  return str(node.value)
41
41
  elif isinstance(node, (str, TriccStatic, TriccNodeSelectOption)):
42
42
  if isinstance(node, TriccNodeSelectOption):
43
43
  value = node.name
44
44
  elif isinstance(node, TriccStatic):
45
45
  value = node.value
46
+ if isinstance(value, TriccNodeSelectOption):
47
+ value = value.name
46
48
  else:
47
49
  value = node
48
50
  if isinstance(value, bool): # or r.value in ('true', 'false')
@@ -51,10 +53,12 @@ def get_export_name(node, replace_dots=True):
51
53
  export_name = BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]
52
54
  elif value == TRICC_FALSE_VALUE:
53
55
  export_name = BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]
54
- elif isinstance(value, str):
55
- export_name = f"'{clean_str(value, replace_dots=replace_dots)}'"
56
+ elif value == '$this':
57
+ export_name = '.'
58
+ elif isinstance(value, str) and not isinstance(node, str):
59
+ export_name = f"'{value}'"
56
60
  else:
57
- export_name = str(value)
61
+ export_name = value
58
62
  if hasattr(node, 'export_name'):
59
63
  node.export_name = export_name
60
64
  return export_name
@@ -62,7 +66,12 @@ def get_export_name(node, replace_dots=True):
62
66
  return node
63
67
  else:
64
68
  node.gen_name()
65
- if isinstance(node, TriccNodeSelectOption):
69
+ if isinstance(node, TriccNodeActivity) and getattr(node, 'instance', 1) > 1:
70
+ node.export_name = clean_name(
71
+ node.name + INSTANCE_SEPARATOR + str(node.instance),
72
+ replace_dots=replace_dots,
73
+ )
74
+ elif isinstance(node, TriccNodeSelectOption):
66
75
  node.export_name = node.name
67
76
  elif node.last is False:
68
77
  node.export_name = clean_name(
@@ -7,7 +7,7 @@ import re
7
7
 
8
8
  from tricc_oo.converters.utils import remove_html, clean_str
9
9
  from tricc_oo.converters.cql_to_operation import transform_cql_to_operation
10
- from tricc_oo.converters.utils import generate_id, get_rand_name
10
+ from tricc_oo.converters.utils import generate_id
11
11
  from tricc_oo.models.base import (
12
12
  TriccOperator, TriccOperation,
13
13
  TriccStatic, TriccReference, TriccNodeType, TriccEdge, OPERATION_LIST
@@ -101,16 +101,16 @@ def create_activity(diagram, media_path, project):
101
101
 
102
102
  external_id = diagram.attrib.get("id")
103
103
  id = get_id(external_id, diagram.attrib.get("id"))
104
- root = create_root_node(diagram)
105
- name = diagram.attrib.get("name")
104
+ root, name = create_root_node(diagram)
105
+ label = diagram.attrib.get("name")
106
106
  form_id = diagram.attrib.get("name", None)
107
107
  if root is not None:
108
108
  activity = TriccNodeActivity(
109
109
  root=root,
110
- name=get_rand_name(f"a{id}"),
110
+ name=name, # start node 'name' is saved in label
111
111
  id=id,
112
112
  external_id=external_id,
113
- label=name,
113
+ label=label,
114
114
  form_id=form_id,
115
115
  )
116
116
  if root.relevance is not None:
@@ -128,9 +128,9 @@ def create_activity(diagram, media_path, project):
128
128
  for n in nodes.values():
129
129
 
130
130
  if (
131
- issubclass(n.__class__, (TriccNodeDisplayModel, TriccNodeDisplayCalculateBase))
131
+ issubclass(n.__class__, (TriccNodeDisplayModel, TriccNodeDisplayCalculateBase, TriccNodeInput))
132
132
  and not isinstance(n, (TriccRhombusMixIn, TriccNodeRhombus, TriccNodeDisplayBridge))
133
- and not n.name.startswith("label_")
133
+ and not n.name.startswith("label_") # FIXME
134
134
  ):
135
135
  system = n.name.split(".")[0] if "." in n.name else "tricc"
136
136
  if isinstance(n, TriccNodeSelectOption) and isinstance(n.select, TriccNodeSelectNotAvailable):
@@ -139,7 +139,7 @@ def create_activity(diagram, media_path, project):
139
139
  system,
140
140
  n.select.name,
141
141
  n.label,
142
- {"datatype": "Boolean", "contextType": get_context_type(n)},
142
+ {"dataType": "Boolean", "conceptType": get_concept_type(n)},
143
143
  )
144
144
  elif not isinstance(n, TriccNodeSelectNotAvailable):
145
145
  add_concept(
@@ -148,8 +148,20 @@ def create_activity(diagram, media_path, project):
148
148
  n.name,
149
149
  n.label,
150
150
  {
151
- "datatype": get_data_type(n.tricc_type),
152
- "contextType": get_context_type(n),
151
+ "dataType": get_data_type(n.tricc_type),
152
+ "conceptType": get_concept_type(n),
153
+ },
154
+ )
155
+ elif not issubclass(n.__class__, TriccNodeCalculate):
156
+ system = n.name.split(".")[0] if "." in n.name else "calculate"
157
+ add_concept(
158
+ project.code_systems,
159
+ system,
160
+ n.name,
161
+ n.label,
162
+ {
163
+ "dataType": get_data_type(n.tricc_type),
164
+ "conceptType": get_concept_type(n),
153
165
  },
154
166
  )
155
167
  if getattr(n, "save", None):
@@ -160,8 +172,8 @@ def create_activity(diagram, media_path, project):
160
172
  n.save,
161
173
  n.label,
162
174
  {
163
- "datatype": get_data_type(n.tricc_type),
164
- "contextType": get_context_type(n),
175
+ "dataType": get_data_type(n.tricc_type),
176
+ "conceptType": get_concept_type(n),
165
177
  },
166
178
  )
167
179
 
@@ -175,7 +187,7 @@ def create_activity(diagram, media_path, project):
175
187
  # link back the activity
176
188
  activity.root.activity = activity
177
189
  manage_dangling_calculate(activity)
178
-
190
+ # assign the process
179
191
  if activity is not None:
180
192
  if activity.root is not None:
181
193
  project.pages[activity.id] = activity
@@ -197,6 +209,7 @@ def create_activity(diagram, media_path, project):
197
209
  )
198
210
  if images:
199
211
  project.images += images
212
+ # Assign parent to NotAvailable
200
213
  for node in list(
201
214
  filter(
202
215
  lambda p_node: isinstance(p_node, TriccNodeSelectNotAvailable),
@@ -444,17 +457,18 @@ def create_root_node(diagram):
444
457
  if elm is not None:
445
458
  external_id = elm.attrib.get("id")
446
459
  id = get_id(external_id, diagram.attrib.get("id"))
460
+ name = generate_id("start"+external_id)
447
461
  node = TriccNodeActivityStart(
448
462
  id=id,
449
463
  external_id=external_id,
450
464
  # parent=elm.attrib.get("parent"),
451
- name="ma" + id,
465
+ name=name,
452
466
  label=diagram.attrib.get("name"),
453
467
  relevance=elm.attrib.get("relevance"),
454
468
  instance=int(elm.attrib.get("instance") if elm.attrib.get("instance") is not None else 1),
455
469
  )
456
470
  load_expressions(node)
457
- return node
471
+ return node, _get_name(elm.attrib.get("name", "act_"), external_id, diagram.attrib.get("id")) if node else None
458
472
 
459
473
 
460
474
  # converter XML item to object
@@ -476,10 +490,10 @@ def set_additional_attributes(attribute_names, elm, node):
476
490
  setattr(node, attributename, attribute)
477
491
 
478
492
 
479
- def get_context_type(node):
480
- context_type = getattr(node, "context_type", None)
481
- if context_type:
482
- return context_type
493
+ def get_concept_type(node):
494
+ concept_type = getattr(node, "concept_type", None)
495
+ if concept_type:
496
+ return concept_type
483
497
  if isinstance(node, TriccNodeSelectMultiple):
484
498
  return "Question"
485
499
  elif isinstance(node, TriccNodeSelectOption):
@@ -534,7 +548,7 @@ def get_select_options(diagram, select_node, nodes):
534
548
  activity=select_node.activity,
535
549
  group=select_node.group,
536
550
  )
537
- set_additional_attributes(["save", "relevance", "context_type"], elm, option)
551
+ set_additional_attributes(["save", "relevance", "concept_type"], elm, option)
538
552
  load_expressions(option)
539
553
  options[i] = option
540
554
  nodes[id] = option
@@ -624,6 +638,8 @@ def enrich_node(diagram, media_path, edge, node, activity, help_before=False):
624
638
  name=f"{node.name}.more_info",
625
639
  label=message,
626
640
  parent=node,
641
+ group=node.group,
642
+ activity=node.activity,
627
643
  required=None,
628
644
  )
629
645
  # node.help = message
@@ -799,9 +815,11 @@ def set_mandatory_attribute(elm, mandatory_attributes, diagram=None):
799
815
  id = elm.attrib.get("id")
800
816
  attribute_value = _get_name(name, id, diagram_id)
801
817
  elif attributes == "list_name":
802
- name = elm.attrib.get("name")
803
- id = elm.attrib.get("id")
804
- attribute_value = TRICC_LIST_NAME.format(clean_str(_get_name(name, id, diagram_id), replace_dots=True))
818
+ attribute_value = elm.attrib.get("list_name", None)
819
+ if not attribute_value:
820
+ name = elm.attrib.get("name")
821
+ id = elm.attrib.get("id")
822
+ attribute_value = TRICC_LIST_NAME.format(clean_str(_get_name(name, id, diagram_id), replace_dots=True))
805
823
  else:
806
824
  attribute_value = elm.attrib.get(attributes)
807
825
  if attribute_value is None:
tricc_oo/models/base.py CHANGED
@@ -11,7 +11,7 @@ from tricc_oo.models.ordered_set import OrderedSet
11
11
 
12
12
  logger = logging.getLogger("default")
13
13
 
14
- Expression = Annotated[str, StringConstraints(pattern=r"^[^\\/\:]+$")]
14
+ Expression = Annotated[str, StringConstraints(pattern=r".+")]
15
15
 
16
16
  triccId = Annotated[str, StringConstraints(pattern=r"^[^\\/\: ]+$")]
17
17
 
@@ -274,7 +274,7 @@ class TriccNodeBaseModel(TriccBaseModel):
274
274
 
275
275
 
276
276
  class TriccStatic(BaseModel):
277
- value: Union[str, float, int, bool]
277
+ value: Union[str, float, int, bool, TriccNodeBaseModel]
278
278
 
279
279
  def __init__(self, value):
280
280
  super().__init__(value=value)
@@ -494,6 +494,8 @@ class TriccOperation(BaseModel):
494
494
  return "mixed"
495
495
  else:
496
496
  return rtype.pop()
497
+ else:
498
+ return self.get_reference_datatype(self.reference)
497
499
 
498
500
  def get_reference_datatype(self, references):
499
501
  rtype = set()
@@ -6,16 +6,17 @@ from tricc_oo.converters.tricc_to_xls_form import (
6
6
  get_export_name, BOOLEAN_MAP
7
7
  )
8
8
  from tricc_oo.models.lang import SingletonLangClass
9
- from tricc_oo.converters.utils import clean_name, remove_html
9
+ from tricc_oo.converters.utils import clean_name, remove_html, generate_id
10
10
  from tricc_oo.models.base import (
11
11
  TriccOperator,
12
12
  TriccOperation, TriccStatic, TriccReference, and_join, TriccNodeType
13
13
  )
14
14
  from tricc_oo.models.calculate import (
15
15
  TriccNodeDisplayCalculateBase,
16
+ TriccNodeCalculate
16
17
  )
17
18
  from tricc_oo.models.tricc import (
18
- TriccNodeActivity, TriccNodeBaseModel, TriccNodeSelectMultiple, TriccNodeSelectOption,
19
+ TriccNodeBaseModel, TriccNodeSelectMultiple, TriccNodeSelectOption,
19
20
  TriccNodeSelectOne,
20
21
  TriccNodeSelect,
21
22
  TriccNodeMoreInfo,
@@ -31,6 +32,7 @@ from tricc_oo.visitors.tricc import (
31
32
  get_applicability_expression,
32
33
  get_prev_instance_skip_expression,
33
34
  get_process_skip_expression,
35
+ process_operation_reference,
34
36
  )
35
37
 
36
38
  logger = logging.getLogger("default")
@@ -39,6 +41,9 @@ langs = SingletonLangClass()
39
41
  TRICC_CALC_EXPRESSION = "${{{0}}}>0"
40
42
 
41
43
 
44
+ def get_export_group_name(in_node): return f"gcalc_{get_export_name(in_node)}"
45
+
46
+
42
47
  def start_group(
43
48
  strategy,
44
49
  cur_group,
@@ -58,10 +63,38 @@ def start_group(
58
63
 
59
64
  else:
60
65
  groups[name] = 0
61
- is_activity = isinstance(cur_group, TriccNodeActivity)
62
66
  relevance = relevance and cur_group.relevance is not None and cur_group.relevance != ""
67
+ past_instances = len(getattr(cur_group.base_instance, "instances", []))
68
+ group_calc_required = relevance is not None and (len(str(relevance)) > 100 or past_instances > 1)
69
+ calc = None
70
+ if group_calc_required and getattr(cur_group.relevance, 'operator', None) != TriccOperator.ISTRUE:
71
+
72
+ calc = TriccNodeCalculate(
73
+ id=generate_id(get_export_group_name(name)),
74
+ group=cur_group.group,
75
+ activity=cur_group.activity,
76
+ name=get_export_group_name(name),
77
+ expression=cur_group.relevance
78
+ )
79
+
80
+ if calc not in cur_group.activity.calculates:
81
+ process_reference(
82
+ calc,
83
+ processed_nodes,
84
+ calculates=kwargs.get('calculates', None),
85
+ used_calculates=kwargs.get('used_calculates', None),
86
+ replace_reference=True,
87
+ warn=False,
88
+ codesystems=kwargs.get('codesystems', None)
89
+ )
90
+ cur_group.activity.calculates.append(calc)
91
+ cur_group.activity.nodes[calc.id] = calc
92
+ processed_nodes.add(calc)
63
93
 
64
- group_calc_required = False and relevance and not is_activity and len(relevance) > 100
94
+ cur_group.relevance = TriccOperation(
95
+ TriccOperator.ISTRUE,
96
+ [calc]
97
+ )
65
98
 
66
99
  relevance_expression = cur_group.relevance
67
100
  relevance_expression = get_applicability_expression(cur_group, processed_nodes, process, relevance_expression)
@@ -69,14 +102,20 @@ def start_group(
69
102
  relevance_expression = get_process_skip_expression(cur_group, processed_nodes, process, relevance_expression)
70
103
 
71
104
  if not relevance:
72
- relevance_expression = ""
105
+ relevance_expression_str = ""
73
106
  elif isinstance(relevance_expression, (TriccOperation, TriccStatic)):
74
- relevance_expression = strategy.get_tricc_operation_expression(relevance_expression)
75
-
76
- # elif is_activity:
77
- # relevance_expression = TRICC_CALC_EXPRESSION.format(get_export_name(cur_group.root))
78
- elif group_calc_required:
79
- relevance_expression = TRICC_CALC_EXPRESSION.format("gcalc_" + name)
107
+ relevance_expression = process_operation_reference(
108
+ relevance_expression,
109
+ cur_group,
110
+ processed_nodes=processed_nodes,
111
+ calculates=kwargs.get('calculates', None),
112
+ used_calculates=kwargs.get('used_calculates', None),
113
+ replace_reference=True,
114
+ warn=False,
115
+ codesystems=kwargs.get('codesystems', None),
116
+ ) or relevance_expression
117
+ if relevance_expression:
118
+ relevance_expression_str = strategy.get_tricc_operation_expression(relevance_expression)
80
119
 
81
120
  # group
82
121
  values = []
@@ -91,23 +130,23 @@ def start_group(
91
130
  if relevance_expression is True:
92
131
  values.append("")
93
132
  else:
94
- values.append(relevance_expression)
133
+ values.append(relevance_expression_str)
95
134
 
96
135
  else:
97
136
  values.append(get_xfrom_trad(strategy, cur_group, column, SURVEY_MAP))
98
137
  df_survey.loc[len(df_survey)] = values
99
138
 
100
139
  # calc
101
- if group_calc_required and len(df_calculate[df_calculate["name"] == "gcalc_" + name]) == 0:
140
+ if calc and len(df_calculate[df_calculate["name"] == get_export_group_name(name)]) == 0:
102
141
  calc_values = []
103
142
  for column in SURVEY_MAP:
104
143
  if column == "type":
105
144
  calc_values.append("calculate")
106
145
  elif column == "name":
107
- value = "gcalc_" + name
146
+ value = get_export_name(calc)
108
147
  calc_values.append(value)
109
148
  elif column == "calculation":
110
- calc_values.append(get_attr_if_exists(strategy, cur_group, "relevance", SURVEY_MAP))
149
+ calc_values.append(f"number({strategy.get_tricc_operation_expression(calc.expression)})")
111
150
  elif column == "relevance":
112
151
  calc_values.append("")
113
152
  else:
@@ -376,7 +415,7 @@ def get_attr_if_exists(strategy, node, column, map_array):
376
415
 
377
416
  elif isinstance(value, (TriccOperation, TriccStatic, TriccReference)):
378
417
  expression = strategy.get_tricc_operation_expression(value)
379
- return expression.replace("$this", ".") if isinstance(expression, str) else expression
418
+ return expression
380
419
  elif value is not None:
381
420
  return str(value) if not isinstance(value, dict) else value
382
421
  else:
@@ -399,7 +438,7 @@ def get_more_info_select(strategy, node):
399
438
  if column == "type":
400
439
  values.append("select_one more_info")
401
440
  elif column == "label":
402
- values.append("NO_LABEL")
441
+ values.append(strategy.get_empty_label())
403
442
  elif column == "name":
404
443
  values.append(get_export_name(node) + "_optin")
405
444
  elif column == "hint":
@@ -43,6 +43,9 @@ class BaseOutPutStrategy:
43
43
 
44
44
  self.export(self.project.start_pages, version=version)
45
45
 
46
+ logger.info("validate the output")
47
+ self.validate()
48
+
46
49
  # walking function
47
50
  def process_base(self, start_pages, **kwargs):
48
51
  # for each node, check if condition is required issubclass(TriccNodeDisplayModel)
@@ -106,6 +109,10 @@ class BaseOutPutStrategy:
106
109
  def export(self, **kwargs):
107
110
  pass
108
111
 
112
+ @abc.abstractmethod
113
+ def validate(self):
114
+ pass
115
+
109
116
  def tricc_operation_equal(self, ref_expressions):
110
117
  # r[0] = r[1]
111
118
  raise NotImplementedError("This type of opreration is not supported in this strategy")