tricc-oo 1.5.22__py3-none-any.whl → 1.5.24__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 (45) hide show
  1. tests/build.py +17 -23
  2. tests/test_cql.py +37 -108
  3. tests/to_ocl.py +15 -17
  4. tricc_oo/__init__.py +0 -6
  5. tricc_oo/converters/codesystem_to_ocl.py +51 -40
  6. tricc_oo/converters/cql/cqlLexer.py +1 -0
  7. tricc_oo/converters/cql/cqlListener.py +1 -0
  8. tricc_oo/converters/cql/cqlParser.py +1 -0
  9. tricc_oo/converters/cql/cqlVisitor.py +1 -0
  10. tricc_oo/converters/cql_to_operation.py +125 -123
  11. tricc_oo/converters/datadictionnary.py +45 -54
  12. tricc_oo/converters/drawio_type_map.py +143 -61
  13. tricc_oo/converters/tricc_to_xls_form.py +14 -24
  14. tricc_oo/converters/utils.py +3 -3
  15. tricc_oo/converters/xml_to_tricc.py +286 -231
  16. tricc_oo/models/__init__.py +2 -1
  17. tricc_oo/models/base.py +300 -308
  18. tricc_oo/models/calculate.py +63 -49
  19. tricc_oo/models/lang.py +26 -27
  20. tricc_oo/models/ocl.py +146 -161
  21. tricc_oo/models/ordered_set.py +15 -19
  22. tricc_oo/models/tricc.py +145 -89
  23. tricc_oo/parsers/xml.py +15 -30
  24. tricc_oo/serializers/planuml.py +4 -6
  25. tricc_oo/serializers/xls_form.py +81 -135
  26. tricc_oo/strategies/input/base_input_strategy.py +28 -32
  27. tricc_oo/strategies/input/drawio.py +59 -71
  28. tricc_oo/strategies/output/base_output_strategy.py +142 -67
  29. tricc_oo/strategies/output/fhir_form.py +377 -0
  30. tricc_oo/strategies/output/html_form.py +224 -0
  31. tricc_oo/strategies/output/openmrs_form.py +647 -0
  32. tricc_oo/strategies/output/spice.py +106 -127
  33. tricc_oo/strategies/output/xls_form.py +263 -222
  34. tricc_oo/strategies/output/xlsform_cdss.py +623 -142
  35. tricc_oo/strategies/output/xlsform_cht.py +108 -115
  36. tricc_oo/strategies/output/xlsform_cht_hf.py +13 -24
  37. tricc_oo/visitors/tricc.py +1297 -1016
  38. tricc_oo/visitors/utils.py +16 -16
  39. tricc_oo/visitors/xform_pd.py +91 -89
  40. {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.24.dist-info}/METADATA +127 -84
  41. tricc_oo-1.5.24.dist-info/RECORD +50 -0
  42. tricc_oo-1.5.24.dist-info/licenses/LICENSE +373 -0
  43. tricc_oo-1.5.22.dist-info/RECORD +0 -46
  44. {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.24.dist-info}/WHEEL +0 -0
  45. {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.24.dist-info}/top_level.txt +0 -0
@@ -6,17 +6,29 @@ Strategy to build the skyp logic following the XLSForm way
6
6
  import datetime
7
7
  import logging
8
8
  import os
9
-
9
+ import re
10
10
  import pandas as pd
11
11
 
