tricc-oo 1.5.22__py3-none-any.whl → 1.5.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tests/build.py +13 -23
- tests/test_cql.py +37 -108
- tests/to_ocl.py +15 -17
- tricc_oo/__init__.py +0 -6
- tricc_oo/converters/codesystem_to_ocl.py +51 -40
- tricc_oo/converters/cql/cqlLexer.py +1 -0
- tricc_oo/converters/cql/cqlListener.py +1 -0
- tricc_oo/converters/cql/cqlParser.py +1 -0
- tricc_oo/converters/cql/cqlVisitor.py +1 -0
- tricc_oo/converters/cql_to_operation.py +125 -123
- tricc_oo/converters/datadictionnary.py +39 -53
- tricc_oo/converters/drawio_type_map.py +143 -61
- tricc_oo/converters/tricc_to_xls_form.py +14 -24
- tricc_oo/converters/utils.py +3 -3
- tricc_oo/converters/xml_to_tricc.py +286 -231
- tricc_oo/models/__init__.py +2 -1
- tricc_oo/models/base.py +300 -308
- tricc_oo/models/calculate.py +63 -49
- tricc_oo/models/lang.py +26 -27
- tricc_oo/models/ocl.py +146 -161
- tricc_oo/models/ordered_set.py +15 -19
- tricc_oo/models/tricc.py +144 -88
- tricc_oo/parsers/xml.py +15 -30
- tricc_oo/serializers/planuml.py +4 -6
- tricc_oo/serializers/xls_form.py +81 -135
- tricc_oo/strategies/input/base_input_strategy.py +28 -32
- tricc_oo/strategies/input/drawio.py +57 -69
- tricc_oo/strategies/output/base_output_strategy.py +108 -67
- tricc_oo/strategies/output/spice.py +106 -127
- tricc_oo/strategies/output/xls_form.py +275 -200
- tricc_oo/strategies/output/xlsform_cdss.py +623 -142
- tricc_oo/strategies/output/xlsform_cht.py +106 -114
- tricc_oo/strategies/output/xlsform_cht_hf.py +13 -24
- tricc_oo/visitors/tricc.py +1191 -1021
- tricc_oo/visitors/utils.py +16 -16
- tricc_oo/visitors/xform_pd.py +91 -89
- {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.23.dist-info}/METADATA +3 -1
- tricc_oo-1.5.23.dist-info/RECORD +47 -0
- tricc_oo-1.5.23.dist-info/licenses/LICENSE +373 -0
- tricc_oo-1.5.22.dist-info/RECORD +0 -46
- {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.23.dist-info}/WHEEL +0 -0
- {tricc_oo-1.5.22.dist-info → tricc_oo-1.5.23.dist-info}/top_level.txt +0 -0
tricc_oo/models/base.py
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
import
|
|
5
|
-
import string
|
|
6
|
-
from enum import Enum, auto
|
|
7
|
-
from typing import Dict, ForwardRef, List, Optional, Union, Set, Annotated
|
|
4
|
+
from typing import Annotated, Dict, ForwardRef, List, Optional, Union
|
|
8
5
|
|
|
9
6
|
from pydantic import BaseModel, StringConstraints
|
|
10
7
|
from strenum import StrEnum
|
|
@@ -14,74 +11,57 @@ from tricc_oo.models.ordered_set import OrderedSet
|
|
|
14
11
|
|
|
15
12
|
logger = logging.getLogger("default")
|
|
16
13
|
|
|
17
|
-
Expression = Annotated[
|
|
18
|
-
str,
|
|
19
|
-
StringConstraints(pattern=r'^[^\\/\:]+$')
|
|
20
|
-
]
|
|
21
|
-
|
|
22
|
-
triccId = Annotated[
|
|
23
|
-
str,
|
|
24
|
-
StringConstraints(pattern=r'^[^\\/\: ]+$')
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
triccName = Annotated[
|
|
28
|
-
str,
|
|
29
|
-
StringConstraints(pattern=r'^[^\s]+( [^\s]+)*$')
|
|
30
|
-
]
|
|
31
|
-
|
|
32
|
-
b64 = Annotated[
|
|
33
|
-
str,
|
|
34
|
-
StringConstraints(pattern=r'^[^-A-Za-z0-9+/=]|=[^=]|={3,}$')
|
|
35
|
-
]
|
|
14
|
+
Expression = Annotated[str, StringConstraints(pattern=r"^[^\\/\:]+$")]
|
|
36
15
|
|
|
16
|
+
triccId = Annotated[str, StringConstraints(pattern=r"^[^\\/\: ]+$")]
|
|
37
17
|
|
|
38
|
-
|
|
39
|
-
# data:page/id,UkO_xCL5ZjyshJO9Bexg
|
|
18
|
+
triccName = Annotated[str, StringConstraints(pattern=r"^[^\s]+( [^\s]+)*$")]
|
|
40
19
|
|
|
20
|
+
b64 = Annotated[str, StringConstraints(pattern=r"^[^-A-Za-z0-9+/=]|=[^=]|={3,}$")]
|
|
41
21
|
|
|
42
|
-
ACTIVITY_END_NODE_FORMAT = "aend_{}"
|
|
43
22
|
END_NODE_FORMAT = "end_{}"
|
|
44
23
|
|
|
45
24
|
|
|
46
25
|
class TriccNodeType(StrEnum):
|
|
47
|
-
#replace with auto ?
|
|
48
|
-
note =
|
|
49
|
-
calculate =
|
|
50
|
-
output =
|
|
51
|
-
select_multiple =
|
|
52
|
-
select_one =
|
|
53
|
-
select_yesno =
|
|
54
|
-
select_option =
|
|
55
|
-
decimal =
|
|
56
|
-
integer =
|
|
57
|
-
text =
|
|
58
|
-
date =
|
|
59
|
-
rhombus =
|
|
60
|
-
goto =
|
|
61
|
-
start =
|
|
62
|
-
activity_start =
|
|
63
|
-
link_in =
|
|
64
|
-
link_out =
|
|
65
|
-
count =
|
|
66
|
-
add =
|
|
67
|
-
container_hint_media =
|
|
68
|
-
activity =
|
|
69
|
-
help =
|
|
70
|
-
hint =
|
|
71
|
-
exclusive =
|
|
72
|
-
end =
|
|
73
|
-
activity_end =
|
|
74
|
-
edge =
|
|
75
|
-
page =
|
|
76
|
-
not_available =
|
|
77
|
-
quantity =
|
|
78
|
-
bridge =
|
|
79
|
-
wait =
|
|
80
|
-
operation =
|
|
81
|
-
context =
|
|
82
|
-
diagnosis =
|
|
83
|
-
proposed_diagnosis =
|
|
84
|
-
input =
|
|
26
|
+
# replace with auto ?
|
|
27
|
+
note = "note"
|
|
28
|
+
calculate = ("calculate",)
|
|
29
|
+
output = ("output",)
|
|
30
|
+
select_multiple = "select_multiple"
|
|
31
|
+
select_one = "select_one"
|
|
32
|
+
select_yesno = "select_one yesno"
|
|
33
|
+
select_option = "select_option"
|
|
34
|
+
decimal = "decimal"
|
|
35
|
+
integer = "integer"
|
|
36
|
+
text = "text"
|
|
37
|
+
date = "date"
|
|
38
|
+
rhombus = "rhombus" # fetch data
|
|
39
|
+
goto = "goto" #: start the linked activity within the target activity
|
|
40
|
+
start = "start" #: main start of the algo
|
|
41
|
+
activity_start = "activity_start" #: start of an activity (link in)
|
|
42
|
+
link_in = "link_in"
|
|
43
|
+
link_out = "link_out"
|
|
44
|
+
count = "count" #: count the number of valid input
|
|
45
|
+
add = "add" # add counts
|
|
46
|
+
container_hint_media = "container_hint_media" # DEPRECATED
|
|
47
|
+
activity = "activity"
|
|
48
|
+
help = "help-message"
|
|
49
|
+
hint = "hint-message"
|
|
50
|
+
exclusive = "not"
|
|
51
|
+
end = "end"
|
|
52
|
+
activity_end = "activity_end"
|
|
53
|
+
edge = "edge"
|
|
54
|
+
page = "container_page"
|
|
55
|
+
not_available = "not_available"
|
|
56
|
+
quantity = "quantity"
|
|
57
|
+
bridge = "bridge"
|
|
58
|
+
wait = "wait"
|
|
59
|
+
operation = "operation"
|
|
60
|
+
context = "context"
|
|
61
|
+
diagnosis = "diagnosis"
|
|
62
|
+
proposed_diagnosis = "proposed_diagnosis"
|
|
63
|
+
input = "input"
|
|
64
|
+
remote_reference = "remote_reference"
|
|
85
65
|
|
|
86
66
|
def __iter__(self):
|
|
87
67
|
return iter(self.__members__.values())
|
|
@@ -90,7 +70,6 @@ class TriccNodeType(StrEnum):
|
|
|
90
70
|
return next(iter(self))
|
|
91
71
|
|
|
92
72
|
|
|
93
|
-
|
|
94
73
|
media_nodes = [
|
|
95
74
|
TriccNodeType.note,
|
|
96
75
|
TriccNodeType.select_multiple,
|
|
@@ -110,42 +89,42 @@ class TriccBaseModel(BaseModel):
|
|
|
110
89
|
base_instance: Optional[TriccBaseModel] = None
|
|
111
90
|
last: bool = None
|
|
112
91
|
version: int = 1
|
|
92
|
+
|
|
113
93
|
def get_datatype(self):
|
|
114
94
|
return self.datatype or self.tricc_type
|
|
115
|
-
|
|
95
|
+
|
|
116
96
|
def get_next_instance(self):
|
|
117
|
-
if getattr(self,
|
|
97
|
+
if getattr(self, "instances", None):
|
|
118
98
|
return max(100, *[n.instance for n in self.instances.values()]) + 1
|
|
119
|
-
if getattr(self,
|
|
99
|
+
if getattr(self, "base_instance", None) and getattr(self.base_instance, "instances", None):
|
|
120
100
|
return max(100, *[n.instance for n in self.base_instance.instances.values()]) + 1
|
|
121
|
-
return max(100,self.instance) + 1
|
|
122
|
-
|
|
101
|
+
return max(100, self.instance) + 1
|
|
102
|
+
|
|
123
103
|
def to_dict(self):
|
|
124
|
-
return {key: value for key, value in vars(self).items() if not key.startswith(
|
|
104
|
+
return {key: value for key, value in vars(self).items() if not key.startswith("_")}
|
|
125
105
|
|
|
126
106
|
def make_instance(self, nb_instance=None, **kwargs):
|
|
127
|
-
if nb_instance
|
|
107
|
+
if nb_instance is None:
|
|
128
108
|
nb_instance = self.get_next_instance()
|
|
129
109
|
instance = self.copy()
|
|
130
110
|
attr_dict = self.to_dict()
|
|
131
111
|
for attr, value in attr_dict.items():
|
|
132
|
-
if not attr.startswith(
|
|
112
|
+
if not attr.startswith("_") and value is not None:
|
|
133
113
|
try:
|
|
134
|
-
if hasattr(value,
|
|
114
|
+
if hasattr(value, "copy"):
|
|
135
115
|
setattr(instance, attr, value.copy())
|
|
136
116
|
else:
|
|
137
117
|
setattr(instance, attr, value)
|
|
138
118
|
except Exception as e:
|
|
139
119
|
logger.warning(f"Warning: Could not copy attribute {attr}: {e}")
|
|
140
|
-
|
|
120
|
+
|
|
141
121
|
# change the id to avoid collision of name
|
|
142
122
|
instance.id = generate_id(f"{self.id}{nb_instance}")
|
|
143
123
|
instance.instance = int(nb_instance)
|
|
144
124
|
instance.base_instance = self
|
|
145
|
-
if hasattr(self,
|
|
125
|
+
if hasattr(self, "instances"):
|
|
146
126
|
self.instances[nb_instance] = instance
|
|
147
|
-
|
|
148
|
-
|
|
127
|
+
|
|
149
128
|
# assign the defualt group
|
|
150
129
|
# if activity is not None and self.group == activity.base_instance:
|
|
151
130
|
# instance.group = instance
|
|
@@ -166,16 +145,16 @@ class TriccBaseModel(BaseModel):
|
|
|
166
145
|
|
|
167
146
|
def get_name(self):
|
|
168
147
|
return self.id
|
|
169
|
-
|
|
148
|
+
|
|
170
149
|
def __str__(self):
|
|
171
150
|
return self.get_name()
|
|
172
|
-
|
|
151
|
+
|
|
173
152
|
def __repr__(self):
|
|
174
153
|
return f"{self.tricc_type}:{self.get_name()}({self.id})"
|
|
175
|
-
|
|
154
|
+
|
|
176
155
|
def __init__(self, **data):
|
|
177
|
-
if
|
|
178
|
-
data[
|
|
156
|
+
if "id" not in data:
|
|
157
|
+
data["id"] = generate_id(str(data))
|
|
179
158
|
super().__init__(**data)
|
|
180
159
|
|
|
181
160
|
|
|
@@ -185,8 +164,7 @@ class TriccEdge(TriccBaseModel):
|
|
|
185
164
|
source_external_id: triccId = None
|
|
186
165
|
target: Union[triccId, TriccNodeBaseModel]
|
|
187
166
|
target_external_id: triccId = None
|
|
188
|
-
value: Optional[str]
|
|
189
|
-
|
|
167
|
+
value: Optional[str] = None
|
|
190
168
|
|
|
191
169
|
|
|
192
170
|
class TriccGroup(TriccBaseModel):
|
|
@@ -194,37 +172,37 @@ class TriccGroup(TriccBaseModel):
|
|
|
194
172
|
group: Optional[TriccBaseModel] = None
|
|
195
173
|
activity: TriccBaseModel
|
|
196
174
|
name: Optional[str] = None
|
|
197
|
-
export_name:Optional[str] = None
|
|
198
|
-
label: Optional[Union[str, Dict[str,str]]] = None
|
|
175
|
+
export_name: Optional[str] = None
|
|
176
|
+
label: Optional[Union[str, Dict[str, str]]] = None
|
|
199
177
|
relevance: Optional[Union[Expression, TriccOperation]] = None
|
|
200
178
|
path_len: int = 0
|
|
201
179
|
prev_nodes: OrderedSet[TriccBaseModel] = OrderedSet()
|
|
180
|
+
|
|
202
181
|
def __init__(self, **data):
|
|
203
182
|
super().__init__(**data)
|
|
204
183
|
if self.name is None:
|
|
205
184
|
self.name = generate_id(str(data))
|
|
206
|
-
|
|
185
|
+
|
|
207
186
|
def gen_name(self):
|
|
208
187
|
if self.name is None:
|
|
209
188
|
self.name = get_rand_name(self.id)
|
|
210
|
-
|
|
189
|
+
|
|
211
190
|
def get_name(self):
|
|
212
191
|
result = str(super().get_name())
|
|
213
|
-
name =
|
|
214
|
-
label =
|
|
215
|
-
|
|
192
|
+
name = getattr(self, "name", None)
|
|
193
|
+
label = getattr(self, "label", None)
|
|
194
|
+
|
|
216
195
|
if name:
|
|
217
196
|
result = result + "::" + name
|
|
218
197
|
if label:
|
|
219
|
-
result = result + "::" + (
|
|
220
|
-
next(iter(self.label.values())) if isinstance(self.label, Dict) else self.label
|
|
221
|
-
)
|
|
198
|
+
result = result + "::" + (next(iter(self.label.values())) if isinstance(self.label, Dict) else self.label)
|
|
222
199
|
if len(name) < 50:
|
|
223
200
|
return result
|
|
224
201
|
else:
|
|
225
|
-
return result[:50]
|
|
202
|
+
return result[:50]
|
|
226
203
|
|
|
227
|
-
|
|
204
|
+
|
|
205
|
+
FwTriccNodeBaseModel = ForwardRef("TriccNodeBaseModel")
|
|
228
206
|
|
|
229
207
|
|
|
230
208
|
class TriccNodeBaseModel(TriccBaseModel):
|
|
@@ -232,44 +210,40 @@ class TriccNodeBaseModel(TriccBaseModel):
|
|
|
232
210
|
group: Optional[Union[TriccGroup, FwTriccNodeBaseModel]] = None
|
|
233
211
|
name: Optional[str] = None
|
|
234
212
|
export_name: Optional[str] = None
|
|
235
|
-
label: Optional[Union[str, Dict[str,str]]] = None
|
|
213
|
+
label: Optional[Union[str, Dict[str, str]]] = None
|
|
236
214
|
next_nodes: OrderedSet[TriccNodeBaseModel] = OrderedSet()
|
|
237
215
|
prev_nodes: OrderedSet[TriccNodeBaseModel] = OrderedSet()
|
|
238
216
|
expression: Optional[Union[Expression, TriccOperation, TriccStatic]] = None # will be generated based on the input
|
|
239
217
|
expression_inputs: List[Expression] = []
|
|
240
218
|
activity: Optional[FwTriccNodeBaseModel] = None
|
|
241
|
-
ref_def: Optional[Union[int,str]]
|
|
219
|
+
ref_def: Optional[Union[int, str]] = None # for medal creator
|
|
242
220
|
|
|
243
221
|
class Config:
|
|
244
222
|
use_enum_values = True # <--
|
|
245
|
-
|
|
223
|
+
|
|
246
224
|
def __hash__(self):
|
|
247
|
-
return hash(self.id
|
|
225
|
+
return hash(self.id)
|
|
248
226
|
|
|
249
227
|
# to be updated while processing because final expression will be possible to build$
|
|
250
|
-
# #only the last time the script will go through the node (all prev node expression would be created
|
|
228
|
+
# #only the last time the script will go through the node (all prev node expression would be created
|
|
251
229
|
def get_name(self):
|
|
252
|
-
result = self.__class__.__name__[9:]# str(super().get_name())
|
|
253
|
-
name =
|
|
254
|
-
label =
|
|
255
|
-
|
|
230
|
+
result = self.__class__.__name__[9:] # str(super().get_name())
|
|
231
|
+
name = getattr(self, "name", None)
|
|
232
|
+
label = getattr(self, "label", None)
|
|
233
|
+
|
|
256
234
|
if name:
|
|
257
235
|
result += name
|
|
258
236
|
if label:
|
|
259
|
-
result += "::" + (
|
|
260
|
-
next(iter(self.label.values())) if isinstance(self.label, Dict) else self.label
|
|
261
|
-
)
|
|
237
|
+
result += "::" + (next(iter(self.label.values())) if isinstance(self.label, Dict) else self.label)
|
|
262
238
|
if len(result) < 80:
|
|
263
239
|
return result
|
|
264
240
|
else:
|
|
265
|
-
return result[:80]
|
|
266
|
-
|
|
267
|
-
|
|
241
|
+
return result[:80]
|
|
268
242
|
|
|
269
243
|
def make_instance(self, instance_nb=None, activity=None):
|
|
270
244
|
instance = super().make_instance(instance_nb)
|
|
271
245
|
instance.group = activity
|
|
272
|
-
if hasattr(self,
|
|
246
|
+
if hasattr(self, "activity") and activity is not None:
|
|
273
247
|
instance.activity = activity
|
|
274
248
|
next_nodes = OrderedSet()
|
|
275
249
|
instance.next_nodes = next_nodes
|
|
@@ -277,31 +251,42 @@ class TriccNodeBaseModel(TriccBaseModel):
|
|
|
277
251
|
instance.prev_nodes = prev_nodes
|
|
278
252
|
expression_inputs = []
|
|
279
253
|
instance.expression_inputs = expression_inputs
|
|
280
|
-
|
|
281
|
-
for attr in [
|
|
254
|
+
|
|
255
|
+
for attr in [
|
|
256
|
+
"expression",
|
|
257
|
+
"relevance",
|
|
258
|
+
"default",
|
|
259
|
+
"reference",
|
|
260
|
+
"remote_reference",
|
|
261
|
+
"expression_reference",
|
|
262
|
+
]:
|
|
282
263
|
if getattr(self, attr, None):
|
|
283
|
-
setattr(instance, attr,
|
|
284
|
-
|
|
264
|
+
setattr(instance, attr, getattr(self, attr))
|
|
265
|
+
|
|
285
266
|
return instance
|
|
286
267
|
|
|
287
268
|
def gen_name(self):
|
|
288
269
|
if self.name is None:
|
|
289
270
|
self.name = get_rand_name(self.id)
|
|
271
|
+
|
|
290
272
|
def get_references(self):
|
|
291
273
|
return OrderedSet()
|
|
292
274
|
|
|
275
|
+
|
|
293
276
|
class TriccStatic(BaseModel):
|
|
294
277
|
value: Union[str, float, int, bool]
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
278
|
+
|
|
279
|
+
def __init__(self, value):
|
|
280
|
+
super().__init__(value=value)
|
|
281
|
+
|
|
298
282
|
def get_datatype(self):
|
|
299
|
-
if str(type(self.value)) ==
|
|
300
|
-
return
|
|
301
|
-
elif
|
|
302
|
-
return
|
|
283
|
+
if str(type(self.value)) == "bool":
|
|
284
|
+
return "boolean"
|
|
285
|
+
elif str(self.value).isnumeric():
|
|
286
|
+
return "number"
|
|
303
287
|
else:
|
|
304
288
|
return str(type(self.value))
|
|
289
|
+
|
|
305
290
|
def __eq__(self, other):
|
|
306
291
|
if isinstance(other, self.__class__):
|
|
307
292
|
return self.value == other.value
|
|
@@ -314,20 +299,23 @@ class TriccStatic(BaseModel):
|
|
|
314
299
|
def __hash__(self):
|
|
315
300
|
hash_value = hash(self.value)
|
|
316
301
|
return hash_value
|
|
302
|
+
|
|
317
303
|
def get_name(self):
|
|
318
304
|
return self.value
|
|
319
|
-
|
|
305
|
+
|
|
320
306
|
def __str__(self):
|
|
321
307
|
return str(self.value)
|
|
322
|
-
|
|
308
|
+
|
|
323
309
|
def __repr__(self):
|
|
324
|
-
return self.__class__.__name__+":"+str(type(self.value))+
|
|
310
|
+
return self.__class__.__name__ + ":" + str(type(self.value)) + ":" + str(self.value)
|
|
325
311
|
|
|
326
312
|
def get_references(self):
|
|
327
313
|
return OrderedSet()
|
|
328
314
|
|
|
315
|
+
|
|
329
316
|
class TriccReference(TriccStatic):
|
|
330
317
|
value: str
|
|
318
|
+
|
|
331
319
|
def __copy__(self):
|
|
332
320
|
return type(self)(self.value)
|
|
333
321
|
|
|
@@ -338,59 +326,60 @@ class TriccReference(TriccStatic):
|
|
|
338
326
|
return OrderedSet([self])
|
|
339
327
|
|
|
340
328
|
|
|
341
|
-
class TriccOperator(StrEnum):
|
|
342
|
-
AND =
|
|
343
|
-
ADD_OR =
|
|
344
|
-
#ADD_STRING: 'add_string'
|
|
345
|
-
OR =
|
|
346
|
-
NATIVE =
|
|
347
|
-
ISTRUE =
|
|
348
|
-
ISNOTTRUE =
|
|
349
|
-
ISFALSE =
|
|
350
|
-
ISNOTFALSE =
|
|
351
|
-
SELECTED =
|
|
352
|
-
MORE_OR_EQUAL =
|
|
353
|
-
LESS_OR_EQUAL =
|
|
354
|
-
EQUAL =
|
|
355
|
-
MORE =
|
|
356
|
-
NOTEQUAL =
|
|
357
|
-
BETWEEN =
|
|
358
|
-
LESS =
|
|
359
|
-
CONTAINS =
|
|
360
|
-
NOTEXISTS =
|
|
361
|
-
EXISTS =
|
|
362
|
-
NOT =
|
|
363
|
-
ISNULL =
|
|
364
|
-
ISNOTNULL=
|
|
365
|
-
ROUND =
|
|
366
|
-
|
|
367
|
-
CASE =
|
|
368
|
-
IFS =
|
|
369
|
-
IF =
|
|
370
|
-
|
|
329
|
+
class TriccOperator(StrEnum):
|
|
330
|
+
AND = "and" # and between left and rights
|
|
331
|
+
ADD_OR = "and_or" # left and one of the righs
|
|
332
|
+
# ADD_STRING: 'add_string'
|
|
333
|
+
OR = "or" # or between left and rights
|
|
334
|
+
NATIVE = "native" # default left is native expression
|
|
335
|
+
ISTRUE = "istrue" # left is right
|
|
336
|
+
ISNOTTRUE = "isnottrue"
|
|
337
|
+
ISFALSE = "isfalse" # left is false
|
|
338
|
+
ISNOTFALSE = "isnotfalse" # left is false
|
|
339
|
+
SELECTED = "selected" # right must be la select and one or several options
|
|
340
|
+
MORE_OR_EQUAL = "more_or_equal"
|
|
341
|
+
LESS_OR_EQUAL = "less_or_equal"
|
|
342
|
+
EQUAL = "equal"
|
|
343
|
+
MORE = "more"
|
|
344
|
+
NOTEQUAL = "not_equal"
|
|
345
|
+
BETWEEN = "between"
|
|
346
|
+
LESS = "less"
|
|
347
|
+
CONTAINS = "contains" # ref, txt Does CONTAINS make sense, like Select with wildcard
|
|
348
|
+
NOTEXISTS = "notexists"
|
|
349
|
+
EXISTS = "exists"
|
|
350
|
+
NOT = "not"
|
|
351
|
+
ISNULL = "isnull"
|
|
352
|
+
ISNOTNULL = "isnotnull"
|
|
353
|
+
ROUND = "round"
|
|
354
|
+
|
|
355
|
+
CASE = "case" # ref (equal value, res), (equal value,res)
|
|
356
|
+
IFS = "ifs" # (cond, res), (cond,res)
|
|
357
|
+
IF = "if" # cond val_true, val_false
|
|
358
|
+
|
|
371
359
|
# CDSS Specific
|
|
372
|
-
HAS_QUALIFIER =
|
|
373
|
-
ZSCORE =
|
|
374
|
-
IZSCORE =
|
|
375
|
-
AGE_DAY =
|
|
376
|
-
AGE_MONTH =
|
|
377
|
-
AGE_YEAR =
|
|
378
|
-
DIVIDED =
|
|
379
|
-
MULTIPLIED =
|
|
380
|
-
PLUS =
|
|
381
|
-
MINUS =
|
|
382
|
-
MODULO =
|
|
383
|
-
COUNT =
|
|
384
|
-
CAST_NUMBER =
|
|
385
|
-
CAST_INTEGER =
|
|
386
|
-
DRUG_DOSAGE =
|
|
387
|
-
COALESCE =
|
|
388
|
-
CAST_DATE =
|
|
389
|
-
PARENTHESIS =
|
|
390
|
-
CONCATENATE =
|
|
391
|
-
DATETIME_TO_DECIMAL =
|
|
392
|
-
|
|
393
|
-
|
|
360
|
+
HAS_QUALIFIER = "has_qualifier"
|
|
361
|
+
ZSCORE = "zscore" # left table_name, right Y, gender give Z
|
|
362
|
+
IZSCORE = "izscore" # left table_name, right Z, gender give Y
|
|
363
|
+
AGE_DAY = "age_day" # age from dob
|
|
364
|
+
AGE_MONTH = "age_month" # age from dob
|
|
365
|
+
AGE_YEAR = "age_year" # age from dob
|
|
366
|
+
DIVIDED = "divided"
|
|
367
|
+
MULTIPLIED = "multiplied"
|
|
368
|
+
PLUS = "plus"
|
|
369
|
+
MINUS = "minus"
|
|
370
|
+
MODULO = "modulo"
|
|
371
|
+
COUNT = "count"
|
|
372
|
+
CAST_NUMBER = "cast_number"
|
|
373
|
+
CAST_INTEGER = "cast_integer"
|
|
374
|
+
DRUG_DOSAGE = "drug_dosage" # drug name, *param1 (ex: weight, age)
|
|
375
|
+
COALESCE = "coalesce"
|
|
376
|
+
CAST_DATE = "cast_date"
|
|
377
|
+
PARENTHESIS = "parenthesis"
|
|
378
|
+
CONCATENATE = "concatenate"
|
|
379
|
+
DATETIME_TO_DECIMAL = "datetime_to_decimal"
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
RETURNS_BOOLEAN = [
|
|
394
383
|
TriccOperator.ADD_OR,
|
|
395
384
|
TriccOperator.AND,
|
|
396
385
|
TriccOperator.OR,
|
|
@@ -411,7 +400,7 @@ RETURNS_BOOLEAN =[
|
|
|
411
400
|
TriccOperator.LESS_OR_EQUAL,
|
|
412
401
|
TriccOperator.EQUAL,
|
|
413
402
|
TriccOperator.MORE,
|
|
414
|
-
TriccOperator.LESS
|
|
403
|
+
TriccOperator.LESS,
|
|
415
404
|
]
|
|
416
405
|
|
|
417
406
|
RETURNS_NUMBER = [
|
|
@@ -429,87 +418,98 @@ RETURNS_NUMBER = [
|
|
|
429
418
|
TriccOperator.COUNT,
|
|
430
419
|
TriccOperator.MODULO,
|
|
431
420
|
TriccOperator.CAST_NUMBER,
|
|
432
|
-
TriccOperator.CAST_INTEGER
|
|
421
|
+
TriccOperator.CAST_INTEGER,
|
|
433
422
|
]
|
|
434
423
|
|
|
435
|
-
RETURNS_DATE =[
|
|
436
|
-
TriccOperator.CAST_DATE
|
|
437
|
-
]
|
|
424
|
+
RETURNS_DATE = [TriccOperator.CAST_DATE]
|
|
438
425
|
|
|
439
426
|
OPERATION_LIST = {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
}
|
|
427
|
+
">=": TriccOperator.MORE_OR_EQUAL,
|
|
428
|
+
"<=": TriccOperator.LESS_OR_EQUAL,
|
|
429
|
+
"==": TriccOperator.EQUAL,
|
|
430
|
+
"!=": TriccOperator.NOTEQUAL,
|
|
431
|
+
"=": TriccOperator.EQUAL,
|
|
432
|
+
">": TriccOperator.MORE,
|
|
433
|
+
"<": TriccOperator.LESS,
|
|
434
|
+
}
|
|
435
|
+
|
|
448
436
|
|
|
449
437
|
class TriccOperation(BaseModel):
|
|
450
438
|
tricc_type: TriccNodeType = TriccNodeType.operation
|
|
451
439
|
operator: TriccOperator = TriccOperator.NATIVE
|
|
452
440
|
reference: OrderedSet[
|
|
453
441
|
Union[
|
|
454
|
-
TriccStatic,
|
|
455
|
-
|
|
442
|
+
TriccStatic,
|
|
443
|
+
TriccNodeBaseModel,
|
|
444
|
+
TriccOperation,
|
|
445
|
+
TriccReference,
|
|
446
|
+
Expression,
|
|
447
|
+
List[
|
|
448
|
+
Union[
|
|
449
|
+
TriccStatic,
|
|
450
|
+
TriccNodeBaseModel,
|
|
451
|
+
TriccOperation,
|
|
452
|
+
TriccReference,
|
|
453
|
+
Expression,
|
|
454
|
+
]
|
|
455
|
+
],
|
|
456
456
|
]
|
|
457
457
|
] = []
|
|
458
|
-
|
|
458
|
+
|
|
459
459
|
def __str__(self):
|
|
460
460
|
str_ref = map(str, self.reference)
|
|
461
461
|
return f"{self.operator}({', '.join(map(str, str_ref))})"
|
|
462
|
-
|
|
462
|
+
|
|
463
463
|
def __hash__(self):
|
|
464
464
|
return hash(self.__repr__())
|
|
465
465
|
|
|
466
466
|
def __repr__(self):
|
|
467
467
|
str_ref = map(repr, self.reference)
|
|
468
468
|
return f"TriccOperation:{self.operator}({', '.join(map(str, str_ref))})"
|
|
469
|
-
|
|
469
|
+
|
|
470
470
|
def __eq__(self, other):
|
|
471
471
|
return self.__str__() == str(other)
|
|
472
|
-
|
|
472
|
+
|
|
473
473
|
def __init__(self, operator, reference=[]):
|
|
474
474
|
super().__init__(operator=operator, reference=reference)
|
|
475
|
-
|
|
475
|
+
|
|
476
476
|
def get_datatype(self):
|
|
477
477
|
if self.operator in RETURNS_BOOLEAN:
|
|
478
|
-
return
|
|
478
|
+
return "boolean"
|
|
479
479
|
elif self.operator in RETURNS_NUMBER:
|
|
480
|
-
return
|
|
480
|
+
return "number"
|
|
481
481
|
elif self.operator in RETURNS_DATE:
|
|
482
|
-
return
|
|
482
|
+
return "date"
|
|
483
483
|
elif self.operator == TriccOperator.CONCATENATE:
|
|
484
|
-
return
|
|
484
|
+
return "string"
|
|
485
485
|
elif self.operator == TriccOperator.PARENTHESIS:
|
|
486
486
|
return self.get_reference_datatype(self.reference)
|
|
487
487
|
elif self.operator == TriccOperator.IF:
|
|
488
488
|
return self.get_reference_datatype(self.reference[1:])
|
|
489
|
-
elif self.operator in (
|
|
489
|
+
elif self.operator in (TriccOperator.IFS, TriccOperator.CASE):
|
|
490
490
|
rtype = set()
|
|
491
491
|
for rl in self.reference:
|
|
492
492
|
rtype.add(self.get_reference_datatype(self.reference[-2:]))
|
|
493
|
-
if len(rtype)>1:
|
|
494
|
-
return
|
|
493
|
+
if len(rtype) > 1:
|
|
494
|
+
return "mixed"
|
|
495
495
|
else:
|
|
496
|
-
return rtype.pop()
|
|
497
|
-
|
|
496
|
+
return rtype.pop()
|
|
497
|
+
|
|
498
498
|
def get_reference_datatype(self, references):
|
|
499
499
|
rtype = set()
|
|
500
500
|
for r in references:
|
|
501
|
-
if hasattr(r,
|
|
501
|
+
if hasattr(r, "get_datatype"):
|
|
502
502
|
rtype.add(r.get_datatype())
|
|
503
|
-
elif hasattr(r,
|
|
503
|
+
elif hasattr(r, "value"):
|
|
504
504
|
return str(type(r.value))
|
|
505
505
|
else:
|
|
506
506
|
return str(type(r))
|
|
507
|
-
|
|
508
|
-
if len(rtype)>1:
|
|
509
|
-
return
|
|
507
|
+
|
|
508
|
+
if len(rtype) > 1:
|
|
509
|
+
return "mixed"
|
|
510
510
|
else:
|
|
511
|
-
return rtype.pop()
|
|
512
|
-
|
|
511
|
+
return rtype.pop()
|
|
512
|
+
|
|
513
513
|
def get_references(self):
|
|
514
514
|
predecessor = OrderedSet()
|
|
515
515
|
if isinstance(self.reference, list):
|
|
@@ -518,7 +518,7 @@ class TriccOperation(BaseModel):
|
|
|
518
518
|
else:
|
|
519
519
|
raise NotImplementedError("cannot find predecessor of a str")
|
|
520
520
|
return predecessor
|
|
521
|
-
|
|
521
|
+
|
|
522
522
|
def _process_reference(self, reference, predecessor):
|
|
523
523
|
if isinstance(reference, list):
|
|
524
524
|
for e in reference:
|
|
@@ -532,10 +532,11 @@ class TriccOperation(BaseModel):
|
|
|
532
532
|
|
|
533
533
|
def append(self, value):
|
|
534
534
|
self.reference.append(value)
|
|
535
|
-
|
|
535
|
+
|
|
536
|
+
def replace_node(self, old_node, new_node):
|
|
536
537
|
if isinstance(self.reference, list):
|
|
537
538
|
for key in [i for i, x in enumerate(self.reference)]:
|
|
538
|
-
self.reference[key] = self._replace_reference(self.reference[key], new_node, old_node)
|
|
539
|
+
self.reference[key] = self._replace_reference(self.reference[key], new_node, old_node)
|
|
539
540
|
elif self.reference is not None:
|
|
540
541
|
raise NotImplementedError(f"cannot manage {self.reference.__class__}")
|
|
541
542
|
|
|
@@ -544,55 +545,64 @@ class TriccOperation(BaseModel):
|
|
|
544
545
|
for key in [i for i, x in enumerate(reference)]:
|
|
545
546
|
reference[key] = self._replace_reference(reference[key], new_node, old_node)
|
|
546
547
|
if isinstance(reference, TriccOperation):
|
|
547
|
-
reference.replace_node(old_node
|
|
548
|
+
reference.replace_node(old_node, new_node)
|
|
548
549
|
elif issubclass(reference.__class__, (TriccNodeBaseModel, TriccReference)) and reference == old_node:
|
|
549
550
|
reference = new_node
|
|
550
551
|
# to cover the options
|
|
551
|
-
if
|
|
552
|
-
|
|
552
|
+
if (
|
|
553
|
+
hasattr(reference, "select")
|
|
554
|
+
and hasattr(new_node, "select")
|
|
555
|
+
and issubclass(reference.select.__class__, TriccNodeBaseModel)
|
|
556
|
+
):
|
|
557
|
+
self.replace_node(reference.select, new_node.select)
|
|
553
558
|
return reference
|
|
554
|
-
|
|
559
|
+
|
|
555
560
|
def __copy__(self, keep_node=False):
|
|
556
561
|
# Create a new instance
|
|
557
562
|
if keep_node:
|
|
558
563
|
reference = [e for e in self.reference]
|
|
559
564
|
else:
|
|
560
|
-
reference = [
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
565
|
+
reference = [
|
|
566
|
+
(
|
|
567
|
+
e.copy()
|
|
568
|
+
if isinstance(e, (TriccReference, TriccOperation))
|
|
569
|
+
else (TriccReference(e.name) if hasattr(e, "name") else e)
|
|
570
|
+
)
|
|
571
|
+
for e in self.reference
|
|
572
|
+
]
|
|
573
|
+
|
|
574
|
+
new_instance = type(self)(self.operator, reference)
|
|
567
575
|
# Copy attributes (shallow copy for mutable attributes)
|
|
568
|
-
|
|
576
|
+
|
|
569
577
|
return new_instance
|
|
570
|
-
|
|
578
|
+
|
|
571
579
|
def copy(self, keep_node=False):
|
|
572
580
|
return self.__copy__(keep_node)
|
|
573
581
|
|
|
582
|
+
|
|
574
583
|
# function that make multipat and
|
|
575
584
|
# @param argv list of expression to join with and
|
|
576
585
|
def clean_and_list(argv):
|
|
577
586
|
for a in list(argv):
|
|
578
587
|
if isinstance(a, TriccOperation) and a.operator == TriccOperator.AND:
|
|
579
588
|
argv.remove(a)
|
|
580
|
-
return clean_and_list([*argv
|
|
581
|
-
elif a == TriccStatic(True) or a
|
|
589
|
+
return clean_and_list([*argv, *a.reference])
|
|
590
|
+
elif a == TriccStatic(True) or a is True:
|
|
582
591
|
argv.remove(a)
|
|
583
|
-
elif a == TriccStatic(False)
|
|
592
|
+
elif a == TriccStatic(False):
|
|
584
593
|
return [TriccStatic(False)]
|
|
585
|
-
|
|
594
|
+
|
|
586
595
|
internal = list(set(argv))
|
|
587
596
|
for a in internal:
|
|
588
|
-
for b in internal[internal.index(a)+1:]:
|
|
597
|
+
for b in internal[internal.index(a) + 1:]:
|
|
589
598
|
if not_clean(b) == a:
|
|
590
599
|
return [TriccStatic(False)]
|
|
591
600
|
return sorted(list(set(argv)), key=str)
|
|
592
|
-
|
|
601
|
+
|
|
602
|
+
|
|
593
603
|
def not_clean(a):
|
|
594
604
|
new_operator = None
|
|
595
|
-
if a is None or isinstance(a, str) and a ==
|
|
605
|
+
if a is None or isinstance(a, str) and a == "":
|
|
596
606
|
return TriccStatic(False)
|
|
597
607
|
elif isinstance(a, TriccStatic) and a == TriccStatic(False):
|
|
598
608
|
return TriccStatic(True)
|
|
@@ -620,26 +630,16 @@ def not_clean(a):
|
|
|
620
630
|
new_operator = TriccOperator.LESS
|
|
621
631
|
elif isinstance(a, TriccOperation) and a.operator == TriccOperator.NOT:
|
|
622
632
|
return a.reference[0]
|
|
623
|
-
|
|
633
|
+
|
|
624
634
|
if new_operator:
|
|
625
|
-
return TriccOperation(
|
|
626
|
-
|
|
627
|
-
a.reference
|
|
628
|
-
)
|
|
629
|
-
|
|
635
|
+
return TriccOperation(new_operator, a.reference)
|
|
636
|
+
|
|
630
637
|
elif not isinstance(a, TriccOperation) and issubclass(a.__class__, object):
|
|
631
|
-
return TriccOperation(
|
|
632
|
-
operator=TriccOperator.NOTEXISTS,
|
|
633
|
-
reference=[a]
|
|
634
|
-
)
|
|
638
|
+
return TriccOperation(operator=TriccOperator.NOTEXISTS, reference=[a])
|
|
635
639
|
else:
|
|
636
|
-
return TriccOperation(
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
)
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
640
|
+
return TriccOperation(TriccOperator.NOT, [a])
|
|
641
|
+
|
|
642
|
+
|
|
643
643
|
# function that generate remove unsure condition
|
|
644
644
|
# @param list_or
|
|
645
645
|
# @param and elm use upstream
|
|
@@ -651,17 +651,17 @@ def clean_or_list(list_or, elm_and=None):
|
|
|
651
651
|
for a in list(list_or):
|
|
652
652
|
if isinstance(a, TriccOperation) and a.operator == TriccOperator.OR:
|
|
653
653
|
list_or.remove(a)
|
|
654
|
-
return clean_or_list([*list_or
|
|
655
|
-
elif a == TriccStatic(False) or a
|
|
654
|
+
return clean_or_list([*list_or, *a.reference])
|
|
655
|
+
elif a == TriccStatic(False) or a is False or a == 0:
|
|
656
656
|
list_or.remove(a)
|
|
657
|
-
elif a == TriccStatic(True) or a
|
|
657
|
+
elif a == TriccStatic(True) or a is True or a == 1 or (elm_and is not None and not_clean(a) in list_or):
|
|
658
658
|
return [TriccStatic(True)]
|
|
659
659
|
# if there is x and not(X) in an OR list them the list is always true
|
|
660
|
-
elif elm_and is not None and
|
|
660
|
+
elif elm_and is not None and (not_clean(a) == elm_and or a == elm_and):
|
|
661
661
|
list_or.remove(a)
|
|
662
|
-
internal = list(list_or)
|
|
662
|
+
internal = list(list_or)
|
|
663
663
|
for a in internal:
|
|
664
|
-
for b in internal[internal.index(a)+1:]:
|
|
664
|
+
for b in internal[internal.index(a) + 1:]:
|
|
665
665
|
if not_clean(b) == a:
|
|
666
666
|
return [TriccStatic(True)]
|
|
667
667
|
if len(list_or) == 0:
|
|
@@ -669,19 +669,17 @@ def clean_or_list(list_or, elm_and=None):
|
|
|
669
669
|
|
|
670
670
|
return sorted(list(set(list_or)), key=repr)
|
|
671
671
|
|
|
672
|
+
|
|
672
673
|
def and_join(argv):
|
|
673
|
-
argv=clean_and_list(argv)
|
|
674
|
+
argv = clean_and_list(argv)
|
|
674
675
|
if len(argv) == 0:
|
|
675
|
-
return
|
|
676
|
+
return ""
|
|
676
677
|
elif len(argv) == 1:
|
|
677
678
|
return argv[0]
|
|
678
679
|
else:
|
|
679
|
-
return
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
)
|
|
683
|
-
|
|
684
|
-
|
|
680
|
+
return TriccOperation(TriccOperator.AND, argv)
|
|
681
|
+
|
|
682
|
+
|
|
685
683
|
def string_join(left: Union[str, TriccOperation], right: Union[str, TriccOperation]) -> TriccOperation:
|
|
686
684
|
"""
|
|
687
685
|
Concatenates two arguments (strings or TriccOperation) into a TriccOperation with CONCATENATE operator.
|
|
@@ -705,14 +703,15 @@ def string_join(left: Union[str, TriccOperation], right: Union[str, TriccOperati
|
|
|
705
703
|
# Return a new TriccOperation with the merged operands
|
|
706
704
|
return TriccOperation(operator=TriccOperator.CONCATENATE, reference=operands)
|
|
707
705
|
|
|
706
|
+
|
|
708
707
|
# function that make a 2 part and
|
|
709
708
|
# @param left part
|
|
710
709
|
# @param right part
|
|
711
710
|
def simple_and_join(left, right):
|
|
712
|
-
|
|
711
|
+
pass
|
|
713
712
|
# no term is considered as True
|
|
714
|
-
left_issue = left is None or left ==
|
|
715
|
-
right_issue = right is None or right ==
|
|
713
|
+
left_issue = left is None or left == ""
|
|
714
|
+
right_issue = right is None or right == ""
|
|
716
715
|
left_neg = not_clean(left)
|
|
717
716
|
right_neg = not_clean(right)
|
|
718
717
|
if left_issue and right_issue:
|
|
@@ -720,61 +719,54 @@ def simple_and_join(left, right):
|
|
|
720
719
|
elif left_neg == right or right_neg == left:
|
|
721
720
|
return TriccStatic(False)
|
|
722
721
|
elif left_issue:
|
|
723
|
-
logger.debug(
|
|
724
|
-
return
|
|
725
|
-
elif left ==
|
|
726
|
-
return
|
|
722
|
+
logger.debug("and with empty left term")
|
|
723
|
+
return right
|
|
724
|
+
elif left == "1" or left == 1 or left == TriccStatic(True) or left is True:
|
|
725
|
+
return right
|
|
727
726
|
elif right_issue:
|
|
728
|
-
logger.debug(
|
|
729
|
-
return
|
|
730
|
-
elif right ==
|
|
731
|
-
return
|
|
727
|
+
logger.debug("and with empty right term")
|
|
728
|
+
return left
|
|
729
|
+
elif right == "1" or right == 1 or right == TriccStatic(True) or right is True:
|
|
730
|
+
return left
|
|
732
731
|
else:
|
|
733
|
-
return
|
|
734
|
-
|
|
735
|
-
[left, right]
|
|
736
|
-
)
|
|
732
|
+
return TriccOperation(TriccOperator.AND, [left, right])
|
|
733
|
+
|
|
737
734
|
|
|
738
735
|
def or_join(list_or, elm_and=None):
|
|
739
|
-
cleaned_list
|
|
736
|
+
cleaned_list = clean_or_list(set(list_or), elm_and)
|
|
740
737
|
if len(cleaned_list) == 1:
|
|
741
738
|
return cleaned_list[0]
|
|
742
|
-
elif len(cleaned_list)>1:
|
|
743
|
-
return TriccOperation(
|
|
744
|
-
TriccOperator.OR,
|
|
745
|
-
cleaned_list
|
|
746
|
-
)
|
|
739
|
+
elif len(cleaned_list) > 1:
|
|
740
|
+
return TriccOperation(TriccOperator.OR, cleaned_list)
|
|
747
741
|
else:
|
|
748
742
|
logger.error("empty or list")
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
743
|
+
|
|
744
|
+
|
|
752
745
|
# function that make a 2 part NAND
|
|
753
746
|
# @param left part
|
|
754
747
|
# @param right part
|
|
755
748
|
def nand_join(left, right):
|
|
756
749
|
# no term is considered as True
|
|
757
|
-
left_issue = left is None or left ==
|
|
758
|
-
right_issue = right is None or right ==
|
|
759
|
-
left_neg = left
|
|
760
|
-
right_neg = right
|
|
750
|
+
left_issue = left is None or left == ""
|
|
751
|
+
right_issue = right is None or right == ""
|
|
752
|
+
left_neg = left is False or left == 0 or left == "0" or left == TriccStatic(False)
|
|
753
|
+
right_neg = right is False or right == 0 or right == "0" or right == TriccStatic(False)
|
|
761
754
|
if left_issue and right_issue:
|
|
762
755
|
logger.critical("and with both terms empty")
|
|
763
756
|
elif left_issue:
|
|
764
|
-
logger.debug(
|
|
765
|
-
return
|
|
766
|
-
elif left ==
|
|
767
|
-
return
|
|
768
|
-
elif right_issue
|
|
769
|
-
logger.debug(
|
|
770
|
-
return
|
|
771
|
-
elif right ==
|
|
772
|
-
return
|
|
757
|
+
logger.debug("and with empty left term")
|
|
758
|
+
return not_clean(right)
|
|
759
|
+
elif left == "1" or left == 1 or left == TriccStatic(True):
|
|
760
|
+
return not_clean(right)
|
|
761
|
+
elif right_issue:
|
|
762
|
+
logger.debug("and with empty right term")
|
|
763
|
+
return TriccStatic(False)
|
|
764
|
+
elif right == "1" or right == 1 or left_neg or right == TriccStatic(True):
|
|
765
|
+
return TriccStatic(False)
|
|
773
766
|
elif right_neg:
|
|
774
767
|
return left
|
|
775
768
|
else:
|
|
776
|
-
return
|
|
769
|
+
return and_join([left, not_clean(right)])
|
|
777
770
|
|
|
778
771
|
|
|
779
772
|
TriccGroup.update_forward_refs()
|
|
780
|
-
TriccEdge.update_forward_refs()
|