tricc-oo 1.6.4__py3-none-any.whl → 1.6.5__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.
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
 
@@ -399,7 +399,7 @@ def get_more_info_select(strategy, node):
399
399
  if column == "type":
400
400
  values.append("select_one more_info")
401
401
  elif column == "label":
402
- values.append("NO_LABEL")
402
+ values.append(strategy.get_empty_label())
403
403
  elif column == "name":
404
404
  values.append(get_export_name(node) + "_optin")
405
405
  elif column == "hint":
@@ -25,6 +25,8 @@ from tricc_oo.models.tricc import (
25
25
  TriccNodeDisplayModel,
26
26
  TriccNodeCalculateBase,
27
27
  TriccNodeActivity,
28
+ TriccNodeSelect,
29
+ TriccNodeSelectYesNo,
28
30
  )
29
31
  from tricc_oo.models.calculate import TriccNodeDisplayCalculateBase
30
32
  from tricc_oo.models.ordered_set import OrderedSet
@@ -66,18 +68,22 @@ class DHIS2Strategy(BaseOutPutStrategy):
66
68
 
67
69
  def get_export_name(self, r):
68
70
  if isinstance(r, TriccNodeSelectOption):
69
- return self.get_option_value(r.name)
71
+ ret = self.get_option_value(r.name)
70
72
  elif isinstance(r, str):
71
- return self.get_option_value(r)
73
+ ret = self.get_option_value(r)
72
74
  elif isinstance(r, TriccStatic):
73
75
  if isinstance(r.value, str):
74
- return self.get_option_value(r.value)
76
+ ret = self.get_option_value(r.value)
75
77
  elif isinstance(r.value, bool):
76
- return str(r.value).lower()
78
+ ret = str(r.value).lower()
77
79
  else:
78
- return r.value
80
+ ret = r.value
81
+ else:
82
+ ret = get_export_name(r)
83
+ if isinstance(ret, str):
84
+ return ret[:50]
79
85
  else:
80
- return get_export_name(r)
86
+ return ret
81
87
 
82
88
  def generate_id(self, name):
83
89
  """Generate DHIS2-compliant UID: 1 letter + 10 alphanumeric characters"""
@@ -139,7 +145,15 @@ class DHIS2Strategy(BaseOutPutStrategy):
139
145
  raise NotImplementedError(
140
146
  f"This type of operation '{operation.operator}' is not supported in this strategy"
141
147
  )
142
-
148
+ def get_display(self, node):
149
+ if hasattr(node, 'label') and node.label:
150
+ ret = node.label
151
+ elif hasattr(node, 'name') and node.name:
152
+ ret = node.name
153
+ else:
154
+ ret = str(node.id)
155
+ return ret.replace('\u00a0', ' ').strip()
156
+
143
157
  def execute(self):
144
158
  version = datetime.datetime.now().strftime("%Y%m%d%H%M")
145
159
  logger.info(f"build version: {version}")
@@ -223,11 +237,13 @@ class DHIS2Strategy(BaseOutPutStrategy):
223
237
  self.program_rule_actions.append(program_rule_action)
224
238
 
225
239
  # Create program rule referencing the action
240
+ condition = self.simplify_expression(f"!({relevance_str})") # Negate for hide when true
241
+ condition = self.simplify_expression(condition)
226
242
  self.program_rules.append({
227
243
  "id": rule_id,
228
- "name": f"Hide {node.get_name()} when condition met",
229
- "description": f"Hide {node.get_name()} based on relevance",
230
- "condition": f"!({relevance_str})", # Negate for hide when true
244
+ "name": f"Hide `{self.get_export_name(node)}` when condition met",
245
+ "description": f"Hide `{self.get_display(node)}` based on relevance",
246
+ "condition": condition,
231
247
  "programRuleActions": [{"id": action_id}]
232
248
  })
233
249
  return True
@@ -257,11 +273,15 @@ class DHIS2Strategy(BaseOutPutStrategy):
257
273
  "id": de_id,
