tricc-oo 1.4.17__tar.gz → 1.4.18__tar.gz

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 (51) hide show
  1. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/PKG-INFO +2 -1
  2. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/pyproject.toml +2 -1
  3. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/cql_to_operation.py +7 -0
  4. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/datadictionnary.py +4 -0
  5. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/xml_to_tricc.py +3 -1
  6. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/models/base.py +11 -12
  7. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/models/tricc.py +5 -2
  8. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/serializers/xls_form.py +9 -116
  9. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/strategies/input/drawio.py +1 -1
  10. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/strategies/output/xls_form.py +10 -7
  11. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/strategies/output/xlsform_cdss.py +0 -4
  12. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/visitors/tricc.py +105 -80
  13. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo.egg-info/PKG-INFO +2 -1
  14. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo.egg-info/requires.txt +1 -0
  15. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/README.md +0 -0
  16. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/setup.cfg +0 -0
  17. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tests/build.py +0 -0
  18. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tests/test_cql.py +0 -0
  19. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tests/to_ocl.py +0 -0
  20. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/__init__.py +0 -0
  21. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/__init__.py +0 -0
  22. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/codesystem_to_ocl.py +0 -0
  23. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/cql/cqlLexer.py +0 -0
  24. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/cql/cqlListener.py +0 -0
  25. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/cql/cqlParser.py +0 -0
  26. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/cql/cqlVisitor.py +0 -0
  27. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/drawio_type_map.py +0 -0
  28. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/tricc_to_xls_form.py +0 -0
  29. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/converters/utils.py +0 -0
  30. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/models/__init__.py +0 -0
  31. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/models/calculate.py +0 -0
  32. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/models/lang.py +0 -0
  33. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/models/ocl.py +0 -0
  34. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/models/ordered_set.py +0 -0
  35. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/parsers/__init__.py +0 -0
  36. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/parsers/xml.py +0 -0
  37. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/serializers/__init__.py +0 -0
  38. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/serializers/planuml.py +0 -0
  39. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/strategies/__init__.py +0 -0
  40. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/strategies/input/__init__.py +0 -0
  41. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/strategies/input/base_input_strategy.py +0 -0
  42. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/strategies/output/base_output_strategy.py +0 -0
  43. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/strategies/output/spice.py +0 -0
  44. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/strategies/output/xlsform_cht.py +0 -0
  45. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/strategies/output/xlsform_cht_hf.py +0 -0
  46. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/visitors/__init__.py +0 -0
  47. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/visitors/utils.py +0 -0
  48. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo/visitors/xform_pd.py +0 -0
  49. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo.egg-info/SOURCES.txt +0 -0
  50. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo.egg-info/dependency_links.txt +0 -0
  51. {tricc_oo-1.4.17 → tricc_oo-1.4.18}/tricc_oo.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: tricc-oo
3
- Version: 1.4.17
3
+ Version: 1.4.18
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
@@ -14,6 +14,7 @@ Requires-Dist: markdownify
14
14
  Requires-Dist: pydantic
15
15
  Requires-Dist: babel
16
16
  Requires-Dist: xlsxwriter
17
+ Requires-Dist: html2text
17
18
  Requires-Dist: pandas
18
19
  Requires-Dist: polib
19
20
  Requires-Dist: strenum
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tricc-oo"
7
- version = "1.4.17"
7
+ version = "1.4.18"
8
8
  description = "Python library that converts CDSS L2 in L3"
9
9
  readme = "README.md"
10
10
 
