tricc-oo 1.0.1__py3-none-any.whl → 1.4.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. tests/build.py +213 -0
  2. tests/test_cql.py +197 -0
  3. tests/to_ocl.py +51 -0
  4. {tricc → tricc_oo}/__init__.py +3 -1
  5. tricc_oo/converters/codesystem_to_ocl.py +169 -0
  6. tricc_oo/converters/cql/cqlLexer.py +822 -0
  7. tricc_oo/converters/cql/cqlListener.py +1632 -0
  8. tricc_oo/converters/cql/cqlParser.py +11204 -0
  9. tricc_oo/converters/cql/cqlVisitor.py +913 -0
  10. tricc_oo/converters/cql_to_operation.py +402 -0
  11. tricc_oo/converters/datadictionnary.py +115 -0
  12. tricc_oo/converters/drawio_type_map.py +222 -0
  13. tricc_oo/converters/tricc_to_xls_form.py +61 -0
  14. tricc_oo/converters/utils.py +65 -0
  15. tricc_oo/converters/xml_to_tricc.py +1003 -0
  16. tricc_oo/models/__init__.py +4 -0
  17. tricc_oo/models/base.py +732 -0
  18. tricc_oo/models/calculate.py +216 -0
  19. tricc_oo/models/ocl.py +281 -0
  20. tricc_oo/models/ordered_set.py +125 -0
  21. tricc_oo/models/tricc.py +418 -0
  22. tricc_oo/parsers/xml.py +138 -0
  23. tricc_oo/serializers/__init__.py +0 -0
  24. tricc_oo/serializers/xls_form.py +745 -0
  25. tricc_oo/strategies/__init__.py +0 -0
  26. tricc_oo/strategies/input/__init__.py +0 -0
  27. tricc_oo/strategies/input/base_input_strategy.py +111 -0
  28. tricc_oo/strategies/input/drawio.py +317 -0
  29. tricc_oo/strategies/output/base_output_strategy.py +148 -0
  30. tricc_oo/strategies/output/spice.py +365 -0
  31. tricc_oo/strategies/output/xls_form.py +697 -0
  32. tricc_oo/strategies/output/xlsform_cdss.py +189 -0
  33. tricc_oo/strategies/output/xlsform_cht.py +200 -0
  34. tricc_oo/strategies/output/xlsform_cht_hf.py +334 -0
  35. tricc_oo/visitors/__init__.py +0 -0
  36. tricc_oo/visitors/tricc.py +2198 -0
  37. tricc_oo/visitors/utils.py +17 -0
  38. tricc_oo/visitors/xform_pd.py +264 -0
  39. tricc_oo-1.4.15.dist-info/METADATA +219 -0
  40. tricc_oo-1.4.15.dist-info/RECORD +46 -0
  41. {tricc_oo-1.0.1.dist-info → tricc_oo-1.4.15.dist-info}/WHEEL +1 -1
  42. tricc_oo-1.4.15.dist-info/top_level.txt +2 -0
  43. tricc/converters/mc_to_tricc.py +0 -542
  44. tricc/converters/tricc_to_xls_form.py +0 -553
  45. tricc/converters/utils.py +0 -44
  46. tricc/converters/xml_to_tricc.py +0 -740
  47. tricc/models/tricc.py +0 -1093
  48. tricc/parsers/xml.py +0 -81
  49. tricc/serializers/xls_form.py +0 -364
  50. tricc/strategies/input/base_input_strategy.py +0 -80
  51. tricc/strategies/input/drawio.py +0 -246
  52. tricc/strategies/input/medalcreator.py +0 -168
  53. tricc/strategies/output/base_output_strategy.py +0 -92
  54. tricc/strategies/output/xls_form.py +0 -194
  55. tricc/strategies/output/xlsform_cdss.py +0 -46
  56. tricc/strategies/output/xlsform_cht.py +0 -106
  57. tricc/visitors/tricc.py +0 -375
  58. tricc_oo-1.0.1.dist-info/LICENSE +0 -78
  59. tricc_oo-1.0.1.dist-info/METADATA +0 -229
  60. tricc_oo-1.0.1.dist-info/RECORD +0 -26
  61. tricc_oo-1.0.1.dist-info/top_level.txt +0 -2
  62. venv/bin/vba_extract.py +0 -78
  63. {tricc → tricc_oo}/converters/__init__.py +0 -0
  64. {tricc → tricc_oo}/models/lang.py +0 -0
  65. {tricc/serializers → tricc_oo/parsers}/__init__.py +0 -0
  66. {tricc → tricc_oo}/serializers/planuml.py +0 -0