12
- from tricc_oo.converters.tricc_to_xls_form import *
12
+ from tricc_oo.converters.utils import clean_name
13
+ from tricc_oo.models.base import (
14
+ TriccOperator,
15
+ TriccOperation, TriccStatic, TriccReference
16
+ )
17
+ from tricc_oo.models.ordered_set import OrderedSet
18
+ from tricc_oo.models.calculate import (
19
+ TriccNodeEnd,
20
+ TriccNodeDisplayCalculateBase,
13
21
 
14
- from tricc_oo.models import (
15
- TriccNodeActivity,
16
- TriccGroup,
17
- TriccOperation,
18
- TriccOperator
19
22
  )
23
+ from tricc_oo.models.tricc import (
24
+ TriccNodeCalculateBase,
25
+ TriccNodeBaseModel,
26
+ TriccNodeSelectOption,
27
+ TriccNodeInputModel,
28
+ TriccNodeDisplayModel
29
+ )
30
+ from tricc_oo.converters.tricc_to_xls_form import get_export_name
31
+
20
32
  from tricc_oo.models.lang import SingletonLangClass
21
33
 
22
34
  from tricc_oo.visitors.tricc import (
@@ -27,7 +39,9 @@ from tricc_oo.visitors.tricc import (
27
39
  get_node_expressions,
28
40
  TRICC_TRUE_VALUE,
29
41
  TRICC_FALSE_VALUE,
30
- set_last_version_false
42
+ set_last_version_false,
43
+ generate_calculate,
44
+ generate_base,
31
45
  )
32
46
  from tricc_oo.serializers.xls_form import (
33
47
  CHOICE_MAP,
@@ -35,14 +49,13 @@ from tricc_oo.serializers.xls_form import (
35
49
  end_group,
36
50
  generate_xls_form_export,
37
51
  start_group,
38
- BOOLEAN_MAP
52
+ BOOLEAN_MAP,
39
53
  )
40
54
  from tricc_oo.strategies.output.base_output_strategy import BaseOutPutStrategy
41
55
 
42
56
  logger = logging.getLogger("default")
43
57
 
44
58
 
45
-
46
59
  """
47
60
  The XLSForm strategy is a strategy that will generate the XLSForm logic
48
61
  The XLSForm logic is a logic that is based on the XLSForm format
@@ -61,7 +74,7 @@ logger = logging.getLogger("default")
61
74
  check_stashed_loop
62
75
  generate_xls_form_export
63
76
  generate_xls_form_export
64
-
77
+
65
78
  """
66
79
  langs = SingletonLangClass()
67
80
 
@@ -73,31 +86,31 @@ OPERATOR_COALESCE_FALLBACK = {
73
86
  TriccOperator.MORE: -2147483648,
74
87
  TriccOperator.MORE_OR_EQUAL: -2147483648,
75
88
  TriccOperator.LESS: 2147483647,
76
- TriccOperator.LESS_OR_EQUAL: 2147483647
89
+ TriccOperator.LESS_OR_EQUAL: 2147483647,
77
90
  }
78
91
 
92
+
79
93
  class XLSFormStrategy(BaseOutPutStrategy):
80
- pd.set_option('display.max_colwidth', None)
94
+ pd.set_option("display.max_colwidth", None)
81
95
  df_survey = pd.DataFrame(columns=SURVEY_MAP.keys())
82
96
  df_calculate = pd.DataFrame(columns=SURVEY_MAP.keys())
83
97
  df_choice = pd.DataFrame(columns=CHOICE_MAP.keys())
84
98
  calculates = {}
85
99
  # add save nodes and merge nodes
86
100
 
87
-
88
- def clean_coalesce(self, expression):
101
+ def clean_coalesce(self, expression):
89
102
  if re.match(r"^coalesce\(\${[^}]+},''\)$", str(expression)):
90
103
  return str(expression[9:-4])
91
104
  return str(expression)
92
105
 
93
106
  def generate_base(self, node, **kwargs):
94
- return self.generate_xls_form_condition(node, **kwargs)
107
+ return generate_base(node, **kwargs)
95
108
 
96
109
  def generate_relevance(self, node, **kwargs):
97
110
  return self.generate_xls_form_relevance(node, **kwargs)
98
111
 
99
112
  def generate_calculate(self, node, **kwargs):
100
- return self.generate_xls_form_calculate(node, **kwargs)
113
+ return generate_calculate(node, **kwargs)
101
114
 
102
115
  def __init__(self, project, output_path):
103
116
  super().__init__(project, output_path)
@@ -112,12 +125,36 @@ class XLSFormStrategy(BaseOutPutStrategy):
112
125
  "df_survey": self.df_survey,
113
126
  "df_choice": self.df_choice,
114
127
  "df_calculate": self.df_calculate,
115
- "calculates": self.calculates
128
+ "calculates": self.calculates,
116
129
  }
117
130
 
118
131
  def generate_export(self, node, **kwargs):
119
132
  return generate_xls_form_export(self, node, **kwargs)
120
133
 
134
+ def inject_version(self):
135
+ # Add hidden version field using ODK's jr:version()
136
+ empty = langs.get_trads("", force_dict=True)
137
+ self.df_survey.loc[len(self.df_survey)] = [
138
+ "hidden",
139
+ "version",
140
+ *list(empty.values()), # label
141
+ *list(empty.values()), # hint
142
+ *list(empty.values()), # help
143
+ "", # default
144
+ "hidden", # appearance
145
+ "", # constraint
146
+ *list(empty.values()), # constraint_message
147
+ "", # relevance
148
+ "", # disabled
149
+ "", # required
150
+ *list(empty.values()), # required_message
151
+ "", # read only
152
+ "jr:version()", # calculation
153
+ "", # trigger
154
+ "", # repeat_count
155
+ "", # image
156
+ "", # choice_filter
157
+ ]
121
158
 
122
159
  def export(self, start_pages, version):
123
160
  if start_pages["main"].root.form_id is not None:
@@ -128,7 +165,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
128
165
  title = start_pages["main"].root.label
129
166
  file_name = form_id + ".xlsx"
130
167
  # make a 'settings' tab
131
- now = datetime.datetime.now()
168
+ datetime.datetime.now()
132
169
  indx = [[1]]
133
170
 
134
171
  settings = {
@@ -146,10 +183,10 @@ class XLSFormStrategy(BaseOutPutStrategy):
146
183
  if not os.path.exists(self.output_path):
147
184
  os.makedirs(self.output_path)
148
185
 
186
+ self.inject_version()
187
+
149
188
  # create a Pandas Excel writer using XlsxWriter as the engine
150
189
  writer = pd.ExcelWriter(newpath, engine="xlsxwriter")
151
- if len(self.df_survey[self.df_survey['name'] == 'version'] ):
152
- self.df_survey.loc[ self.df_survey['name'] == 'version', 'label'] = f"v{version}"
153
190
  self.df_survey.to_excel(writer, sheet_name="survey", index=False)
154
191
  self.df_choice.to_excel(writer, sheet_name="choices", index=False)
155
192
  df_settings.to_excel(writer, sheet_name="settings", index=False)
@@ -175,9 +212,16 @@ class XLSFormStrategy(BaseOutPutStrategy):
175
212
  cur_group = activity
176
213
  groups[activity.id] = 0
177
214
  path_len = 0
178
- process = ['main']
215
+ process = ["main"]
179
216
  # keep the vesrions on the group id, max version
180
- start_group(self, cur_group=cur_group, groups=groups, processed_nodes=processed_nodes, process=process, **self.get_kwargs())
217
+ start_group(
218
+ self,
219
+ cur_group=cur_group,
220
+ groups=groups,
221
+ processed_nodes=processed_nodes,
222
+ process=process,
223
+ **self.get_kwargs(),
224
+ )
181
225
  walktrhough_tricc_node_processed_stached(
182
226
  activity.root,
183
227
  self.generate_export,
@@ -187,14 +231,14 @@ class XLSFormStrategy(BaseOutPutStrategy):
187
231
  cur_group=activity.root.group,
188
232
  process=process,
189
233
  recursive=False,
190
- **self.get_kwargs()
234
+ **self.get_kwargs(),
191
235
  )
192
236
  end_group(self, cur_group=activity, groups=groups, **self.get_kwargs())
193
237
  # we save the survey data frame
194
238
  df_survey_final = pd.DataFrame(columns=SURVEY_MAP.keys())
195
239
  if len(self.df_survey) > (2 + skip_header):
196
240
  df_survey_final = self.df_survey
197
- ## MANAGE STASHED NODES
241
+ # MANAGE STASHED NODES
198
242
  prev_stashed_nodes = stashed_nodes.copy()
199
243
  loop_count = 0
200
244
  len_prev_processed_nodes = 0
@@ -214,9 +258,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
214
258
  # while len(stashed_nodes)>0 and isinstance(s_node,TriccGroup):
215
259
  # s_node = stashed_nodes.pop()
216
260
  if s_node.group is None:
217
- logger.critical(
218
- "ERROR group is none for node {}".format(s_node.get_name())
219
- )
261
+ logger.critical("ERROR group is none for node {}".format(s_node.get_name()))
220
262
  start_group(
221
263
  self,
222
264
  cur_group=s_node.group,
@@ -224,7 +266,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
224
266
  processed_nodes=processed_nodes,
225
267
  process=process,
226
268
  relevance=True,
227
- **self.get_kwargs()
269
+ **self.get_kwargs(),
228
270
  )
229
271
  # arrange empty group
230
272
  walktrhough_tricc_node_processed_stached(
@@ -236,8 +278,8 @@ class XLSFormStrategy(BaseOutPutStrategy):
236
278
  groups=groups,
237
279
  cur_group=s_node.group,
238
280
  recursive=False,
239
- process = process,
240
- **self.get_kwargs()
281
+ process=process,
282
+ **self.get_kwargs(),
241
283
  )
242
284
  # add end group if new node where added OR if the previous end group was removed
243
285
  end_group(self, cur_group=s_node.group, groups=groups, **self.get_kwargs())
@@ -254,13 +296,9 @@ class XLSFormStrategy(BaseOutPutStrategy):
254
296
  )
255
297
  )
256
298
  if len(df_survey_final):
257
- df_survey_final.drop(
258
- index=df_survey_final.index[-1], axis=0, inplace=True
259
- )
260
- self.df_survey = self.df_survey[(1 + skip_header) :]
261
- df_survey_final = pd.concat(
262
- [df_survey_final, self.df_survey], ignore_index=True
263
- )
299
+ df_survey_final.drop(index=df_survey_final.index[-1], axis=0, inplace=True)
300
+ self.df_survey = self.df_survey[(1 + skip_header):]
301
+ df_survey_final = pd.concat([df_survey_final, self.df_survey], ignore_index=True)
264
302
 
265
303
  else:
266
304
  logger.debug(
@@ -271,9 +309,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
271
309
  s_node.group.instance,
272
310
  )
273
311
  )