@@ -19,6 +19,7 @@ dependencies = [
19
19
  "pydantic",
20
20
  "babel",
21
21
  "xlsxwriter",
22
+ "html2text",
22
23
  "pandas",
23
24
  "polib",
24
25
  "strenum",
@@ -150,6 +150,13 @@ class cqlToXlsFormVisitor(cqlVisitor):
150
150
  function_name = ctx.getChild(2).getText()
151
151
  return not_clean(self._get_membership_expression(ctx, function_name))
152
152
 
153
+ def visitInvocationExpressionTerm(self, ctx):
154
+ result = super().visitInvocationExpressionTerm(ctx)
155
+ if isinstance(result, list) and all(isinstance(x, TriccStatic) for x in result):
156
+ value = '.'.join([x.value for x in result])
157
+ logger.warning(f"guessed reference for '{value}'")
158
+ return TriccReference(value)
159
+ return result
153
160
 
154
161
  def visitBetweenExpression(self, ctx):
155
162
  ref = self.visit(ctx.expression(0))
@@ -16,6 +16,10 @@ logger = logging.getLogger("default")
16
16
 
17
17
 
18
18
  def lookup_codesystems_code(codesystems, ref):
19
+ if ref.startswith('final.'):
20
+ concept = lookup_codesystems_code(codesystems, ref[6:])
21
+ if concept:
22
+ return concept
19
23
  for code_system in codesystems.values():
20
24
  for concept in code_system.concept or []:
21
25
  if concept.code == ref:
@@ -35,6 +35,7 @@ DISPLAY_ATTRIBUTES = [
35
35
  'help'
36
36
  ]
37
37
  logger = logging.getLogger("default")
38
+ import html2text
38
39
 
39
40
 
40
41
 
@@ -211,6 +212,7 @@ def process_edges(diagram, media_path, activity, nodes):
211
212
  ):
212
213
  if isinstance(nodes[edge.source], TriccNodeRhombus):
213
214
  edge.source = nodes[edge.source].path.id
215
+ edge.source_external_id = None
214
216
  processed = True
215
217
  elif label.lower() in (TRICC_YES_LABEL) or label == "":
216
218
  # do nothinbg for yes
@@ -219,7 +221,7 @@ def process_edges(diagram, media_path, activity, nodes):
219
221
  calc = process_factor_edge(edge, nodes)
220
222
  elif label.lower() in TRICC_NO_LABEL:
221
223
  calc = process_exclusive_edge(edge, nodes)
222
- elif any(reserved in label.lower() for reserved in ([str(o) for o in list(TriccOperator)] + list(OPERATION_LIST.keys()) + ['$this'])):
224
+ elif any(reserved in html2text.html2text(label.lower()) for reserved in ([str(o) for o in list(TriccOperator)] + list(OPERATION_LIST.keys()) + ['$this'])):
223
225
  # manage comment
224
226
  calc = process_condition_edge(edge, nodes)
225
227
  else:
@@ -118,10 +118,6 @@ class TriccBaseModel(BaseModel):
118
118
 
119
119
  def make_instance(self, nb_instance, **kwargs):
120
120
  instance = self.copy()
121
- # change the id to avoid collision of name
122
- instance.id = generate_id(f"{self.id}{nb_instance}")
123
- instance.instance = int(nb_instance)
124
- instance.base_instance = self
125
121
  attr_dict = self.to_dict()
126
122
  for attr, value in attr_dict.items():
127
123
  if not attr.startswith('_') and value is not None:
@@ -132,6 +128,13 @@ class TriccBaseModel(BaseModel):
132
128
  setattr(instance, attr, value)
133
129
  except Exception as e:
134
130
  logger.warning(f"Warning: Could not copy attribute {attr}: {e}")
131
+
132
+ # change the id to avoid collision of name
133
+ instance.id = generate_id(f"{self.id}{nb_instance}")
134
+ instance.instance = int(nb_instance)
135
+ instance.base_instance = self
136
+
137
+
135
138
  # assign the defualt group
136
139
  # if activity is not None and self.group == activity.base_instance:
137
140
  # instance.group = instance
@@ -269,7 +272,7 @@ class TriccNodeBaseModel(TriccBaseModel):
269
272
  if self.name is None:
270
273
  self.name = get_rand_name(self.id)
271
274
  def get_references(self):
272
- return OrderedSet([self])
275
+ return OrderedSet()
273
276
 
274
277
  class TriccStatic(BaseModel):
275
278
  value: Union[str, float, int, bool]
@@ -706,17 +709,13 @@ def nand_join(left, right):
706
709
  right_issue = right is None or right == ''
707
710
  left_neg = left == False or left == 0 or left == '0' or left == TriccStatic(False)
708
711
  right_neg = right == False or right == 0 or right == '0' or right == TriccStatic(False)