tricc/models/tricc.py DELETED
@@ -1,1093 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import logging
4
- import random
5
- import string
6
- from enum import Enum, auto
7
- from typing import Dict, ForwardRef, List, Optional, Union
8
-
9
- from pydantic import BaseModel, constr
10
- from strenum import StrEnum
11
-
12
- from tricc.converters.utils import generate_id
13
-
14
- logger = logging.getLogger("default")
15
-
16
- Expression = constr(regex="^[^\\/]+$")
17
-
18
- triccId = constr(regex="^.+$")
19
- triccIdList = constr(regex="^.+$")
20
-
21
- b64 = constr(regex="[^-A-Za-z0-9+/=]|=[^=]|={3,}$")
22
-
23
- TriccEdge = ForwardRef('TriccEdge')
24
- # data:page/id,UkO_xCL5ZjyshJO9Bexg
25
-
26
-
27
- ACTIVITY_END_NODE_FORMAT = "aend_{}"
28
- END_NODE_FORMAT = "end_{}"
29
-
30
-
31
- class TriccNodeType(StrEnum):
32
- #replace with auto ?
33
- note = 'note'
34
- calculate = 'calculate'
35
- select_multiple = 'select_multiple'
36
- select_one = 'select_one'
37
- decimal = 'decimal'
38
- integer = 'integer'
39
- text = 'text'
40
- date = 'date'
41
- rhombus = 'rhombus' # fetch data
42
- goto = 'goto' #: start the linked activity within the target activity
43
- start = 'start' #: main start of the algo
44
- activity_start = 'activity_start' #: start of an activity (link in)
45
- link_in = 'link_in'
46
- link_out = 'link_out'
47
- count = 'count' #: count the number of valid input
48
- add = 'add' # add counts
49
- container_hint_media = 'container_hint_media' # DEPRECATED
50
- activity = 'activity'
51
- select_yesno = 'select_one yesno' # NOT YET SUPPORTED
52
- select_option = 'select_option'
53
- hint = 'hint-message'
54
- help = 'help-message'
55
- exclusive = 'not'
56
- end = 'end'
57
- activity_end = 'activity_end'
58
- edge = 'edge'
59
- page = 'page'
60
- not_available = 'not_available'
61
- quantity = 'quantity'
62
- bridge = 'bridge'
63
- wait = 'wait'
64
-
65
-
66
- class TriccOperation(str, Enum):
67
- _and = 'and'
68
- _or = 'or'
69
- _not = 'not'
70
-
71
-
72
- media_nodes = [
73
- TriccNodeType.note,
74
- TriccNodeType.select_multiple,
75
- TriccNodeType.select_one,
76
- TriccNodeType.decimal,
77
- TriccNodeType.integer,
78
- TriccNodeType.text,
79
- ]
80
-
81
-
82
- class TriccBaseModel(BaseModel):
83
- id: triccId
84
- tricc_type: TriccNodeType
85
- #parent: Optional[triccId]#TODO: used ?
86
- instance: int = 1
87
- base_instance: Optional[TriccBaseModel]
88
-
89
- def make_instance(self, nb_instance, **kwargs):
90
- instance = self.copy()
91
- # change the id to avoid collision of name
92
- instance.id = generate_id()
93
- instance.instance = int(nb_instance)
94
- instance.base_instance = self
95
-
96
- # assign the defualt group
97
- # if activity is not None and self.group == activity.base_instance:
98
- # instance.group = instance
99
- return instance
100
-
101
- def __eq__(self, other):
102
- if isinstance(other, self.__class__):
103
- return self.id == other.id
104
- else:
105
- return False
106
-
107
- def __ne__(self, other):
108
- return not self.__eq__(other)
109
-
110
- def __hash__(self):
111
- hash_value = hash(self.id)
112
- return hash_value
113
-
114
- def get_name(self):
115
- return id
116
-
117
-
118
- class TriccEdge(TriccBaseModel):
119
- tricc_type: TriccNodeType = TriccNodeType.edge
120
- source: Union[triccId, TriccNodeBaseModel]
121
- target: Union[triccId, TriccNodeBaseModel]
122
- value: Optional[str]
123
-
124
- def make_instance(self, instance_nb, activity=None):
125
- instance = super().make_instance(instance_nb, activity=activity)
126
- #if issubclass(self.source.__class__, TriccBaseModel):
127
- instance.source = self.source if isinstance(self.source, str) else self.source.copy() #TODO should we copy the nodes ?
128
- #if issubclass(self.target.__class__, TriccBaseModel):
129
- instance.target = self.target if isinstance(self.target, str) else self.target.copy()
130
- return instance
131
-
132
-
133
- class TriccGroup(TriccBaseModel):
134
- tricc_type: TriccNodeType = TriccNodeType.page
135
- group: Optional[TriccBaseModel]
136
- name: Optional[str]
137
- export_name:Optional[str]
138
- label: Optional[Union[str, Dict[str,str]]]
139
- relevance: Optional[Expression]
140
- path_len: int = 0
141
- prev_nodes: List[TriccBaseModel] = []
142
- def __init__(self, **data):
143
- super().__init__(**data)
144
- if self.name is None:
145
- self.name = generate_id()
146
-
147
- def get_name(self):
148
-
149
- if self.label is not None:
150
- name = self.label[self.label.keys()[0]] if isinstance(self.label, Dict) else self.label
151
- if len(name) < 50:
152
- return name
153
- else:
154
- return name[:50]
155
- else:
156
- return self.name
157
-
158
-
159
- class TriccNodeBaseModel(TriccBaseModel):
160
- path_len: int = 0
161
- group: Optional[Union[TriccGroup, TriccNodeActivity]]
162
- name: Optional[str]
163
- export_name:Optional[str]
164
- label: Optional[Union[str, Dict[str,str]]]
165
- next_nodes: List[TriccNodeBaseModel] = []
166
- prev_nodes: List[TriccNodeBaseModel] = []
167
- expression: Optional[Expression] # will be generated based on the input
168
- expression_inputs: List[Expression] = []
169
- activity: Optional[TriccNodeActivity]
170
- ref_def: Optional[Union[int,str]] # for medal creator
171
-
172
- class Config:
173
- use_enum_values = True # <--
174
-
175
- # to be updated while processing because final expression will be possible to build$
176
- # #only the last time the script will go through the node (all prev node expression would be created
177
-
178
- def get_name(self):
179
- if self.label is not None:
180
- name = next(iter(self.label.values())) if isinstance(self.label, Dict) else self.label
181
- if len(name) < 50:
182
- return name
183
- else:
184
- return name[:50]
185
- elif self.name is not None:
186
- return self.name
187
- else:
188
- # TODO call parent.get_name instead
189
- return self.id
190
-
191
- def make_instance(self, instance_nb, activity=None):
192
- instance = super().make_instance(instance_nb)
193
- instance.group = activity
194
- if hasattr(self, 'activity') and activity is not None:
195
- instance.activity = activity
196
- next_nodes = []
197
- instance.next_nodes = next_nodes
198
- prev_nodes = []
199
- instance.prev_nodes = prev_nodes
200
- expression_inputs = []
201
- instance.expression_inputs = expression_inputs
202
-
203
- return instance
204
-
205
- def gen_name(self):
206
- if self.name is None:
207
- self.name = ''.join(random.choices(string.ascii_lowercase, k=8))
208
-
209
-
210
- class TriccNodeActivity(TriccNodeBaseModel):
211
- tricc_type: TriccNodeType = TriccNodeType.activity
212
- # starting point of the activity
213
- root: TriccNodeBaseModel
214
- # edge list
215
- edges: List[TriccEdge] = []
216
- # copy of the edge for later restauration
217
- unused_edges: List[TriccEdge] = []
218
- # nodes part of that actvity
219
- nodes: Dict[str, TriccNodeBaseModel] = {}
220
- # groups
221
- groups: Dict[str, TriccGroup] = {}
222
- # save the instance on the base activity
223
- instances: Dict[int, TriccNodeBaseModel] = {}
224
- relevance: Optional[Expression]
225
- #caclulate that are not part of the any skip logic:
226
- # - inputs
227
- # - dandling calculate
228
- # - case definition
229
- calculates: List[TriccNodeCalculateBase] = []
230
-
231
- # redefine
232
- def make_instance(self, instance_nb, **kwargs):
233
- # shallow copy
234
- if instance_nb in self.instances:
235
- return self.instances[instance_nb]
236
- else:
237
- instance = super().make_instance(instance_nb, activity=None)
238
- self.instances[instance_nb] = instance
239
- # instance.base_instance = self
240
- # we duplicate all the related nodes (not the calculate, duplication is manage in calculate version code)
241
- nodes = {}
242
- instance.nodes = nodes
243
- edges = []
244
- instance.edges = edges
245
- unused_edges = []
246
- instance.edges = unused_edges
247
- calculates = []
248
- instance.calculates = calculates
249
- relevance = None
250
- instance.relevance = relevance
251
- groups = {}
252
- instance.groups = groups
253
- instance.group = instance
254
- instance.activity = instance
255
- for edge in self.edges:
256
- instance.edges.append(edge.make_instance(instance_nb, activity=instance))
257
- instance.update_nodes(self.root)
258
- # we walk throught the nodes and replace them when ready
259
- for node in list(filter(lambda p_node: isinstance(p_node, (TriccNodeDisplayBridge,TriccNodeBridge)),list(self.nodes.values()) )):
260
- instance.update_nodes(node)
261
- for node in list(filter(lambda p_node: p_node != self.root and not isinstance(p_node, (TriccNodeDisplayBridge,TriccNodeBridge)),list(self.nodes.values()) )):
262
- instance_node = instance.update_nodes(node)
263
- if node in self.calculates and instance_node:
264
- instance.calulates.append(instance_node)
265
-
266
- for group in self.groups:
267
- instance.update_groups(group)
268
- # update parent group
269
- for group in self.groups:
270
- instance.update_groups_group(group)
271
-
272
- return instance
273
-
274
- def update_groups_group(self, group):
275
- for instance_group in self.groups:
276
- if instance_group.group == group:
277
- instance_group.group == instance_group
278
- elif instance_group.group == self.base_instance:
279
- instance_group.group == self
280
-
281
- def update_groups(self, group):
282
- # create new group
283
- instance_group = group.make_instance(self.instance, activity=self)
284
- # update the group in all activity
285
- for node in list(self.nodes.values()):
286
- if node.group == group:
287
- node.group == instance_group
288
- self.groups[instance_group.id] = instance_group
289
-
290
- def update_nodes(self, node_origin):
291
- updated_edges = 0
292
- node_instance = None
293
- if not isinstance(node_origin, TriccNodeSelectOption):
294
- # do not perpetuate the instance number in the underlying activities
295
- if isinstance(node_origin, TriccNodeActivity):
296
- node_instance = node_origin.make_instance(node_origin.instance if node_origin.instance<100 else 0 , activity=self)
297
- else:
298
- node_instance = node_origin.make_instance(self.instance, activity=self)
299
- self.nodes[node_instance.id] = node_instance
300
- if isinstance(node_instance, (TriccNodeActivityEnd, TriccNodeEnd)):
301
- node_instance.set_name()
302
- # update root
303
- if isinstance(node_origin, TriccNodeActivityStart) and node_origin == node_origin.activity.root:
304
- self.root = node_instance
305
- if issubclass(node_instance.__class__, TriccRhombusMixIn):
306
- old_path = node_origin.path
307
- if old_path is not None:
308
- for n in node_instance.activity.nodes.values():
309
- if n.base_instance.id == old_path.id:
310
- node_instance.path = n
311
- if node_instance.path is None:
312
- logger.error("new path not found")
313
- elif not (len(node_instance.reference)== 1 and issubclass(node_instance.reference[0].__class__, TriccNodeInputModel)):
314
- logger.warning("Rhombus without a path")
315
-
316
- # generate options
317
- elif issubclass(node_instance.__class__, TriccNodeSelect):
318
- for key, option_instance in node_instance.options.items():
319
- updated_edges += self.update_edges(node_origin.options[key], option_instance)
320
- updated_edges += self.update_edges(node_origin, node_instance)
321
- if updated_edges == 0:
322
- node_edge = list(filter(lambda x: (x.source == node_instance.id or x.source == node_instance) , node_instance.activity.edges))
323
- node_edge_origin = list(filter(lambda x: (x.source == node_origin.id or x.source == node_origin) , node_origin.activity.edges))
324
- if len(node_edge) == 0:
325
- logger.error("no edge was updated for node {}::{}::{}::{}".format(node_instance.activity.get_name(),
326
- node_instance.__class__,
327
- node_instance.get_name(),
328
- node_instance.instance))
329
- return node_instance
330
-
331
- def update_edges(self, node_origin, node_instance):
332
- updates = 0
333
-
334
- for edge in self.edges:
335
- if edge.source == node_origin.id or edge.source == node_origin:
336
- edge.source = node_instance.id
337
- updates += 1
338
- if edge.target == node_origin.id or edge.target == node_origin:
339
- edge.target = node_instance.id
340
- updates += 1
341
- return updates
342
-
343
- def get_end_nodes(self):
344
- return list(filter(lambda x: issubclass(x.__class__, (TriccNodeEnd,TriccNodeActivityEnd)), self.nodes.values()))
345
-
346
-
347
- class TriccNodeDisplayModel(TriccNodeBaseModel):
348
- name: str
349
- image: Optional[b64]
350
- hint: Optional[Union[str, Dict[str,str]]]
351
- help: Optional[Union[str, Dict[str,str]]]
352
- group: Optional[Union[TriccGroup, TriccNodeActivity]]
353
- relevance: Optional[Expression]
354
-
355
- def make_instance(self, instance_nb, activity=None):
356
- instance = super().make_instance(instance_nb, activity=activity)
357
- instance.relevance = None
358
- return instance
359
-
360
- # to use the enum value of the TriccNodeType
361
-
362
-
363
- class TriccNodeNote(TriccNodeDisplayModel):
364
- tricc_type: TriccNodeType = TriccNodeType.note
365
-
366
- class TriccNodeInputModel(TriccNodeDisplayModel):
367
- required: Optional[Expression]
368
- constraint_message: Optional[Union[str, Dict[str,str]]]
369
- constraint: Optional[Expression]
370
- save: Optional[str] # contribute to another calculate
371
-
372
-
373
- class TriccNodeDate(TriccNodeInputModel):
374
- tricc_type: TriccNodeType = TriccNodeType.date
375
-
376
-
377
- class TriccNodeMainStart(TriccNodeBaseModel):
378
- tricc_type: TriccNodeType = TriccNodeType.start
379
- form_id: Optional[str]
380
- process: Optional[str]
381
-
382
-
383
- class TriccNodeLinkIn(TriccNodeBaseModel):
384
- tricc_type: TriccNodeType = TriccNodeType.link_in
385
-
386
-
387
- class TriccNodeLinkOut(TriccNodeBaseModel):
388
- tricc_type: TriccNodeType = TriccNodeType.link_out
389
- reference: Optional[Union[TriccNodeLinkIn, triccId]]
390
- # no need to copy
391
-
392
-
393
- class TriccNodeGoTo(TriccNodeBaseModel):
394
- tricc_type: TriccNodeType = TriccNodeType.goto
395
- link: Union[TriccNodeActivity, triccId]
396
-
397
- # no need ot copy
398
- def make_instance(self, instance_nb, activity, **kwargs):
399
- # shallow copy
400
- instance = super().make_instance(instance_nb, activity=activity)
401
- # do not use activity instance for goto
402
- instance.instance = self.instance
403
- return instance
404
-
405
-
406
- class TriccNodeSelectOption(TriccNodeDisplayModel):
407
- tricc_type: TriccNodeType = TriccNodeType.select_option
408
- label: Union[str, Dict[str,str]]
409
- save: Optional[str]
410
- select: TriccNodeInputModel
411
- list_name: str
412
-
413
-
414
- def make_instance(self, instance_nb, activity, select, **kwargs):
415
- # shallow copy
416
- instance = super().make_instance(instance_nb, activity=activity)
417
- instance.select = select
418
- return instance
419
-
420
- def get_name(self):
421
- name = super().get_name()
422
- select_name = self.select.get_name()
423
- return select_name + "::" + name
424
-
425
-
426
- class TriccNodeSelect(TriccNodeInputModel):
427
- filter: Optional[str]
428
- options: Dict[int, TriccNodeSelectOption] = {}
429
- list_name: str
430
-
431
- def make_instance(self, instance_nb, activity, **kwargs):
432
- # shallow copy, no copy of filter and list_name
433
- instance = super().make_instance(instance_nb, activity=activity)
434
- instance.options = {}
435
- for key, option in self.options.items():
436
- instance.options[key] = option.make_instance(instance_nb, activity=activity, select=instance)
437
- return instance
438
-
439
-
440
- class TriccNodeSelectOne(TriccNodeSelect):
441
- tricc_type: TriccNodeType = TriccNodeType.select_one
442
-
443
-
444
- class TriccNodeSelectYesNo(TriccNodeSelectOne):
445
- pass
446
-
447
-
448
- # options: List[TriccNodeSelectOption] = [TriccNodeSelectOption(label='Yes', name='yes'),
449
- # TriccNodeSelectOption(label='No', name='no')]
450
- class TriccNodeSelectNotAvailable(TriccNodeSelectOne):
451
- pass
452
-
453
-
454
- class TriccNodeSelectMultiple(TriccNodeSelect):
455
- tricc_type: TriccNodeType = TriccNodeType.select_multiple
456
-
457
-
458
- class TriccNodeNumber(TriccNodeInputModel):
459
- min: Optional[float]
460
- max: Optional[float]
461
- # no need to copy min max in make isntance
462
-
463
-
464
- class TriccNodeDecimal(TriccNodeNumber):
465
- tricc_type: TriccNodeType = TriccNodeType.decimal
466
-
467
-
468
- class TriccNodeInteger(TriccNodeNumber):
469
- tricc_type: TriccNodeType = TriccNodeType.integer
470
-
471
-
472
- class TriccNodeText(TriccNodeInputModel):
473
- tricc_type: TriccNodeType = TriccNodeType.text
474
-
475
-
476
- class TriccNodeCalculateBase(TriccNodeBaseModel):
477
- input: Dict[TriccOperation, TriccNodeBaseModel] = {}
478
- reference: Optional[Union[List[TriccNodeBaseModel], Expression]]
479
- expression_reference: Optional[str]
480
- version: int = 1
481
- last: bool = True
482
-
483
- # to use the enum value of the TriccNodeType
484
- class Config:
485
- use_enum_values = True # <--
486
-
487
- def make_instance(self, instance_nb, activity, **kwargs):
488
- # shallow copy
489
- instance = super().make_instance(instance_nb, activity=activity)
490
- input = {}
491
- instance.input = input
492
- expression = self.expression.copy() if self.expression is not None else None
493
- instance.expression = expression
494
- version = 1
495
- instance.version = version
496
- return instance
497
-
498
- def __init__(self, **data):
499
- super().__init__(**data)
500
- self.gen_name()
501
-
502
-
503
- class TriccNodeDisplayCalculateBase(TriccNodeCalculateBase):
504
- save: Optional[str] # contribute to another calculate
505
- hint: Optional[str] # for diagnostic display
506
- help: Optional[str] # for diagnostic display
507
- # no need to copy save
508
- def to_fake(self):
509
- data = vars(self)
510
- del data['hint']
511
- del data['help']
512
- del data['save']
513
- fake = TriccNodeFakeCalculateBase(**data)
514
- replace_node(self,fake)
515
- return fake
516
-
517
-
518
- # qualculate that saves quantity, or we may merge integer/decimals
519
- class TriccNodeQuantity(TriccNodeDisplayCalculateBase):
520
- tricc_type: TriccNodeType = TriccNodeType.quantity
521
-
522
-
523
- class TriccNodeCalculate(TriccNodeDisplayCalculateBase):
524
- tricc_type: TriccNodeType = TriccNodeType.calculate
525
-
526
-
527
- class TriccNodeAdd(TriccNodeDisplayCalculateBase):
528
- tricc_type: TriccNodeType = TriccNodeType.add
529
-
530
-
531
- class TriccNodeCount(TriccNodeDisplayCalculateBase):
532
- tricc_type: TriccNodeType = TriccNodeType.count
533
-
534
-
535
- class TriccNodeFakeCalculateBase(TriccNodeCalculateBase):
536
- pass
537
-
538
- class TriccNodeDisplayBridge(TriccNodeDisplayCalculateBase):
539
- tricc_type: TriccNodeType = TriccNodeType.bridge
540
-
541
-
542
- class TriccNodeBridge(TriccNodeFakeCalculateBase):
543
- tricc_type: TriccNodeType = TriccNodeType.bridge
544
-
545
- class TriccRhombusMixIn():
546
-
547
- def make_mixin_instance(self, instance, instance_nb, activity, **kwargs):
548
- # shallow copy
549
- reference = []
550
- instance.path = None
551
- if isinstance(self.reference, str):
552
- reference = self.reference
553
- elif isinstance(self.reference, list):
554
- for ref in self.reference:
555
- if issubclass(ref.__class__, TriccBaseModel):
556
- pass
557
- # get the reference
558
- if self.activity == ref.activity:
559
- for sub_node in activity.nodes.values():
560
- if sub_node.base_instance == ref:
561
- reference.append(sub_node)
562
- else: # ref from outside
563
- # FIXME find the latest version
564
- reference.append(ref)
565
- elif isinstance(ref, str):
566
- logger.debug("passing raw reference {} on node {}".format(ref, self.get_name()))
567
- reference.append(ref)
568
- else:
569
- logger.error("unexpected reference in node node {}".format(ref, self.get_name()))
570
- exit()
571
- instance.reference = reference
572
- instance.name = get_rand_name(8)
573
- return instance
574
-
575
- class TriccNodeRhombus(TriccNodeCalculateBase,TriccRhombusMixIn):
576
- tricc_type: TriccNodeType = TriccNodeType.rhombus
577
- path: Optional[TriccNodeBaseModel] = None
578
- reference: Union[List[TriccNodeBaseModel], Expression]
579
-
580
- def make_instance(self, instance_nb, activity, **kwargs):
581
- instance = super(TriccNodeRhombus, self).make_instance(instance_nb, activity, **kwargs)
582
- instance = self.make_mixin_instance(instance, instance_nb, activity, **kwargs)
583
- return instance
584
-
585
-
586
- def __init__(self, **data):
587
- super().__init__(**data)
588
- # rename rhombus
589
- self.name = get_rand_name(8)
590
-
591
-
592
- def get_rand_name(k):
593
- return "r_" + ''.join(random.choices(string.ascii_lowercase, k=k))
594
-
595
-
596
- class TriccNodeExclusive(TriccNodeFakeCalculateBase):
597
- tricc_type: TriccNodeType = TriccNodeType.exclusive
598
-
599
- def get_node_from_id(activity, node, edge_only):
600
- node_id = getattr(node,'id',node)
601
- if not isinstance(node_id, str):
602
- logger.error("can set prev_next only with string or node")
603
- exit()
604
- if issubclass(node.__class__, TriccBaseModel):
605
- return node_id, node
606
- elif node_id in activity.nodes:
607
- node = activity.nodes[node_id]
608
- elif not edge_only:
609
- logger.error(f"cannot find {node_id} in {activiy.get_name()}")
610
- exit()
611
- return node_id, node
612
-
613
- # Set the source next node to target and clean next nodes of replace node
614
- def set_prev_next_node(source_node, target_node, replaced_node=None, edge_only = False, activity=None):
615
- activity = activity or source_node.activity
616
- source_id, source_node = get_node_from_id(activity, source_node, edge_only)
617
- target_id, target_node = get_node_from_id(activity, target_node, edge_only)
618
- # if it is end node, attached it to the activity/page
619
- if not edge_only:
620
- set_prev_node(source_node, target_node, replaced_node, edge_only)
621
- set_next_node(source_node, target_node, replaced_node,edge_only)
622
-
623
- if not any([(e.source == source_id) and ( e.target == target_id) for e in activity.edges]):
624
- activity.edges.append(TriccEdge(id = generate_id(), source = source_id, target = target_id))
625
-
626
-
627
-
628
-
629
- def set_next_node(source_node, target_node, replaced_node=None, edge_only = False, activity=None):
630
- activity = activity or source_node.activity
631
- if not edge_only:
632
- if replaced_node is not None and hasattr(source_node, 'path') and replaced_node == source_node.path:
633
- source_node.path = target_node
634
- if replaced_node is not None and hasattr(source_node, 'next_nodes') and replaced_node in source_node.next_nodes:
635
- source_node.next_nodes.remove(replaced_node)
636
- if replaced_node is not None and hasattr(target_node, 'next_nodes') and replaced_node in target_node.next_nodes:
637
- target_node.next_nodes.remove(replaced_node)
638
- if target_node not in source_node.next_nodes:
639
- source_node.next_nodes.append(target_node)
640
- # if rhombus in next_node of prev node and next node as ref
641
- if replaced_node is not None:
642
- rhombus_list = list(filter(lambda x: issubclass(x.__class__, TriccRhombusMixIn), source_node.next_nodes))
643
- for rhm in rhombus_list:
644
- if isinstance(rhm.reference, list):
645
- if replaced_node in rhm.reference:
646
- rhm.reference.remove(replaced_node)
647
- rhm.reference.append(target_node)
648
- next_edges = [ e for e in activity.edges if replaced_node and (e.target == replaced_node.id or e.target == replaced_node)]
649
- if len(next_edges)==0:
650
- for e in next_edges:
651
- e.target = target_node.id
652
-
653
- # Set the target_node prev node to source and clean prev nodes of replace_node
654
- def set_prev_node(source_node, target_node, replaced_node=None, edge_only = False, activity=None):
655
- activity = activity or source_node.activity
656
- # update the prev node of the target not if not an end node
657
- # update directly the prev node of the target
658
- if replaced_node is not None and hasattr(target_node, 'path') and replaced_node == target_node.path:
659
- target_node.path = source_node
660
- if replaced_node is not None and hasattr(target_node, 'prev_nodes') and replaced_node in target_node.prev_nodes:
661
- target_node.prev_nodes.remove(replaced_node)
662
- if replaced_node is not None and hasattr(source_node, 'prev_nodes') and replaced_node in source_node.prev_nodes:
663
- source_node.prev_nodes.remove(replaced_node)
664
- if source_node not in target_node.prev_nodes:
665
- target_node.prev_nodes.append(source_node)
666
-
667
- prev_edges = [ e for e in activity.edges if replaced_node and (e.source == replaced_node.id or e.source == replaced_node)]
668
- if len(prev_edges)==0:
669
- for e in prev_edges:
670
- e.source = source_node.id
671
-
672
- def replace_node(old, new, page = None):
673
- if page is None:
674
- page = old.activity
675
- logger.debug("replacing node {} with node {} from page {}".format(old.get_name(), new.get_name(), page.get_name()))
676
- # list_node used to avoid updating a list in the loop
677
- list_nodes = []
678
- for prev_node in old.prev_nodes:
679
- list_nodes.append(prev_node)
680
- for prev_node in list_nodes:
681
- set_prev_next_node(prev_node, new, old)
682
- old.prev_nodes = []
683
- list_nodes = []
684
- for next_node in old.next_nodes:
685
- list_nodes.append(next_node)
686
- for next_node in list_nodes:
687
- set_prev_next_node(new, next_node, old)
688
- old.next_nodes = []
689
- if old in page.nodes:
690
- del page.nodes[old.id]
691
- page.nodes[new.id] = new
692
-
693
- for edge in page.edges:
694
- if edge.source == old.id:
695
- edge.source = new.id
696
- if edge.target == old.id:
697
- edge.target = new.id
698
-
699
-
700
- def reorder_node_list(list_node, group):
701
- if len(list_node)>1:
702
- list_out = []
703
- list_out_group = []
704
- list_out_other = []
705
-
706
-
707
- for l_node in list_node:
708
- group_id = l_node.group.id if hasattr(l_node, 'group') and l_node.group is not None else None
709
- if group is not None and group.id == group_id:
710
- list_out.append(l_node)
711
- elif hasattr(group, 'group') and group.group is not None and group.group.id == group_id:
712
- list_out_group.append(l_node)
713
- else:
714
- list_out_other.append(l_node)
715
-
716
- list_node = []
717
- if len(list_out)>0:
718
- list_node.extend(list_out)
719
- if len(list_out_group)>0:
720
- list_node.extend(list_out_group)
721
- if len(list_out_other)>0:
722
- list_node.extend(list_out_other)
723
-
724
- logger.debug("reorder list init len: {}, group : {} group.group: {} other: {}".format(len(list_node), len(list_out), len(list_out_group), len(list_out_other)))
725
-
726
-
727
-
728
-
729
- # walkthough all node in an iterative way, the same node might be parsed 2 times
730
- # therefore to avoid double processing the nodes variable saves the node already processed
731
- # there 2 strategies : process it the first time or the last time (wait that all the previuous node are processed)
732
-
733
- def walktrhough_tricc_node_processed_stached(node, callback, processed_nodes, stashed_nodes, path_len, recursive=True, warn = False,
734
- **kwargs):
735
- # logger.debug("walkthrough::{}::{}".format(callback.__name__, node.get_name()))
736
- if hasattr(node, 'prev_nodes') and len(node.prev_nodes) > 0:
737
- path_len = max(path_len, *[n.path_len + 1 for n in node.prev_nodes], len(processed_nodes)+1)
738
- node.path_len = max(node.path_len, path_len)
739
- if (callback(node, processed_nodes=processed_nodes, stashed_nodes=stashed_nodes, warn = warn,**kwargs)):
740
- # node processing succeed
741
- if node not in processed_nodes:
742
- processed_nodes.append(node)
743
- logger.debug("{}::{}: processed ({})".format(callback.__name__, node.get_name(), len(processed_nodes)))
744
- if node in stashed_nodes:
745
- stashed_nodes.remove(node)
746
- # logger.debug("{}::{}: unstashed ({})".format(callback.__name__, node.get_name(), len(stashed_nodes)))
747
- # put the stached node from that group first
748
- # if has next, walkthrough them (support options)
749
- # if len(stashed_nodes)>1:
750
- if not recursive:
751
- reorder_node_list(stashed_nodes, node.group)
752
- # logger.debug("{}::{}: reorder stashed ({})".format(callback.__name__, node.get_name(), len(stashed_nodes)))
753
- if isinstance(node, TriccNodeActivity):
754
- if node.root is not None:
755
- node.root.path_len = max(path_len, node.root.path_len)
756
- if recursive:
757
- walktrhough_tricc_node_processed_stached(node.root, callback, processed_nodes, stashed_nodes, path_len,
758
- recursive, warn = warn,**kwargs)
759
- for gp in node.groups:
760
- walktrhough_tricc_node_processed_stached(gp, callback, processed_nodes, stashed_nodes, path_len,
761
- recursive, warn = warn,**kwargs)
762
- if node.calculates:
763
- for c in node.calculates:
764
- walktrhough_tricc_node_processed_stached(c, callback, processed_nodes, stashed_nodes, path_len,
765
- recursive, warn = warn,**kwargs)
766
- elif node.root not in stashed_nodes:
767
- #stashed_nodes.insert(0,node.root)
768
- stashed_nodes.append(node.root)
769
- if node.calculates:
770
- stashed_nodes += node.calculates
771
- for gp in node.groups:
772
- stashed_nodes.append(gp)
773
- # stashed_nodes.insert(0,gp)
774
- return
775
- elif isinstance(node, TriccNodeActivityEnd):
776
- for next_node in node.activity.next_nodes:
777
- if next_node not in stashed_nodes:
778
- #stashed_nodes.insert(0,next_node)
779
- stashed_nodes.append(next_node)
780
- elif issubclass(node.__class__, TriccNodeSelect):
781
- for option in node.options.values():
782
- option.path_len = max(path_len, option.path_len)
783
- callback(option, processed_nodes=processed_nodes, stashed_nodes=stashed_nodes, **kwargs)
784
- if option not in processed_nodes:
785
- processed_nodes.append(option)
786
- logger.debug(
787
- "{}::{}: processed ({})".format(callback.__name__, option.get_name(), len(processed_nodes)))
788
- walkthrough_tricc_option(node, callback, processed_nodes, stashed_nodes, path_len + 1, recursive,
789
- warn = warn, **kwargs)
790
- if hasattr(node, 'next_nodes') and len(node.next_nodes) > 0:
791
- walkthrough_tricc_next_nodes(node, callback, processed_nodes, stashed_nodes, path_len + 1, recursive,
792
- warn = warn,**kwargs)
793
- else:
794
- if node not in processed_nodes and node not in stashed_nodes:
795
- if node not in stashed_nodes:
796
- stashed_nodes.insert(0,node)
797
- logger.debug("{}::{}: stashed({})".format(callback.__name__, node.get_name(), len(stashed_nodes)))
798
-
799
-
800
- def walkthrough_tricc_next_nodes(node, callback, processed_nodes, stashed_nodes, path_len, recursive, warn = False, **kwargs):
801
- if not recursive:
802
- for next_node in node.next_nodes:
803
- if next_node not in stashed_nodes:
804
- stashed_nodes.append(next_node)
805
- else:
806
- list_next = []
807
- while not all(elem in list_next for elem in node.next_nodes):
808
- for next_node in node.next_nodes:
809
- if next_node not in list_next:
810
- list_next.append(next_node)
811
- if not isinstance(node, (TriccNodeActivityEnd, TriccNodeEnd)):
812
- walktrhough_tricc_node_processed_stached(next_node, callback, processed_nodes, stashed_nodes,
813
- path_len + 1,recursive, warn = warn, **kwargs)
814
- else:
815
- logger.error(
816
- "{}::end node of {} has a next node".format(callback.__name__.node.activity.get_name()))
817
- exit()
818
-
819
-
820
- def walkthrough_tricc_option(node, callback, processed_nodes, stashed_nodes, path_len, recursive, warn = False, **kwargs):
821
- if not recursive:
822
- for option in node.options.values():
823
- if hasattr(option, 'next_nodes') and len(option.next_nodes) > 0:
824
- for next_node in option.next_nodes:
825
- if next_node not in stashed_nodes:
826
- stashed_nodes.append(next_node)
827
- #stashed_nodes.insert(0,next_node)
828
- else:
829
- list_option = []
830
- while not all(elem in list_option for elem in list(node.options.values())):
831
- for option in node.options.values():
832
- if option not in list_option:
833
- list_option.append(option)
834
- # then walk the options
835
- if hasattr(option, 'next_nodes') and len(option.next_nodes) > 0:
836
- list_next = []
837
- while not all(elem in list_next for elem in option.next_nodes):
838
- for next_node in option.next_nodes:
839
- if next_node not in list_next:
840
- list_next.append(next_node)
841
- walktrhough_tricc_node_processed_stached(next_node, callback, processed_nodes,
842
- stashed_nodes, path_len + 1, recursive,
843
- warn = warn,**kwargs)
844
-
845
-
846
- def get_data_for_log(node):
847
- return "{}:{}|{} {}:{}".format(
848
- node.group.get_name() if node.group is not None else node.activity.get_name(),
849
- node.group.instance if node.group is not None else node.activityinstance ,
850
- node.__class__,
851
- node.get_name(),
852
- node.instance)
853
-
854
- def stashed_node_func(node, callback, recusive=False, **kwargs):
855
- processed_nodes = kwargs.get('processed_nodes', [])
856
- stashed_nodes = kwargs.get('stashed_nodes', [])
857
- path_len = 0
858
- walktrhough_tricc_node_processed_stached(node, callback, processed_nodes, stashed_nodes, path_len, recusive,
859
- **kwargs)
860
- # callback( node, **kwargs)
861
- ## MANAGE STASHED NODES
862
- prev_stashed_nodes = stashed_nodes.copy()
863
- loop_count = 0
864
- len_prev_processed_nodes = 0
865
- while len(stashed_nodes) > 0:
866
- loop_count = check_stashed_loop(stashed_nodes, prev_stashed_nodes, processed_nodes, len_prev_processed_nodes,
867
- loop_count)
868
- prev_stashed_nodes = stashed_nodes.copy()
869
- len_prev_processed_nodes = len(processed_nodes)
870
- if len(stashed_nodes) > 0:
871
- s_node = stashed_nodes.pop()
872
- # remove duplicates
873
- if s_node in stashed_nodes:
874
- stashed_nodes.remove(s_node)
875
- logger.debug("{}:: {}: unstashed for processing ({})".format(callback.__name__, s_node.__class__,
876
- get_data_for_log(s_node),
877
- len(stashed_nodes)))
878
- warn = loop_count == (10 * len(stashed_nodes )-1)
879
- walktrhough_tricc_node_processed_stached(s_node, callback, processed_nodes, stashed_nodes, path_len,
880
- recusive, warn= warn, **kwargs)
881
-
882
-
883
- # check if the all the prev nodes are processed
884
- def is_ready_to_process(in_node, processed_nodes, strict=True, local = False):
885
- if isinstance(in_node, TriccNodeSelectOption):
886
- node = in_node.select
887
- elif isinstance(in_node, TriccNodeActivityStart):
888
- if local:
889
- # an activitiy start iss always processable locally
890
- return True
891
- node = in_node.activity
892
- else:
893
- node = in_node
894
- if hasattr(node, 'prev_nodes'):
895
- # ensure the previous node of the select are processed, not the option prev nodes
896
- for prev_node in node.prev_nodes:
897
- if isinstance(prev_node, TriccNodeActivity):
898
- if not local:
899
- # other activity dont affect local evaluation
900
- activity_end_nodes = prev_node.get_end_nodes()
901
- if len(activity_end_nodes) == 0:
902
-
903
- logger.error("is_ready_to_process:failed: endless activity {0} before {0}".format(prev_node.get_name(),
904
- node.get_name()))
905
- return False
906
- for end_node in activity_end_nodes:
907
- if end_node not in processed_nodes:
908
- logger.debug("is_ready_to_process:failed:via_end: {} - {} > {} {}:{}".format(
909
- get_data_for_log(prev_node),
910
- end_node.get_name(),
911
- node.__class__, node.get_name(), node.instance))
912
- return False
913
- elif prev_node not in processed_nodes and (not local or prev_node.activity == node.activity):
914
- if isinstance(prev_node, TriccNodeExclusive):
915
- logger.debug("is_ready_to_process:failed:via_excl: {} - {} > {} {}:{}".format(
916
- get_data_for_log(prev_node.prev_nodes[0]),
917
- prev_node.get_name(),
918
- node.__class__, node.get_name(), node.instance))
919
-
920
- else:
921
- logger.debug("is_ready_to_process:failed: {} -> {} {}:{}".format(
922
- get_data_for_log(prev_node),
923
- node.__class__, node.get_name(), node.instance))
924
-
925
- logger.debug("prev node node {}:{} for node {} not in processed".format(prev_node.__class__,
926
- prev_node.get_name(),
927
- node.get_name()))
928
- return False
929
- if strict:
930
- return is_rhombus_ready_to_process(node, processed_nodes, local)
931
- else:
932
- return True
933
- else:
934
- return True
935
-
936
-
937
- def print_trace(node, prev_node, processed_nodes, stashed_nodes, history = []):
938
-
939
- if node != prev_node:
940
- if node in processed_nodes:
941
- logger.warning("print trace :: node {} was the last not processed ({})".format(
942
- get_data_for_log(prev_node), node.id, ">".join(history)))
943
- processed_nodes.append(prev_node)
944
- return False
945
- elif node in history:
946
- logger.error("print trace :: CYCLE node {} found in history ({})".format(
947
- get_data_for_log(prev_node), ">".join(history)))
948
- exit()
949
- elif node in stashed_nodes:
950
- # logger.debug("print trace :: node {}::{} in stashed".format(node.__class__,node.get_name()))
951
- return False
952
- # else:
953
- # logger.debug("print trace :: node {} not processed/stashed".format(node.get_name()))
954
- return True
955
-
956
-
957
- def reverse_walkthrough(in_node, next_node, callback, processed_nodes, stashed_nodes, history = []):
958
- # transform dead-end nodes
959
- if next_node == in_node and next_node not in stashed_nodes:
960
- # workaround fir loop
961
- return False
962
-
963
-
964
- if isinstance(in_node, TriccNodeSelectOption):
965
- node = in_node.select
966
- elif isinstance(in_node, TriccNodeActivityStart):
967
- node = in_node.activity
968
- else:
969
- node = in_node
970
- if callback(node, next_node, processed_nodes, stashed_nodes):
971
- history.append(node)
972
- if isinstance(in_node, TriccNodeActivity):
973
- prev_nodes = in_node.get_end_nodes()
974
- for prev in prev_nodes:
975
- reverse_walkthrough(prev, next_node, callback, processed_nodes, stashed_nodes, history)
976
- if hasattr(node, 'prev_nodes'):
977
- if node.prev_nodes:
978
- for prev in node.prev_nodes:
979
- reverse_walkthrough(prev, node, callback, processed_nodes, stashed_nodes, history)
980
- elif node in node.activity.calculates:
981
- reverse_walkthrough(prev, node.activity.root, callback, processed_nodes, stashed_nodes, history)
982
-
983
- if issubclass(node.__class__, TriccRhombusMixIn):
984
- if isinstance(node.reference, list):
985
- for ref in node.reference:
986
- reverse_walkthrough(ref, node, callback, processed_nodes, stashed_nodes, history)
987
-
988
-
989
- def is_rhombus_ready_to_process(node, processed_nodes, local = False):
990
- if issubclass(node.__class__, TriccRhombusMixIn):
991
- if isinstance(node.reference, str):
992
- return False # calculate not yet processed
993
- elif isinstance(node.reference, list):
994
- for ref in node.reference:
995
- if issubclass(ref.__class__, TriccNodeBaseModel) and ref not in processed_nodes and (not local or ref.activity == node.activity):
996
- return False
997
- elif issubclass(ref.__class__, str):
998
- logger.debug("Node {1} as still a reference to string")
999
- return True
1000
-
1001
-
1002
- def get_prev_node_by_name(processed_nodes, name, node):
1003
- filtered = list(filter(lambda p_node: hasattr(p_node,'name') and p_node.name == name and p_node.instance == node.instance and p_node.path_len <= node.path_len, processed_nodes))
1004
- if len(filtered) == 0:
1005
- filtered = list(filter(lambda p_node: hasattr(p_node, 'name') and p_node.name == name, processed_nodes))
1006
- if len(filtered) > 0:
1007
- return sorted(filtered, key=lambda x: x.path_len, reverse=False)[0]
1008
-
1009
- MIN_LOOP_COUNT = 10
1010
-
1011
- def check_stashed_loop(stashed_nodes, prev_stashed_nodes, processed_nodes, len_prev_processed_nodes, loop_count):
1012
- loop_out = {}
1013
-
1014
- if len(stashed_nodes) == len(prev_stashed_nodes):
1015
- # to avoid checking the details
1016
- if loop_count<=0:
1017
- if loop_count < -MIN_LOOP_COUNT:
1018
- loop_count = MIN_LOOP_COUNT+1
1019
- else:
1020
- loop_count -= 1
1021
- if loop_count>MIN_LOOP_COUNT:
1022
- # copy to sort
1023
- cur_stashed_nodes = sorted(stashed_nodes, key=lambda x: x.id, reverse=True)
1024
-
1025
- prev_stashed_nodes = sorted(prev_stashed_nodes, key=lambda x: x.id, reverse=True)
1026
-
1027
- if cur_stashed_nodes == prev_stashed_nodes and len(processed_nodes) == len_prev_processed_nodes:
1028
- loop_count += 1
1029
- if loop_count > max(MIN_LOOP_COUNT, 10 * len(prev_stashed_nodes) + 1):
1030
- logger.error("Stashed node list was unchanged: loop likely or a cyclic redundancy")
1031
- for es_node in cur_stashed_nodes:
1032
- logger.error("Stashed node {}:{}|{} {}:{}".format(
1033
- es_node.group.get_name() if es_node.group is not None else es_node.activity.get_name() ,
1034
- es_node.group.instance if es_node.group is not None else es_node.activityinstance ,
1035
- es_node.__class__,
1036
- es_node.get_name(), es_node.instance))
1037
- #reverse_walkthrough(es_node, es_node, print_trace, processed_nodes, stashed_nodes)
1038
- if len(stashed_nodes) == len(prev_stashed_nodes):
1039
- exit()
1040
- #else:
1041
- # loop_count += 1
1042
- else:
1043
- loop_count = 0
1044
- return loop_count
1045
-
1046
- class TriccNodeWait(TriccNodeFakeCalculateBase, TriccRhombusMixIn):
1047
- tricc_type: TriccNodeType = TriccNodeType.wait
1048
- path: Optional[TriccNodeBaseModel] = None
1049
- reference: Union[List[TriccNodeBaseModel], Expression]
1050
-
1051
- def make_instance(self, instance_nb, activity, **kwargs):
1052
- instance = super(TriccNodeWait, self).make_instance(instance_nb, activity, **kwargs)
1053
- instance = self.make_mixin_instance(instance, instance_nb, activity, **kwargs)
1054
- return instance
1055
-
1056
-
1057
- class TriccNodeActivityEnd(TriccNodeFakeCalculateBase):
1058
- tricc_type: TriccNodeType = TriccNodeType.activity_end
1059
-
1060
- def __init__(self, **data):
1061
- super().__init__(**data)
1062
- # FOR END
1063
- self.set_name()
1064
-
1065
- def set_name(self):
1066
- self.name = ACTIVITY_END_NODE_FORMAT.format(self.activity.id)
1067
-
1068
-
1069
- class TriccNodeEnd(TriccNodeCalculate):
1070
- tricc_type: TriccNodeType = TriccNodeType.end
1071
-
1072
- def __init__(self, **data):
1073
- super().__init__(**data)
1074
- # FOR END
1075
- self.set_name()
1076
-
1077
- def set_name(self):
1078
- self.name = END_NODE_FORMAT.format(self.activity.id)
1079
-
1080
-
1081
- class TriccNodeActivityStart(TriccNodeFakeCalculateBase):
1082
- tricc_type: TriccNodeType = TriccNodeType.activity_start
1083
-
1084
-
1085
- def get_node_from_list(in_nodes, node_id):
1086
- nodes = list(filter(lambda x: x.id == node_id, in_nodes))
1087
- if len(nodes) > 0:
1088
- return nodes[0]
1089
-
1090
-
1091
- # update FF
1092
- TriccEdge.update_forward_refs()
1093
- TriccNodeBridge.update_forward_refs()