274
- df_survey_final = pd.concat(
275
- [df_survey_final, self.df_survey], ignore_index=True
276
- )
312
+ df_survey_final = pd.concat([df_survey_final, self.df_survey], ignore_index=True)
277
313
  cur_group = s_node.group
278
314
 
279
315
  # add the calulate
@@ -282,20 +318,15 @@ class XLSFormStrategy(BaseOutPutStrategy):
282
318
  self.df_survey.reset_index(drop=True, inplace=True)
283
319
  self.df_calculate.reset_index(drop=True, inplace=True)
284
320
  self.df_calculate = self.df_calculate.drop(df_empty_calc.index)
285
- self.df_survey = pd.concat(
286
- [df_survey_final, self.df_calculate], ignore_index=True
287
- )
288
- df_duplicate = self.df_calculate[
289
- self.df_calculate.duplicated(subset=["calculation"], keep="first")
290
- ]
321
+ self.df_survey = pd.concat([df_survey_final, self.df_calculate], ignore_index=True)
322
+ df_duplicate = self.df_calculate[self.df_calculate.duplicated(subset=["calculation"], keep="first")]
291
323
  # self.df_survey=self.df_survey.drop_duplicates(subset=['name'])
292
324
  for index, drop_calc in df_duplicate.iterrows():
293
325
  # remove the duplicate
294
326
  replace_name = False
295
327
  # find the actual calcualte
296
328
  similar_calc = self.df_survey[
297
- (drop_calc["calculation"] == self.df_survey["calculation"])
298
- & (self.df_survey["type"] == "calculate")
329
+ (drop_calc["calculation"] == self.df_survey["calculation"]) & (self.df_survey["type"] == "calculate")
299
330
  ]
