Skip to content

Commit 8602220

Browse files
committed
Fixes for error propagation
1 parent c7f72f2 commit 8602220

File tree

3 files changed

+140
-1
lines changed

3 files changed

+140
-1
lines changed

features/error_propagation.feature

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
Feature: error_propagation
2+
Tests to ensure errors propagate how they are supposed to
3+
4+
Scenario: equal
5+
6+
When CEL expression '{}.a == 1' is evaluated
7+
Then eval_error is "no such member"
8+
9+
Scenario: not_equal
10+
11+
When CEL expression '{}.a != 1' is evaluated
12+
Then eval_error is "no such member"
13+
14+
Scenario: greater_than
15+
16+
When CEL expression '{}.a > 1' is evaluated
17+
Then eval_error is "no such member"
18+
19+
Scenario: greater_than_or_equal
20+
21+
When CEL expression '{}.a >= 1' is evaluated
22+
Then eval_error is "no such member"
23+
24+
Scenario: less_than
25+
26+
When CEL expression '{}.a > 1' is evaluated
27+
Then eval_error is "no such member"
28+
29+
Scenario: less_than_or_equal
30+
31+
When CEL expression '{}.a >= 1' is evaluated
32+
Then eval_error is "no such member"
33+
34+
Scenario: add
35+
36+
When CEL expression '{}.a + 1' is evaluated
37+
Then eval_error is "no such member"
38+
39+
Scenario: subtract
40+
41+
When CEL expression '{}.a - 1' is evaluated
42+
Then eval_error is "no such member"
43+
44+
Scenario: multiply
45+
46+
When CEL expression '{}.a * 1' is evaluated
47+
Then eval_error is "no such member"
48+
49+
Scenario: divide
50+
51+
When CEL expression '{}.a / 1' is evaluated
52+
Then eval_error is "no such member"
53+
54+
Scenario: modulo
55+
56+
When CEL expression '{}.a % 1' is evaluated
57+
Then eval_error is "no such member"
58+
59+
Scenario: in
60+
61+
When CEL expression '{}.a in [1]' is evaluated
62+
Then eval_error is "no such member"
63+
64+
Scenario: function
65+
66+
When CEL expression 'size({}.a)' is evaluated
67+
Then eval_error is "no such member"
68+
69+
Scenario: method
70+
71+
When CEL expression '{}.a.size()' is evaluated
72+
Then eval_error is "no such member"
73+
74+
Scenario: not
75+
76+
When CEL expression '!{}.a' is evaluated
77+
Then eval_error is "no such member"
78+
79+
Scenario: and_error
80+
81+
When CEL expression '{}.a && true' is evaluated
82+
Then eval_error is "no such member"
83+
84+
Scenario: and_ignore
85+
86+
When CEL expression '{}.a && false' is evaluated
87+
Then eval_error is None
88+
89+
Scenario: or_error
90+
91+
When CEL expression '{}.a || false' is evaluated
92+
Then eval_error is "no such member"
93+
94+
Scenario: or_ignore
95+
96+
When CEL expression '{}.a || true' is evaluated
97+
Then eval_error is None
98+
99+
Scenario: all_error
100+
101+
When CEL expression '[{"a": 1}, {}].all(v, v.a == 1)' is evaluated
102+
Then eval_error is "no such member"
103+
104+
Scenario: all_ignore
105+
106+
When CEL expression '[{"a": 1}, {}].all(v, v.a == 2)' is evaluated
107+
Then eval_error is None
108+
109+
Scenario: exists_error
110+
111+
When CEL expression '[{"a": 1}, {}].exists(v, v.a == 2)' is evaluated
112+
Then eval_error is "no such member"
113+
114+
Scenario: exists_ignore
115+
116+
When CEL expression '[{"a": 1}, {}].exists(v, v.a == 1)' is evaluated
117+
Then eval_error is None
118+
119+
Scenario: exists_one_error
120+
121+
When CEL expression '[{"a": 1}, {}].exists_one(v, v.a == 1)' is evaluated
122+
Then eval_error is "no such member"

src/celpy/celtypes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ def logical_not(x: Value) -> Value:
334334
This could almost be `logical_or = evaluation.boolean(operator.not_)`,
335335
but the definition would expose Python's notion of "truthiness", which isn't appropriate for CEL.
336336
"""
337+
if isinstance(x, Exception):
338+
return x
337339
if isinstance(x, BoolType):
338340
result_value = BoolType(not x)
339341
else:

src/celpy/evaluation.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,11 @@ def boolean(
291291
def bool_function(
292292
a: celpy.celtypes.Value, b: celpy.celtypes.Value
293293
) -> celpy.celtypes.BoolType:
294+
if isinstance(a, CELEvalError):
295+
return a
296+
if isinstance(b, CELEvalError):
297+
return b
298+
294299
result_value = function(a, b)
295300
if result_value == NotImplemented:
296301
return cast(celpy.celtypes.BoolType, result_value)
@@ -323,7 +328,9 @@ def operator_in(item: Result, container: Result) -> Result:
323328
324329
- True. There was a item found. Exceptions may or may not have been found.
325330
- False. No item found AND no exceptions.
326-
- CELEvalError. No item found AND at least one exception.
331+
- CELEvalError. Either:
332+
- No item found AND at least one exception or
333+
- The input item or container itself was already an error
327334
328335
To an extent this is a little like the ``exists()`` macro.
329336
We can think of ``container.contains(item)`` as ``container.exists(r, r == item)``.
@@ -333,6 +340,11 @@ def operator_in(item: Result, container: Result) -> Result:
333340
334341
``reduce(logical_or, (item == c for c in container), BoolType(False))``
335342
"""
343+
if isinstance(item, CELEvalError):
344+
return item
345+
if isinstance(container, CELEvalError):
346+
return container
347+
336348
result_value: Result = celpy.celtypes.BoolType(False)
337349
for c in cast(Iterable[Result], container):
338350
try:
@@ -1547,6 +1559,9 @@ def function_eval(
15471559

15481560
try:
15491561
list_exprlist = cast(List[Result], exprlist or [])
1562+
for expr in list_exprlist:
1563+
if isinstance(expr, CELEvalError):
1564+
return expr
15501565
return function(*list_exprlist)
15511566
except ValueError as ex:
15521567
value = CELEvalError(

0 commit comments

Comments
 (0)