709
- if issubclass(left.__class__, TriccNodeBaseModel):
710
- left = get_export_name(left)
711
- if issubclass(right.__class__, TriccNodeBaseModel):
712
- right = get_export_name(right)
713
712
  if left_issue and right_issue:
714
713
  logger.critical("and with both terms empty")
715
714
  elif left_issue:
716
715
  logger.debug('and with empty left term')
717
- return negate_term(right)
716
+ return not_clean(right)
718
717
  elif left == '1' or left == 1 or left == TriccStatic(True):
719
- return negate_term(right)
718
+ return not_clean(right)
720
719
  elif right_issue :
721
720
  logger.debug('and with empty right term')
722
721
  return TriccStatic(False)
@@ -725,7 +724,7 @@ def nand_join(left, right):
725
724
  elif right_neg:
726
725
  return left
727
726
  else:
728
- return and_join([left, negate_term(right)])
727
+ return and_join([left, not_clean(right)])
729
728
 
730
729
 
731
730
  TriccGroup.update_forward_refs()
@@ -96,7 +96,9 @@ class TriccNodeActivity(TriccNodeBaseModel):
96
96
  return self.instances[instance_nb]
97
97
  else:
98
98
  instance = super().make_instance(instance_nb, activity=None)
99
- self.instances[instance_nb] = instance
99
+ base_instance = (self.base_instance or self)
100
+ base_instance.instances[instance_nb] = instance
101
+ instance.base_instance = base_instance
100
102
  # instance.base_instance = self
101
103
  # we duplicate all the related nodes (not the calculate, duplication is manage in calculate version code)
102
104
  nodes = {}
@@ -124,7 +126,7 @@ class TriccNodeActivity(TriccNodeBaseModel):
124
126
  if node in self.calculates and instance_node:
125
127
  instance.calculates.append(instance_node)
126
128
  # update parents
127
- for node in list(filter(lambda p_node: hasattr(p_node, 'parent'),list(instance.nodes.values()))):
129
+ for node in list(filter(lambda p_node: getattr(p_node, 'parent', None) is not None, list(instance.nodes.values()))):
128
130
  new_parent = list(filter(lambda p_node: p_node.base_instance == node.parent,list(instance.nodes.values())))
129
131
  if new_parent:
130
132
  node.parent = new_parent[0]
@@ -179,6 +181,7 @@ class TriccNodeActivity(TriccNodeBaseModel):
179
181
  if issubclass(node_instance.__class__, TriccRhombusMixIn):
180
182
  old_path = node_origin.path
181
183
  if old_path is not None:
184
+ node_instance.path = None
182
185
  for n in node_instance.activity.nodes.values():
183
186
  if n.base_instance.id == old_path.id:
184
187
  node_instance.path = n
@@ -18,6 +18,9 @@ from tricc_oo.visitors.tricc import (
18
18
  add_calculate,
19
19
  TRICC_TRUE_VALUE,
20
20
  TRICC_FALSE_VALUE,
21
+ get_applicability_expression,
22
+ get_prev_instance_skip_expression,
23
+ get_process_skip_expression,
21
24
  )
22
25
 
23
26
  logger = logging.getLogger("default")