300
331
  same_calc = self.df_survey[self.df_survey["name"] == drop_calc["name"]]
301
332
  if len(same_calc) > 1:
@@ -324,165 +355,193 @@ class XLSFormStrategy(BaseOutPutStrategy):
324
355
  )
325
356
  else:
326
357
  logger.critical(
327
- "duplicate reference not found for calculation: {}".format(
328
- drop_calc["calculation"]
329
- )
358
+ "duplicate reference not found for calculation: {}".format(drop_calc["calculation"])
330
359
  )
331
360
  for index, empty_calc in df_empty_calc.iterrows():
332
361
  self.df_survey.replace("${" + empty_calc["name"] + "}", "1", regex=True)
333
362
 
334
363
  # TODO try to reinject calc to reduce complexity
335
- for i, c in self.df_calculate[
336
- ~self.df_calculate["name"].isin(self.df_survey["name"])
337
- ].iterrows():
364
+ for i, c in self.df_calculate[~self.df_calculate["name"].isin(self.df_survey["name"])].iterrows():
338
365
  real_calc = re.find(r"^number\((.+)\)$", c["calculation"])
339
366
  if real_calc is not None and real_calc != "":
340
- self.df_survey[~self.df_survey["name"] == c["name"]].replace(
341
- real_calc, "${" + c["name"] + "}"
342
- )
343
-
344
- df_duplicate = self.df_survey[
345
- self.df_survey.duplicated(subset=["name"], keep="first")
346
- ]
347
- for index, duplicate in df_duplicate.iterrows():
367
+ self.df_survey[~self.df_survey["name"] == c["name"]].replace(real_calc, "${" + c["name"] + "}")
368
+
369
+ df_duplicate = self.df_survey[self.df_survey.duplicated(subset=["name"], keep="first")]
370
+ for index, duplicate in df_duplicate.iterrows():
348
371
  logger.critical(f"duplicate survey name: {duplicate['name']}")
349
372
  self.df_survey.reset_index(drop=True, inplace=True)
350
373
  return processed_nodes
351
374
 
352
375
  def get_tricc_operation_expression(self, operation):
353
376
  ref_expressions = []
354
- if not hasattr(operation, 'reference'):
355
- return self.get_tricc_operation_operand(operation)
356
-
357
- operator = getattr(operation, 'operator', '')
358
- coalesce_fallback = OPERATOR_COALESCE_FALLBACK[operator] if operator in OPERATOR_COALESCE_FALLBACK else "''"
377
+ if not hasattr(operation, "reference"):
378
+ return self.get_tricc_operation_operand(operation)
379
+
380
+ operator = getattr(operation, "operator", "")
381
+ coalesce_fallback = OPERATOR_COALESCE_FALLBACK[operator] if operator in OPERATOR_COALESCE_FALLBACK else "''"
359
382
  for r in operation.reference:
360
383
  if isinstance(r, list):
361
384
  r_expr = [
362
- self.get_tricc_operation_expression(sr) if isinstance(sr, TriccOperation)
363
- else self.get_tricc_operation_operand(sr,coalesce_fallback)
385
+ (
386
+ self.get_tricc_operation_expression(sr)
387
+ if isinstance(sr, TriccOperation)
388
+ else self.get_tricc_operation_operand(sr, coalesce_fallback)
389
+ )
364
390
  for sr in r
365
391
  ]
366
392
  elif isinstance(r, TriccOperation):
367
393
  r_expr = self.get_tricc_operation_expression(r)
368
394
  else:
369
- r_expr = self.get_tricc_operation_operand(r,coalesce_fallback)
395
+ r_expr = self.get_tricc_operation_operand(r, coalesce_fallback)
370
396
  if isinstance(r_expr, TriccReference):
371
- r_expr = self.get_tricc_operation_operand(r_expr,coalesce_fallback)
397
+ r_expr = self.get_tricc_operation_operand(r_expr, coalesce_fallback)
372
398
  ref_expressions.append(r_expr)
373
-
399
+
374
400
  # build lower level
375
- if hasattr(self,f"tricc_operation_{operation.operator}"):
376
- callable = getattr(self,f"tricc_operation_{operation.operator}")
377
- return callable(ref_expressions)
401
+ if hasattr(self, f"tricc_operation_{operation.operator}"):
402
+ callable = getattr(self, f"tricc_operation_{operation.operator}")
403
+ return callable(ref_expressions)
378
404
  else:
379
- raise NotImplementedError(f"This type of opreation '{operation.operator}' is not supported in this strategy")
380
-
405
+ raise NotImplementedError(
406
+ f"This type of opreation '{operation.operator}' is not supported in this strategy"
407
+ )
408
+
409
+ def tricc_operation_count(self, ref_expressions):
410
+ return f"count-selected({self.clean_coalesce(ref_expressions[0])})"
411
+
381
412
  def tricc_operation_multiplied(self, ref_expressions):
382
- return '*'.join(ref_expressions)
413
+ return "*".join(ref_expressions)
414
+
383
415
  def tricc_operation_divided(self, ref_expressions):
384
416
  return f"{ref_expressions[0]} div {ref_expressions[1]}"
417
+
385
418
  def tricc_operation_modulo(self, ref_expressions):
386
419
  return f"{ref_expressions[0]} mod {ref_expressions[1]}"