258
274
  "name": self.get_export_name(node),
259
275
  "shortName": node.name[:50],
260
- "displayFormName": getattr(node, 'label', node.name).replace('\u00a0', ' ').strip(),
276
+ "displayFormName":self.get_display(node),
277
+ "formName": self.get_display(node),
261
278
  "valueType": value_type,
262
279
  "domainType": "TRACKER",
263
280
  "aggregationType": "NONE"
264
281
  }
282
+
283
+ if issubclass(node.__class__, TriccNodeSelect) and not isinstance(node, TriccNodeSelectYesNo):
284
+ data_element["optionSetValue"] = True
265
285
 
266
286
  # Only create optionSet for non-boolean select questions
267
287
  if node.tricc_type in ['select_one', 'select_multiple'] and not is_boolean_question:
@@ -273,7 +293,7 @@ class DHIS2Strategy(BaseOutPutStrategy):
273
293
  # Create the actual optionSet definition
274
294
  option_set = {
275
295
  "id": option_set_id,
276
- "name": f"{node.name} Options",
296
+ "name": f"{self.get_export_name(node)} Options",
277
297
  "shortName": f"{node.name}_opts"[:50],
278
298
  "valueType": "TEXT",
279
299
  "options": []
@@ -288,10 +308,10 @@ class DHIS2Strategy(BaseOutPutStrategy):
288
308
  option_name = option_name.replace('\u00a0', ' ').strip()
289
309
  elif isinstance(option_name, TriccStatic):
290
310
  option_name = str(option_name.value)
291
- # Create separate option entity
311
+ # Create separate option entityif
292
312
  option_def = {
293
313
  "id": option_id,
294
- "name": option_name,
314
+ "name": self.get_display(option),
295
315
  "shortName": option.name[:50],
296
316
  "code": str(self.get_export_name(option))
297
317
  }
@@ -303,6 +323,20 @@ class DHIS2Strategy(BaseOutPutStrategy):
303
323
  self.option_sets[option_set_id] = option_set
304
324
 
305
325
  self.data_elements[node.name] = data_element
326
+
327
+ # Create program rule variable for this data element
328
+ var_id = self.generate_id(f"var_{node.name}")
329
+ var_name = self.get_export_name(node)
330
+ program_rule_variable = {
331
+ "id": var_id,
332
+ "name": var_name,
333
+ "programRuleVariableSourceType": "DATAELEMENT_CURRENT_EVENT",
334
+ "dataElement": {"id": de_id},
335
+ "program": {"id": self.program_metadata["id"]}
336
+ }
337
+ self.program_rule_variables.append(program_rule_variable)
338
+ self.concept_map[node.name] = var_name # Store variable name for #{var_name} references
339
+
306
340
  return data_element
307
341
  return None
308
342
 
@@ -325,9 +359,10 @@ class DHIS2Strategy(BaseOutPutStrategy):
325
359
  mock_node = MockNode(operation_datatype)
326
360
  data_type = self.map_tricc_type_to_dhis2_value_type(mock_node)
327
361
 
362
+ var_name = self.get_export_name(node)
328
363
  program_rule_variable = {
329
364
  "id": var_id,
330
- "name": self.get_export_name(node.name)[:50],
365
+ "name": var_name,
331
366
  "programRuleVariableSourceType": "CALCULATED_VALUE",
332
367
  "calculatedValueScript": expression_str,
333
368
  "dataType": data_type,
@@ -336,7 +371,7 @@ class DHIS2Strategy(BaseOutPutStrategy):
336
371
  }
337
372
  self.program_rule_variables.append(program_rule_variable)
338
373
  # Add to concept map for potential referencing
339
- self.concept_map[node.name] = var_id
374
+ self.concept_map[node.name] = var_name # Store variable name
340
375
  return True
341
376
  return False
342
377
 
@@ -674,7 +709,7 @@ class DHIS2Strategy(BaseOutPutStrategy):
674
709
  if isinstance(r, TriccOperation):
675
710
  return self.get_tricc_operation_expression(r)
676
711
  elif isinstance(r, TriccReference):
677
- # Use DHIS2 ID from concept_map instead of name
712
+ # Use variable name from concept_map
678
713
  node_id = self.concept_map.get(r.value.name, self.get_export_name(r.value))
679
714
  return f"#{{{node_id}}}"
680
715
  elif isinstance(r, TriccStatic):
@@ -696,25 +731,39 @@ class DHIS2Strategy(BaseOutPutStrategy):
696
731
  return option
697
732
  return f"'{option}'"
698
733
  elif issubclass(r.__class__, TriccNodeDisplayCalculateBase):
699
- # Use DHIS2 ID from concept_map instead of name
700
- node_id = self.concept_map.get(r.name, self.get_export_name(r))
701
- return f"#{node_id}"
734
+ # Use variable name from concept_map
735
+ node_id = self.get_export_name(r)
736
+ return f"#{{{node_id}}}"
737
+ elif issubclass(r.__class__, TriccNodeCalculateBase):
738
+ # Use variable name from concept_map
739
+ node_id = self.get_export_name(r)
740
+ return f"#{{{node_id}}}"
702
741
  elif issubclass(r.__class__, TriccNodeInputModel):
703
- # Use DHIS2 ID from concept_map instead of name
704
- node_id = self.concept_map.get(r.name, self.get_export_name(r))
742
+ # Use variable name from concept_map
743
+ node_id = self.get_export_name(r)
705
744
  return f"#{{{node_id}}}"
706
745
  elif issubclass(r.__class__, TriccNodeBaseModel):
707
- # Use DHIS2 ID from concept_map instead of name
708
- node_id = self.concept_map.get(r.name, self.get_export_name(r))
746
+ # Use variable name from concept_map
747
+ node_id = self.get_export_name(r)
709
748
  return f"#{{{node_id}}}"
710
749
  else:
711
750
  raise NotImplementedError(f"This type of node {r.__class__.__name__} is not supported within an operation")
712
751
 
752
+ def simplify_expression(self, expr):
753
+ while expr.startswith('!(!(') and expr.endswith('))'):
754
+ expr = expr[4:-2]
755
+ return expr
756
+
713
757
  def convert_expression_to_string(self, expression):
714
758
  if isinstance(expression, TriccOperation):
715
- return self.get_tricc_operation_expression(expression)
759
+ expr = self.get_tricc_operation_expression(expression)
716
760
  else:
717
- return self.get_tricc_operation_operand(expression)
761
+ expr = self.get_tricc_operation_operand(expression)
762
+
763
+ # Simplify double negations
764
+ expr = self.simplify_expression(expr)
765
+
766
+ return expr
718
767
 
719
768
  # Operation methods for DHIS2 expressions
720
769
  def tricc_operation_equal(self, ref_expressions):
@@ -765,7 +814,7 @@ class DHIS2Strategy(BaseOutPutStrategy):
765
814
 
766
815
  def tricc_operation_selected(self, ref_expressions):
767
816
  # For DHIS2, check if value is selected in multi-select
768
- return f"d2:hasValue({ref_expressions[0]}) && d2:contains({ref_expressions[0]}, {ref_expressions[1]})"
817
+ return f"d2:countIfValue({ref_expressions[0]}, {ref_expressions[1]})>0"
769
818
 
770
819
  def tricc_operation_count(self, ref_expressions):
771
820
  return f"d2:count({ref_expressions[0]})"
@@ -589,11 +589,14 @@ class XLSFormStrategy(BaseOutPutStrategy):
589
589
  exp += ")"
590
590
  return exp
591
591
 
592
+ def get_empty_label(self):
593
+ return "."
594
+
592
595
  def tricc_operation_if(self, ref_expressions):
593
596
  return f"if({ref_expressions[0]},{ref_expressions[1]},{ref_expressions[2]})"
594
597
 
595
598
  def tricc_operation_contains(self, ref_expressions):
596
- return f"contains('{self.clean_coalesce(ref_expressions[0])}', '{self.clean_coalesce(ref_expressions[1])}')"
599
+ return f"contains({self.clean_coalesce(ref_expressions[0])}, {self.clean_coalesce(ref_expressions[1])})"
597
600
 
598
601
  def tricc_operation_exists(self, ref_expressions):
599
602
  parts = []
@@ -33,6 +33,9 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
33
33
 
34
34
  self.inject_version()
35
35
 
36
+ def get_empty_label(self):
37
+ return "NO_LABEL"
38
+
36
39
  def get_cht_input(self, start_pages, **kwargs):
37
40
  empty = langs.get_trads("", force_dict=True)
38
41
  df_input = pd.DataFrame(columns=SURVEY_MAP.keys())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tricc-oo
3
- Version: 1.6.4
3
+ Version: 1.6.5
4
4
  Summary: Python library that converts CDSS L2 in L3
5
5
  Project-URL: Homepage, https://github.com/SwissTPH/tricc
6
6
  Project-URL: Issues, https://github.com/SwissTPH/tricc/issues
@@ -16,7 +16,7 @@ tricc_oo/converters/cql/cqlListener.py,sha256=fA7-8DcS2Q69ckwjdg57-OfFHBxjTZFdoS
16
16
  tricc_oo/converters/cql/cqlParser.py,sha256=x3KdrwX9nwENSEJ5Ex7_l5NMnu3kWBO0uLdYu4moTq0,414745
17
17
  tricc_oo/converters/cql/cqlVisitor.py,sha256=iHuup2S7OGSVWLEcI4H3oecRqgXztC1sKnew_1P2iGY,33880
18
18
  tricc_oo/models/__init__.py,sha256=CgS52LLqdDIaXHvZy08hhu_VaYw80OEdfL_llM9ICBA,108
19
- tricc_oo/models/base.py,sha256=AaeB69vWg3ulBttoezEniUiU8HWh_pvrw7tCHpL27g4,25926
19
+ tricc_oo/models/base.py,sha256=gqyUkeZlU2NfiR4tTMBtzUYFxKIeY-jtt1HECRomLUw,25917
20
20
  tricc_oo/models/calculate.py,sha256=uNP0IDUqPQcJq9Co05H8eX5wbR_DikSxuOHxfVE5Dxg,8018
21
21
  tricc_oo/models/lang.py,sha256=ZMRwdoPWe01wEDhOM0uRk-6rt3BkoAAZM8mZ61--s3A,2265
22
22
  tricc_oo/models/ocl.py,sha256=MybSeB6fgCOUVJ4aektff0vrrTZsyfwZ2Gt_pPBu_FY,8728
@@ -26,27 +26,27 @@ tricc_oo/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
26
26
  tricc_oo/parsers/xml.py,sha256=uzkb1y18MHfqVFmZqVh0sKT4cx6u0-NcAT_lV_gHBt8,4208
27
27
  tricc_oo/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  tricc_oo/serializers/planuml.py,sha256=t57587-6L3aDncpHh58lS77Zft8yxDE9DPtXx2BeUSU,132
29
- tricc_oo/serializers/xls_form.py,sha256=CTv2-UtpoCsgrLCdY1SEmpP6cZfnniKSEyTwuyct6Gg,21567
29
+ tricc_oo/serializers/xls_form.py,sha256=r4AtsV4JzFhf05KJui3ivmjzHodPqM8QR4L6m9cZsVY,21583
30
30
  tricc_oo/strategies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
31
  tricc_oo/strategies/input/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  tricc_oo/strategies/input/base_input_strategy.py,sha256=BEODXS74na1QRRcJVQ4cxiD8F7uRqaLyhE3QzKpGVvk,3891
33
33
  tricc_oo/strategies/input/drawio.py,sha256=uXAUPhXOeg0Uk_BNqlCqFBW4cWNox4VfH559bj1fhC0,12767
34
34
  tricc_oo/strategies/output/base_output_strategy.py,sha256=M9UFR67-_CFoW681bPAeBS1OUGuFtmUbM_rltACI0hk,8798
35
- tricc_oo/strategies/output/dhis2_form.py,sha256=m23EeZB7uXkNCFJr9hNGevgsA1dQqBrtX5uoy_22QRI,36500
35
+ tricc_oo/strategies/output/dhis2_form.py,sha256=BmqFUaM2XFh-NtqxEbe6A6MBYPuBCEugR59pl9rhZw4,38298
36
36
  tricc_oo/strategies/output/fhir_form.py,sha256=hbL921pe1Doun4IQrJuZ_Sq2fCh98G3grYie5olC4uc,15740
37
37
  tricc_oo/strategies/output/html_form.py,sha256=qSleEZOMV_-Z04y-i-ucyd5rgAYWAyjPwMrw0IHtCRM,8604
38
38
  tricc_oo/strategies/output/openmrs_form.py,sha256=zAmDGMmZdIGNpil5MD-huiUvt_Dbhc2vt5qsGaCS2_k,29003
39
39
  tricc_oo/strategies/output/spice.py,sha256=QMeoismVC3PdbvwTK0PtUjWX9jl9780fbQIXn76fMXw,10761
40
- tricc_oo/strategies/output/xls_form.py,sha256=_0xghjaHU50U1fBKekN4BP9oPzRs17_WRJO8VKtokag,29366
40
+ tricc_oo/strategies/output/xls_form.py,sha256=H4vxE7glOdrj83yZo2-eSojLdL8waDcbCne_nxy3GVQ,29413
41
41
  tricc_oo/strategies/output/xlsform_cdss.py,sha256=X00Lt5MzV8TX14dR4dFI1MqllI5S1e13bKbeysWM9uA,17435
42
- tricc_oo/strategies/output/xlsform_cht.py,sha256=RY_mre9j6w2vVnRFSGn5R3CuTWFjIbQyl1uWwz9Ay5E,22965
42
+ tricc_oo/strategies/output/xlsform_cht.py,sha256=Kvs7kFk5LPaGP_vRJuOU-SgZRKO7aS7u52MWoc4mGdU,23023
43
43
  tricc_oo/strategies/output/xlsform_cht_hf.py,sha256=xm6SKirV3nMZvM2w54_zJcXAeAgAkq-EEqGEjnOWv6c,988
44
44
  tricc_oo/visitors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
45
  tricc_oo/visitors/tricc.py,sha256=V4ai-rPjAbLSGdcKRBQiXohe6IqhZNCVyVjJLxYiavQ,107896
46
46
  tricc_oo/visitors/utils.py,sha256=j83aAq5s5atXi3OC0jc_uJd54a8XrHHmizeeEbWZQJg,421
47
47
  tricc_oo/visitors/xform_pd.py,sha256=ryAnI3V9x3eTmJ2LNsUZfvl0_yfCqo6oBgeSu-WPqaE,9613
48
- tricc_oo-1.6.4.dist-info/licenses/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
49
- tricc_oo-1.6.4.dist-info/METADATA,sha256=UeHJ7oRz6JMRUiXb2Dtp8s3bzfCLxIDeld4SMKwfqKo,8599
50
- tricc_oo-1.6.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
51
- tricc_oo-1.6.4.dist-info/top_level.txt,sha256=NvbfMNAiy9m4b1unBsqpeOQWh4IgA1Xa33BtKA4abxk,15
52
- tricc_oo-1.6.4.dist-info/RECORD,,
48
+ tricc_oo-1.6.5.dist-info/licenses/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
49
+ tricc_oo-1.6.5.dist-info/METADATA,sha256=pz-naLTMnGoP8IQVz_WZpHHZxn0pl8gChUGTp39kIL8,8599
50
+ tricc_oo-1.6.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
51
+ tricc_oo-1.6.5.dist-info/top_level.txt,sha256=NvbfMNAiy9m4b1unBsqpeOQWh4IgA1Xa33BtKA4abxk,15
52
+ tricc_oo-1.6.5.dist-info/RECORD,,