@@ -32,7 +35,7 @@ BOOLEAN_MAP = {
32
35
 
33
36
 
34
37
  def start_group(
35
- strategy, cur_group, groups, df_survey, df_calculate, relevance=False, **kwargs
38
+ strategy, cur_group, groups, df_survey, df_calculate, processed_nodes, process, relevance=False, **kwargs
36
39
  ):
37
40
  name = get_export_name(cur_group)
38
41
 
@@ -46,12 +49,17 @@ def start_group(
46
49
  relevance = (
47
50
  relevance and cur_group.relevance is not None and cur_group.relevance != ""
48
51
  )
52
+
49
53
 
50
54
  group_calc_required = (
51
55
  False and relevance and not is_activity and len(relevance) > 100
52
56
  )
53
57
 
54
58
  relevance_expression = cur_group.relevance
59
+ relevance_expression = get_applicability_expression(cur_group, processed_nodes, process, relevance_expression)
60
+ relevance_expression = get_prev_instance_skip_expression(cur_group, processed_nodes, process, relevance_expression)
61
+ relevance_expression = get_process_skip_expression(cur_group, processed_nodes, process, relevance_expression)
62
+
55
63
  if not relevance:
56
64
  relevance_expression = ""
57
65
  elif isinstance(relevance_expression, TriccOperation):
@@ -628,118 +636,3 @@ def get_input_calc_line(node, replace_dots=True):
628
636
  ]
629
637
 
630
638
 
631
- def get_diagnostic_start_group_line():
632
- label = langs.get_trads("List of diagnostics", force_dict=True)
633
- empty = langs.get_trads("", force_dict=True)
634
- return [
635
- "begin group",
636
- "l_diag_list25",
637
- *list(label.values()),
638
- *list(empty.values()), # hint
639
- *list(empty.values()), # help
640
- "", # default
641
- "field-list", #'appearance',
642
- "", #'constraint',
643
- *list(empty.values()), #'constraint_message'
644
- "", #'relevance'
645
- "", #'disabled'
646
- "", #'required'
647
- *list(empty.values()), #'required message'
648
- "", #'read only'
649
- "", #'expression'
650
- "", #'repeat_count'
651
- "", #'image'
652
- "",
653
- ]
654
-
655
-
656
- def get_diagnostic_add_line(diags, df_choice):
657
- for diag in diags:
658
- df_choice.loc[len(df_choice)] = [
659
- "tricc_diag_add",
660
- get_export_name(diag),
661
- *list(langs.get_trads(diag.label, True).values()),
662
- "", # filter
663
- "", # min y
664
- "", # max Y
665
- "", # l
666
- "", # m
667
- "", # s
668
- ]
669
- label = langs.get_trads("Add a missing diagnostic", force_dict=True)
670
- empty = langs.get_trads("", force_dict=True)
671
- return [
672
- "select_multiple tricc_diag_add",
673
- "new_diag",
674
- *list(label.values()),
675
- *list(empty.values()), # hint
676
- *list(empty.values()), # help
677
- "", # default
678
- "minimal", #'appearance',
679
- "", #'constraint',
680
- *list(empty.values()), #'constraint_message',
681
- "", #'relevance'
682
- "", #'disabled'
683
- "", #'required'
684
- *list(empty.values()), #'required message'
685
- "", #'read only'
686
- "", #'expression'
687
- "", #'repeat_count'
688
- "", #'image'
689
- "",
690
- ]
691
-
692
-
693
- def get_diagnostic_none_line(diags):
694
- relevance = ""
695
- for diag in diags:
696
- relevance += TRICC_CALC_EXPRESSION.format(get_export_name(diag)) + " or "
697
- label = langs.get_trads(
698
- "Aucun diagnostic trouvé par l'outil mais cela ne veut pas dire que le patient est en bonne santé",
699
- force_dict=True,
700
- )
701
- empty = langs.get_trads("", force_dict=True)
702
- return [
703
- "note",
704
- "l_diag_none25",
705
- *list(label.values()),
706
- *list(empty.values()),
707
- *list(empty.values()),
708
- "", # default
709
- "", #'appearance',
710
- "", #'constraint',
711
- *list(empty.values()),
712
- f"not({relevance[:-4]})", #'relevance'
713
- "", #'disabled'
714
- "", #'required'
715
- *list(empty.values()),
716
- "", #'read only'
717
- "", #'expression'
718
- "", #'repeat_count'
719
- "", #'image' TRICC_NEGATE
720
- "",
721
- ]
722
-
723
-
724
- def get_diagnostic_stop_group_line():
725
- label = langs.get_trads("", force_dict=True)
726
- return [
727
- "end group",
728
- "l_diag_list25",
729
- *list(label.values()),
730
- *list(label.values()),
731
- *list(label.values()), # help
732
- "", # default
733
- "", #'appearance',
734
- "", #'constraint',
735
- *list(label.values()),
736
- "", #'relevance'
737
- "", #'disabled'
738
- "", #'required'
739
- *list(label.values()),
740
- "", #'read only'
741
- "", #'expression'
742
- "", #'repeat_count'
743
- "", #'image'
744
- "",
745
- ]
@@ -126,8 +126,8 @@ class DrawioStrategy(BaseInputStrategy):
126
126
 
127
127
  node_edge = list(
128
128
  filter(lambda x: (
129
- (x.source_external_id and x.source_external_id == node.external_id) or
130
129
  ( x.source and x.source == node.id) or
130
+ (not x.source and x.source_external_id and x.source_external_id == node.external_id) or
131
131
  x.source == node
132
132
  ), page.edges)
133
133
  )
@@ -85,7 +85,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
85
85
 
86
86
 
87
87
  def clean_coalesce(self, expression):
88
- if re.match(r"^coalesce\(\${[^}]+},''\)$", expression):
88
+ if re.match(r"^coalesce\(\${[^}]+},''\)$", str(expression)):
89
89
  return expression[9:-4]
90
90
  return expression
91
91
 
@@ -174,8 +174,9 @@ class XLSFormStrategy(BaseOutPutStrategy):
174
174
  cur_group = activity
175
175
  groups[activity.id] = 0
176
176
  path_len = 0
177
+ process = ['main']
177
178
  # keep the vesrions on the group id, max version
178
- start_group(self, cur_group=cur_group, groups=groups, **self.get_kwargs())
179
+ start_group(self, cur_group=cur_group, groups=groups, processed_nodes=processed_nodes, process=process, **self.get_kwargs())
179
180
  walktrhough_tricc_node_processed_stached(
180
181
  activity.root,
181
182
  self.generate_export,
@@ -183,6 +184,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
183
184
  stashed_nodes,
184
185
  path_len,
185
186
  cur_group=activity.root.group,
187
+ process=process,
186
188
  recursive=False,
187
189
  **self.get_kwargs()
188
190
  )
@@ -218,6 +220,8 @@ class XLSFormStrategy(BaseOutPutStrategy):
218
220
  self,
219
221
  cur_group=s_node.group,
220
222
  groups=groups,
223
+ processed_nodes=processed_nodes,
224
+ process=process,
221
225
  relevance=True,
222
226
  **self.get_kwargs()
223
227
  )