420
+
387
421
  def tricc_operation_coalesce(self, ref_expressions):
388
422
  return f"coalesce({','.join(map(self.clean_coalesce, ref_expressions))})"
423
+
389
424
  def tricc_operation_module(self, ref_expressions):
390
425
  return f"{ref_expressions[0]} mod {ref_expressions[1]}"
426
+
391
427
  def tricc_operation_minus(self, ref_expressions):
392
- if len(ref_expressions)>1:
393
- return ' - '.join(map(str,ref_expressions))
394
- elif len(ref_expressions)==1:
395
- return f'-{ref_expressions[0]}'
428
+ if len(ref_expressions) > 1:
429
+ return " - ".join(map(str, ref_expressions))
430
+ elif len(ref_expressions) == 1:
431
+ return f"-{ref_expressions[0]}"
432
+
396
433
  def tricc_operation_plus(self, ref_expressions):
397
- return ' + '.join(ref_expressions)
434
+ return " + ".join(ref_expressions)
435
+
398
436
  def tricc_operation_not(self, ref_expressions):
399
437
  return f"not({ref_expressions[0]})"
438
+
400
439
  def tricc_operation_and(self, ref_expressions):
401
440
  if len(ref_expressions) == 1:
402
441
  return ref_expressions[0]
403
- if len(ref_expressions)>1:
404
- ref_expressions = [f"({r})" if isinstance(r, str) and any(op in r for op in [' or ',' + ',' - '])else r for r in ref_expressions]
405
- return ' and '.join(map(str, ref_expressions))
442
+ if len(ref_expressions) > 1:
443
+ ref_expressions = [
444
+ (f"({r})" if isinstance(r, str) and any(op in r for op in [" or ", " + ", " - "]) else r)
445
+ for r in ref_expressions
446
+ ]
447
+ return " and ".join(map(str, ref_expressions))
406
448
  else:
407
- return '1'
449
+ return "1"
408
450
 
409
451
  def tricc_operation_or(self, ref_expressions):
410
452
  if len(ref_expressions) == 1:
411
453
  return ref_expressions[0]
412
- if len(ref_expressions)>1:
413
- ref_expressions = [f"({r})" if isinstance(r, str) and any(op in r for op in [' and ',' + ',' - ']) else r for r in ref_expressions]
414
- return ' or '.join(map(str, ref_expressions))
454
+ if len(ref_expressions) > 1:
455
+ ref_expressions = [
456
+ (f"({r})" if isinstance(r, str) and any(op in r for op in [" and ", " + ", " - "]) else r)
457
+ for r in ref_expressions
458
+ ]
459
+ return " or ".join(map(str, ref_expressions))
415
460
  else:
416
- return '1'
417
-
418
-
461
+ return "1"
419
462
 
420
463
  def tricc_operation_native(self, ref_expressions):
421
- if len(ref_expressions)>0:
422
- if ref_expressions[0] =='GetChoiceName':
423
- return f"jr:choice-name({self.clean_coalesce(ref_expressions[1])}, '{self.clean_coalesce(ref_expressions[2])}')"
424
- elif ref_expressions[0] =='GetFacilityParam':
425
- return '0'
426
- #return f"jr:choice-name({','.join(ref_expressions[1:])})"
427
- else:
464
+ if len(ref_expressions) > 0:
465
+ if ref_expressions[0] == "GetChoiceName":
466
+ return f"""jr:choice-name({
467
+ self.clean_coalesce(ref_expressions[1])
468
+ }, '{
469
+ self.clean_coalesce(ref_expressions[2])
470
+ }')"""
471
+ elif ref_expressions[0] == "GetFacilityParam":
472
+ return "0"
473
+ # return f"jr:choice-name({','.join(ref_expressions[1:])})"
474
+ else:
428
475
  return f"{ref_expressions[0]}({','.join(ref_expressions[1:])})"
429
-
476
+
430
477
  def tricc_operation_istrue(self, ref_expressions):
431
478
  if str(BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]).isnumeric():
432
479
  return f"{ref_expressions[0]}>={BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]}"
433
480
  else:
434
481
  return f"{ref_expressions[0]}={BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]}"
482
+
435
483
  def tricc_operation_isfalse(self, ref_expressions):
436
484
  if str(BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]).isnumeric():
437
485
  return f"{ref_expressions[0]}={BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]}"
438
486
  else:
439
487
  return f"{ref_expressions[0]}={BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]}"
488
+
440
489
  def tricc_operation_parenthesis(self, ref_expressions):
441
490
  return f"({ref_expressions[0]})"
491
+
442
492
  def tricc_operation_selected(self, ref_expressions):
443
493
  parts = []
444
494
  for s in ref_expressions[1:]:
445
495
  # for option with numeric value
446
- cleaned_s = s if isinstance(s, str) else '\''+str(s)+'\''
496
+ cleaned_s = s if isinstance(s, str) else "'" + str(s) + "'"
447
497
  parts.append(f"selected({self.clean_coalesce(ref_expressions[0])}, {cleaned_s})")
448
498
  if len(parts) == 1:
449
499
  return parts[0]
450
500
  else:
451
501
  return self.tricc_operation_or(parts)
502
+
452
503
  def tricc_operation_more_or_equal(self, ref_expressions):
453
504
  return f"{ref_expressions[0]}>={ref_expressions[1]}"
505
+
454
506
  def tricc_operation_less_or_equal(self, ref_expressions):
455
507
  return f"{ref_expressions[0]}<={ref_expressions[1]}"
508
+
456
509
  def tricc_operation_more(self, ref_expressions):
457
510
  return f"{ref_expressions[0]}>{ref_expressions[1]}"
511
+
458
512
  def tricc_operation_less(self, ref_expressions):
459
513
  return f"{ref_expressions[0]}<{ref_expressions[1]}"
514
+
460
515
  def tricc_operation_between(self, ref_expressions):
461
- return f"{ref_expressions[0]}>={ref_expressions[1]} and {ref_expressions[0]} < {ref_expressions[2]}"
516
+ return f"{ref_expressions[0]}>={ref_expressions[1]} and {ref_expressions[0]} < {ref_expressions[2]}"
517
+
462
518
  def tricc_operation_equal(self, ref_expressions):
463
519
  return f"{ref_expressions[0]}={ref_expressions[1]}"
520
+
464
521
  def tricc_operation_not_equal(self, ref_expressions):
465
522
  return f"{ref_expressions[0]}!={ref_expressions[1]}"
523
+
466
524
  def tricc_operation_isnull(self, ref_expressions):
467
525
  return f"{ref_expressions[0]}=''"
526
+
468
527
  def tricc_operation_isnotnull(self, ref_expressions):
469
528
  return f"{ref_expressions[0]}!=''"
470
-
529
+
471
530
  def tricc_operation_isnottrue(self, ref_expressions):
472
531
  if str(BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]).isnumeric():
473
532
  return f"{ref_expressions[0]}<{BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]}"
474
533
  else:
475
534
  return f"{ref_expressions[0]}!={BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]}"
535
+
476
536
  def tricc_operation_isnotfalse(self, ref_expressions):
477
537
  if str(BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]).isnumeric():
478
538
  return f"{ref_expressions[0]}>{BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]}"
479
539
  else:
480
540
  return f"{ref_expressions[0]}!={BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]}"
541
+
481
542
  def tricc_operation_notexist(self, ref_expressions):
482
543
  return f"{ref_expressions[0]}=''"
483
544
 
484
-
485
-
486
545
  def tricc_operation_case(self, ref_expressions):
487
546
  ifs = 0
488
547
  parts = []
@@ -496,192 +555,174 @@ class XLSFormStrategy(BaseOutPutStrategy):
496
555
  else:
497
556
  else_found = True
498
557
  parts.append(ref_expressions[i])
499
- #join the if
500
- exp = ','.join(map(str,parts))
558
+ # join the if
559
+ exp = ",".join(map(str, parts))
501
560
  # in case there is no default put ''
502
561
  if not else_found:
503
562
  exp += ",''"
504
- #add the closing )
563
+ # add the closing )
505
564
  for i in range(ifs):
506
565
  exp += ")"
507
566
  return exp
508
-
567
+
509
568
  def tricc_operation_ifs(self, ref_expressions):
510
569
  ifs = 0
511
570
  parts = []
512
571
  else_found = False
513
572
  for i in range(int(len(ref_expressions[1:]))):
514
- if isinstance(ref_expressions[i+1], list):
573
+ if isinstance(ref_expressions[i + 1], list):
515
574
  parts.append(f"if({ref_expressions[0]}={ref_expressions[i+1][0]},{ref_expressions[i+1][1]}")
516
575
  ifs += 1
517
576
  else:
518
577
  else_found = True
519
- parts.append(ref_expressions[i+1])
520
- #join the if
521
- exp = ','.join(parts)
578
+ parts.append(ref_expressions[i + 1])
579
+ # join the if
580
+ exp = ",".join(parts)
522
581
  # in case there is no default put ''
523
582
  if not else_found:
524
583
  exp += ",''"
525
- #add the closing )
584
+ # add the closing )
526
585
  for i in range(ifs):
527
586
  exp += ")"
528
587
  return exp
529
-
588
+
530
589
  def tricc_operation_if(self, ref_expressions):
531
590
  return f"if({ref_expressions[0]},{ref_expressions[1]},{ref_expressions[2]})"
532
-
591
+
533
592
  def tricc_operation_contains(self, ref_expressions):
534
593
  return f"contains('{self.clean_coalesce(ref_expressions[0])}', '{self.clean_coalesce(ref_expressions[1])}')"
535
-
594
+
536
595
  def tricc_operation_exists(self, ref_expressions):
537
596
  parts = []
538
597
  for ref in ref_expressions:
539
598
  parts.append(self.tricc_operation_not_equal([self.tricc_operation_coalesce([ref, "''"]), "''"]))
540
599
  return self.tricc_operation_and(parts)
541
-
600
+
542
601
  def tricc_operation_cast_number(self, ref_expressions):
543
- if isinstance(ref_expressions[0], (int, float,)):
602
+ if isinstance(
603
+ ref_expressions[0],
604
+ (
605
+ int,
606
+ float,
607
+ ),
608
+ ):
544
609
  return f"{ref_expressions[0]}"
545
- elif not ref_expressions or ref_expressions[0] == '':
610
+ elif not ref_expressions or ref_expressions[0] == "":
546
611
  logger.warning("empty cast number")