@@ -314,9 +318,8 @@ class XLSFormStrategy(BaseOutPutStrategy):
314
318
  save_calc = save_calc.iloc[0]
315
319
  if save_calc["name"] != drop_calc["name"]:
316
320
  self.df_survey.replace(
317
- "\$\{" + drop_calc["name"] + "\}",
318
- "\$\{" + save_calc["name"] + "\}",
319
- regex=True,
321
+ "${" + drop_calc["name"] + "}",
322
+ "${" + save_calc["name"] + "}",
320
323
  )
321
324
  else:
322
325
  logger.critical(
@@ -325,7 +328,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
325
328
  )
326
329
  )
327
330
  for index, empty_calc in df_empty_calc.iterrows():
328
- self.df_survey.replace("\$\{" + empty_calc["name"] + "\}", "1", regex=True)
331
+ self.df_survey.replace("${" + empty_calc["name"] + "}", "1", regex=True)
329
332
 
330
333
  # TODO try to reinject calc to reduce complexity
331
334
  for i, c in self.df_calculate[
@@ -334,7 +337,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
334
337
  real_calc = re.find(r"^number\((.+)\)$", c["calculation"])
335
338
  if real_calc is not None and real_calc != "":
336
339
  self.df_survey[~self.df_survey["name"] == c["name"]].replace(
337
- real_calc, "\$\{" + c["name"] + "\}"
340
+ real_calc, "${" + c["name"] + "}"
338
341
  )
339
342
 
340
343
  df_duplicate = self.df_survey[
@@ -1,10 +1,6 @@
1
1
  import logging
2
2
  from tricc_oo.models.tricc import TriccNodeActivity
3
3
  from tricc_oo.models.calculate import TriccNodeProposedDiagnosis, TriccNodeInput
4
- from tricc_oo.serializers.xls_form import (
5
- get_diagnostic_none_line,
6
- get_diagnostic_start_group_line,
7
- get_diagnostic_stop_group_line)
8
4
  from tricc_oo.converters.tricc_to_xls_form import get_export_name
9
5
  from tricc_oo.strategies.output.xls_form import XLSFormStrategy
10
6
  from tricc_oo.models.lang import SingletonLangClass
@@ -657,7 +657,7 @@ def process_operation_reference(operation, node, processed_nodes, calculates, us
657
657
  if codesystems:
658
658
  concept = lookup_codesystems_code(codesystems, ref)
659
659
  if not concept:
660
- logger.critical(f"reference {ref} not found in the project")
660
+ logger.critical(f"reference {ref} not found in the project for{str(node)} ")
661
661
  exit(1)
662
662
  else:
663
663
  if warn:
@@ -1144,23 +1144,34 @@ def check_stashed_loop(stashed_nodes, prev_stashed_nodes, processed_nodes, len_p
1144
1144
  es_node.activity.instance if hasattr(es_node,'activity') else '',
1145
1145
  es_node.__class__,
1146
1146
  es_node.get_name()))
1147
+ for es_node in [node for node_list in looped.values() for node in node_list if isinstance(node, TriccReference)]:
1148
+ logger.info("looped node {}:{}|{} {}".format(
1149
+ es_node.activity.get_name() if hasattr(es_node,'activity') else '' ,
1150
+ es_node.activity.instance if hasattr(es_node,'activity') else '',
1151
+ es_node.__class__,
1152
+ es_node.get_name()))
1153
+ for es_node in [node for node_list in waited.values() for node in node_list if isinstance(node, TriccReference)]:
1154
+ logger.info("waited node {}:{}|{} {}".format(
1155
+ es_node.activity.get_name() if hasattr(es_node,'activity') else '' ,
1156
+ es_node.activity.instance if hasattr(es_node,'activity') else '',
1157
+ es_node.__class__,
1158
+ es_node.get_name()))
1147
1159
  logger.info("looped nodes")
1148
1160
  for dep_list in looped:
1149
1161
  for d in looped[dep_list]:
1150
- if d.get_name() == dep_list:
1151
- logger.critical("[{}] depends on itself".format(
1152
- dep_list,
1162
+ if str(d) in looped:
1163
+ logger.critical("[{}] depends on [{}]".format(
1164
+ dep_list, str(d)
1165
+ ))
1166
+ else:
1167
+ logger.error("[{}] depends on [{}]".format(
1168
+ dep_list, str(d)
1153
1169
  ))
1154
- logger.error("[{}] depends on [{}]".format(
1155
- dep_list, str(d)
1156
- ))
1157
1170
  if dep_list in waited:
1158
1171
  for d in waited[dep_list]:
1159
1172
  logger.warning("[{}] depends on [{}]".format(
1160
1173
  dep_list, str(d)
1161
1174
  ))
1162
-
1163
- #reverse_walkthrough(es_node, es_node, print_trace, processed_nodes, stashed_nodes)
1164
1175
  logger.info("waited nodes")
1165
1176
  for dep_list in waited:
1166
1177
  if dep_list not in looped:
@@ -1177,7 +1188,6 @@ def check_stashed_loop(stashed_nodes, prev_stashed_nodes, processed_nodes, len_p
1177
1188
  loop_count = 0
1178
1189
  return loop_count
1179
1190
 
1180
-
1181
1191
  def add_to_tree(tree, n, d):
1182
1192
  n_str = str(n)
1183
1193
  if n_str not in tree:
@@ -1187,12 +1197,16 @@ def add_to_tree(tree, n, d):
1187
1197
  return tree
1188
1198
 
1189
1199
 
1190
- def get_all_dependant(loop, stashed_nodes, processed_nodes, depth=0, waited=None , looped=None):
1200
+ def get_all_dependant(loop, stashed_nodes, processed_nodes, depth=0, waited=None , looped=None, path = None):
1201
+ if path is None:
1202
+ path =[]
1191
1203
  if looped is None:
1192
1204
  looped = {}
1193
1205
  if waited is None:
1194
1206
  waited = {}
1195
1207
  for n in loop:
1208
+ cur_path = path.copy()
1209
+ cur_path.append(n)
1196
1210
  dependant = OrderedSet()
1197
1211
  i=0
1198
1212
  #logger.critical(f"{i}: {n.__class__}::{n.get_name()}::{getattr(n,'instance','')}::{process_reference(n, processed_nodes, [])}")
@@ -1204,28 +1218,30 @@ def get_all_dependant(loop, stashed_nodes, processed_nodes, depth=0, waited=None
1204
1218
  if not isinstance(dependant, list):
1205
1219
  pass
1206
1220
  for d in dependant:
1221
+ if d in path:
1222
+ logger.warning(f"loop {str(d)} already in path {'::'.join(map(path, str))} ")
1207
1223
  if isinstance(d, TriccNodeSelectOption):
1208
1224
  d = d.select
1209
- if d not in waited and d not in looped:
1210
- if isinstance(d, TriccReference):
1211
- if not any(n.name == d.value for n in processed_nodes):
1212
- if not any(n.name == d.value for n in stashed_nodes):
1213
- waited = add_to_tree(waited, n, d)
1214
- else :
1215
- looped = add_to_tree(looped, n, d)
1216
-
1217
- elif d not in processed_nodes:
1218
- if d in stashed_nodes:
1219
- looped = add_to_tree(looped, n, d)
1225
+
1226
+ if isinstance(d, TriccReference):
1227
+ if not any(n.name == d.value for n in processed_nodes):
1228
+ if not any(n.name == d.value for n in stashed_nodes):
1229
+ waited = add_to_tree(waited, n, d)
1220
1230
  else :
1221
- waited = add_to_tree(waited, n, d)
1231
+ looped = add_to_tree(looped, n, d)
1232
+
1233
+ elif d not in processed_nodes:
1234
+ if d in stashed_nodes:
1235
+ looped = add_to_tree(looped, n, d)
1236
+ else :
1237
+ waited = add_to_tree(waited, n, d)
1222
1238
  if depth < MAX_DRILL:
1223
- return get_all_dependant(waited, stashed_nodes, processed_nodes, depth+1, waited , looped)
1239
+ return get_all_dependant(looped, stashed_nodes, processed_nodes, depth+1, waited , looped, path=cur_path)
1224
1240
 
1225
1241
  return waited, looped
1226
1242
 
1227
1243
 
1228
- MAX_DRILL = 1
1244
+ MAX_DRILL = 3
1229
1245
 
1230
1246
  def get_last_end_node(processed_nodes, process=None):
1231
1247
  end_name = 'tricc_end_'
@@ -1548,61 +1564,10 @@ def get_node_expression( in_node, processed_nodes, is_calculate=False, is_prev=F
1548
1564
  if expression is None:
1549
1565
  expression = get_prev_node_expression(node, processed_nodes=processed_nodes, is_calculate=is_calculate, process=process)
1550
1566
  # in_node not in processed_nodes is need for calculates that can but run after the end of the activity
1551
-
1552
-
1553
- if isinstance(node, TriccNodeActivity):
1554
-
1555
-
1556
- if node.base_instance is not None and not is_prev:
1557
- activity = node
1558
- expression_inputs = []
1559
- past_instances = [
1560
- n for n in processed_nodes if getattr(n.base_instance, 'id', None) == node.base_instance.id
1561
- ]
1562
- for past_instance in past_instances:
1563
- add_sub_expression(
1564
- expression_inputs,
1565
- get_node_expression(
1566
- past_instance,
1567
- processed_nodes=processed_nodes,
1568
- is_calculate=False,
1569
- is_prev=True,
1570
- process=process
1571
- )
1572
- )
1573
-
1574
- if isinstance(node.applicability,(TriccStatic,TriccOperation, TriccReference)):
1575
- if expression:
1576
- expression = and_join([node.applicability, expression])
1577
- else:
1578
- expression = node.applicability
1579
- if expression and expression_inputs:
1580
- add_sub_expression(expression_inputs, expression)
1581
- expression = nand_join(expression, or_join(expression_inputs))
1582
- elif expression_inputs:
1583
- expression = negate_term(or_join(expression_inputs))
1584
- if not is_prev:
1585
- end_expressions = []
1586
- f_end_expression = get_end_expression(processed_nodes)
1587
- if f_end_expression:
1588
- end_expressions.append(f_end_expression)
1589
- if process[0] in PROCESSES:
1590
- for p in PROCESSES[PROCESSES.index(process[0])+1:]:
1591
- p_end_expression = get_end_expression(processed_nodes, p)
1592
- if p_end_expression:
1593
- end_expressions.append(p_end_expression)
1594
- if node.applicability:
1595
- end_expressions.append(node.applicability)
1596
- if end_expressions:
1597
- if expression:
1598
- end_expressions.append(expression)
1599
- if len(end_expressions) == 1:
1600
- expression = end_expressions[0]
1601
- else:
1602
- expression = and_join(end_expressions)
1603
-
1604
-
1605
-
1567
+ #if isinstance(node, TriccNodeActivitiy) and not prev:
1568
+ # expression = get_applicability_expression(node, processed_nodes, process, expression)
1569
+ # expression = get_prev_instance_skip_expression(node, processed_nodes, process, expression)
1570
+ # expression = get_process_skip_expression(node, processed_nodes, process, expression)
1606
1571
  if negate:
1607
1572
  if negate_expression is not None:
1608
1573
  return negate_expression
@@ -1613,7 +1578,67 @@ def get_node_expression( in_node, processed_nodes, is_calculate=False, is_prev=F
1613
1578
  # exit(1)
1614
1579
  else:
1615
1580
  return expression
1581
+
1582
+ def get_applicability_expression(node, processed_nodes, process, expression=None):
1583
+ if isinstance(node.applicability,(TriccStatic,TriccOperation, TriccReference)):
1584
+ if expression:
1585
+ expression = and_join([node.applicability, expression])
1586
+ else:
1587
+ expression = node.applicability
1588
+
1589
+ return expression
1590
+
1591
+
1592
+
1593
+
1594
+
1595
+ def get_prev_instance_skip_expression(node, processed_nodes, process, expression=None):
1596
+ if node.base_instance is not None:
1597
+ activity = node
1598
+ expression_inputs = []
1599
+ past_instances = [
1600
+ n for n in processed_nodes if getattr(n.base_instance, 'id', None) == node.base_instance.id
1601
+ ]
1602
+ for past_instance in past_instances:
1603
+ add_sub_expression(
1604
+ expression_inputs,
1605
+ get_node_expression(
1606
+ past_instance,
1607
+ processed_nodes=processed_nodes,
1608
+ is_calculate=False,
1609
+ is_prev=True,
1610
+ process=process
1611
+ )
1612
+ )
1613
+ if expression and expression_inputs:
1614
+ add_sub_expression(expression_inputs, expression)
1615
+ expression = nand_join(expression, or_join(expression_inputs))
1616
+ elif expression_inputs:
1617
+ expression = negate_term(or_join(expression_inputs))
1618
+ return expression
1616
1619
 
1620
+
1621
+ # end def
1622
+ def get_process_skip_expression(node, processed_nodes, process, expression=None):
1623
+
1624
+ end_expressions = []
1625
+ f_end_expression = get_end_expression(processed_nodes)
1626
+ if f_end_expression:
1627
+ end_expressions.append(f_end_expression)
1628
+ if process[0] in PROCESSES:
1629
+ for p in PROCESSES[PROCESSES.index(process[0])+1:]:
1630
+ p_end_expression = get_end_expression(processed_nodes, p)
1631
+ if p_end_expression:
1632
+ end_expressions.append(p_end_expression)
1633
+ if end_expressions:
1634
+ if expression:
1635
+ end_expressions.append(expression)
1636
+ if len(end_expressions) == 1:
1637
+ expression = end_expressions[0]
1638
+ else:
1639
+ expression = and_join(end_expressions)
1640
+ return expression
1641
+
1617
1642
  def get_end_expression(processed_nodes, process=None):
1618
1643
  end_node = get_last_end_node(processed_nodes, process)
1619
1644
  if end_node:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tricc-oo
3
- Version: 1.4.17
3
+ Version: 1.4.18
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
@@ -14,6 +14,7 @@ Requires-Dist: markdownify
14
14
  Requires-Dist: pydantic
15
15
  Requires-Dist: babel
16
16
  Requires-Dist: xlsxwriter
17
+ Requires-Dist: html2text
17
18
  Requires-Dist: pandas
18
19
  Requires-Dist: polib
19
20
  Requires-Dist: strenum
@@ -3,6 +3,7 @@ markdownify
3
3
  pydantic
4
4
  babel
5
5
  xlsxwriter
6
+ html2text
6
7
  pandas
7
8
  polib
8
9
  strenum
File without changes
File without changes
File without changes
File without changes
File without changes