547
- return '0'
548
- elif ref_expressions[0] == 'true' or ref_expressions[0] is True or ref_expressions[0] == BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]:
612
+ return "0"
613
+ elif (
614
+ ref_expressions[0] == "true"
615
+ or ref_expressions[0] is True
616
+ or ref_expressions[0] == BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]
617
+ ):
549
618
  return 1
550
- elif ref_expressions[0] == 'false' or ref_expressions[0] is False or ref_expressions[0] == BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]:
619
+ elif (
620
+ ref_expressions[0] == "false"
621
+ or ref_expressions[0] is False
622
+ or ref_expressions[0] == BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]
623
+ ):
551
624
  return 0
552
625
  else:
553
626
  return f"number({ref_expressions[0]})"
554
-
627
+
555
628
  def tricc_operation_cast_integer(self, ref_expressions):
556
- if isinstance(ref_expressions[0], (int, float,)):
629
+ if isinstance(
630
+ ref_expressions[0],
631
+ (
632
+ int,
633
+ float,
634
+ ),
635
+ ):
557
636
  return f"{ref_expressions[0]}"
558
- elif not ref_expressions or ref_expressions[0] == '':
637
+ elif not ref_expressions or ref_expressions[0] == "":
559
638
  logger.warning("empty cast number")
560
- return '0'
561
- elif ref_expressions[0] == 'true' or ref_expressions[0] is True or ref_expressions[0] == BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]:
639
+ return "0"
640
+ elif (
641
+ ref_expressions[0] == "true"
642
+ or ref_expressions[0] is True
643
+ or ref_expressions[0] == BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]
644
+ ):
562
645
  return 1
563
- elif ref_expressions[0] == 'false' or ref_expressions[0] is False or ref_expressions[0] == BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]:
646
+ elif (
647
+ ref_expressions[0] == "false"
648
+ or ref_expressions[0] is False
649
+ or ref_expressions[0] == BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]
650
+ ):
564
651
  return 0
565
652
  else:
566
- return f"int({ref_expressions[0]})"
653
+ return f"int({ref_expressions[0]})"
654
+
567
655
  def tricc_operation_zscore(self, ref_expressions):
568
656
  y, ll, m, s = self.get_zscore_params(ref_expressions)
569
657
  # return ((Math.pow((y / m), l) - 1) / (s * l));
570
658
  return f"(pow({y} div ({m}), {ll}) -1) div (({s}) div ({ll}))"
571
-
659
+
572
660
  def tricc_operation_datetime_to_decimal(self, ref_expressions):
573
661
  return f"decimal-date-time({ref_expressions[0]})"
574
-
662
+
575
663
  def tricc_operation_round(self, ref_expressions):
576
664
  return f"round({ref_expressions[0]})"
577
-
578
-
579
-
665
+
580
666
  def tricc_operation_izscore(self, ref_expressions):
581
667
  z, ll, m, s = self.get_zscore_params(ref_expressions)
582
668
  # return (m * (z*s*l-1)^(1/l));
583
669
  return f"pow({m} * ({z} * {s} * {ll} -1), 1 div {ll})"
584
-
670
+
585
671
  def get_zscore_params(self, ref_expressions):
586
672
  table = ref_expressions[0]
587
673
  sex = clean_name(ref_expressions[1])
588
674
  x = clean_name(ref_expressions[2])
589
675
  yz = clean_name(ref_expressions[3])
590
- ll = (
591
- f"number(instance({table})/root/item[sex={sex} and x_max>"
592
- + x
593
- + " and x_min<="
594
- + x
595
- + "]/l)"
596
- )
597
- m = (
598
- f"number(instance({table})/root/item[sex={sex} and x_max>"
599
- + x
600
- + " and x_min<="
601
- + x
602
- + "]/m)"
603
- )
604
- s = (
605
- f"number(instance({table})/root/item[sex={sex} and x_max>"
606
- + x
607
- + " and x_min<="
608
- + x
609
- + "]/s)"
610
- )
611
- return yz, ll, m, s
612
-
613
-
614
-
676
+ ll = f"number(instance({table})/root/item[sex={sex} and x_max>" + x + " and x_min<=" + x + "]/l)"
677
+ m = f"number(instance({table})/root/item[sex={sex} and x_max>" + x + " and x_min<=" + x + "]/m)"
678
+ s = f"number(instance({table})/root/item[sex={sex} and x_max>" + x + " and x_min<=" + x + "]/s)"
679
+ return yz, ll, m, s
680
+
615
681
  # function update the calcualte in the XLSFORM format
616
682
  # @param left part
617
- # @param right part
683
+ # @param right part
618
684
  def generate_xls_form_calculate(self, node, processed_nodes, stashed_nodes, calculates, **kwargs):
619
- if is_ready_to_process(node, processed_nodes, strict=False) and process_reference(node, processed_nodes, calculates, replace_reference=False, codesystems= kwargs.get('codesystems', None)):
685
+ if is_ready_to_process(node, processed_nodes, strict=False) and process_reference(
686
+ node,
687
+ processed_nodes,
688
+ calculates,
689
+ replace_reference=False,
690
+ codesystems=kwargs.get("codesystems", None),
691
+ ):
620
692
  if node not in processed_nodes:
621
- if kwargs.get('warn', True):
693
+ if kwargs.get("warn", True):
622
694
  logger.debug("generation of calculate for node {}".format(node.get_name()))
623
- if hasattr(node, 'expression') and (node.expression is None) and issubclass(node.__class__,TriccNodeCalculateBase):
624
- node.expression = get_node_expressions(node, processed_nodes, process=kwargs.get('process', 'main '))
695
+ if (
696
+ hasattr(node, "expression")
697
+ and (node.expression is None)
698
+ and issubclass(node.__class__, TriccNodeCalculateBase)
699
+ ):
700
+ node.expression = get_node_expressions(
701
+ node, processed_nodes, process=kwargs.get("process", "main ")
702
+ )
625
703
  # continue walk
626
- if issubclass(node.__class__, (TriccNodeDisplayModel, TriccNodeDisplayCalculateBase, TriccNodeEnd)):
627
- last_version = set_last_version_false(node, processed_nodes)
628
- return True
629
- return False
630
-
631
- # function update the select node in the XLSFORM format
632
- # @param left part
633
- # @param right part
634
- def generate_xls_form_condition(self, node, processed_nodes, stashed_nodes, calculates, **kwargs):
635
- if is_ready_to_process(node, processed_nodes, strict=False) and process_reference(node, processed_nodes, calculates, replace_reference=False, codesystems= kwargs.get('codesystems', None)):
636
- if node not in processed_nodes:
637
- if issubclass(node.__class__, TriccRhombusMixIn) and isinstance(node.reference, str):
638
- logger.warning("node {} still using the reference string".format(node.get_name()))
639
- if issubclass(node.__class__, TriccNodeInputModel):
640
- # we don't overright if define in the diagram
641
- if node.constraint is None:
642
- if isinstance(node, TriccNodeSelectMultiple):
643
- node.constraint = or_join(
644
- [
645
- TriccOperation(TriccOperator.EQUAL, ['$this', TriccStatic('opt_none')]),
646
- TriccOperation(TriccOperator.NOT, [
647
- TriccOperation(TriccOperator.SELECTED,
648
- [
649
- '$this', TriccStatic('opt_none')
650
- ])
651
- ])
652
- ]
653
- )#'.=\'opt_none\' or not(selected(.,\'opt_none\'))'
654
- node.constraint_message = '**None** cannot be selected together with choice.'
655
- elif node.tricc_type in (TriccNodeType.integer, TriccNodeType.decimal):
656
- constraints = []
657
- constraints_min = ''
658
- constraints_max = ''
659
- if node.min is not None and node.min != '':
660
- constraints.append(TriccOperation(TriccOperator.MORE_OR_EQUAL, ['$this', node.min]))
661
- constraints_min= "The minimun value is {0}.".format(node.min)
662
- if node.max is not None and node.max != '':
663
- constraints.append(TriccOperation(TriccOperator.LESS_OR_EQUAL, ['$this', node.max]))
664
- constraints_max="The maximum value is {0}.".format(node.max)
665
- if len(constraints) > 1:
666
- node.constraint = TriccOperation(TriccOperator.AND, constraints)
667
- node.constraint_message = (constraints_min + " " + constraints_max).strip()
668
- elif len(constraints) == 1:
669
- node.constraint = constraints[0]
670
- node.constraint_message = (constraints_min + " " + constraints_max).strip()
671
- # continue walk
704
+ if issubclass(
705
+ node.__class__,
706
+ (
707
+ TriccNodeDisplayModel,
708
+ TriccNodeDisplayCalculateBase,
709
+ TriccNodeEnd,
710
+ ),
711
+ ):
712
+ set_last_version_false(node, processed_nodes)
672
713
  return True
673
714
  return False
674
715
 
675
- # function transform an object to XLSFORM value
676
- # @param r reference to be translated
677
- def get_tricc_operation_operand(self,r, coalesce_fallback="''"):
716
+ def get_tricc_operation_operand(self, r, coalesce_fallback="''"):
717
+ # function transform an object to XLSFORM value
718
+ # @param r reference to be translated
678
719
  if isinstance(r, TriccOperation):
679
- return self.get_tricc_operation_expression(r)
720
+ return self.get_tricc_operation_expression(r)
680
721
  elif isinstance(r, TriccReference):
681
722
  logger.warning(f"reference `{r.value}` still used in a calculate")
682
- return f"${{{get_export_name(r.value)}}}"
723
+ return f"${{{get_export_name(r.value)}}}"
683
724
  elif isinstance(r, TriccStatic):
684
- if isinstance(r.value, bool) :#or r.value in ('true', 'false')
725
+ if isinstance(r.value, bool): # or r.value in ('true', 'false')
685
726
  return BOOLEAN_MAP[str(TRICC_TRUE_VALUE)] if r.value else BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]
686
727
  if r.value == TRICC_TRUE_VALUE:
687
728
  return BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]
@@ -692,7 +733,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
692
733
  else:
693
734
  return str(r.value)
694
735
  elif isinstance(r, str):
695
- return f"{r}"
736
+ return f"{r}"
696
737
  elif isinstance(r, (int, float)):
697
738
  return str(r)
698
739
  elif isinstance(r, TriccNodeSelectOption):
@@ -706,4 +747,4 @@ class XLSFormStrategy(BaseOutPutStrategy):
706
747
  raise NotImplementedError(f"This type of node {r.__class__} is not supported within an operation")
707
748
 
708
749
  def tricc_operation_concatenate(self, ref_expressions):
709
- return f"concat({','.join(ref_expressions)})"
750
+ return f"concat({','.join(ref_expressions)})"