Skip to content
This repository was archived by the owner on Nov 26, 2025. It is now read-only.

Commit fffc6d3

Browse files
Merge pull request #59 from arpeely/support-in-operator
Add IN operator
2 parents 96dee23 + a71daca commit fffc6d3

3 files changed

Lines changed: 42 additions & 26 deletions

File tree

README.md

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -89,33 +89,34 @@ Out: '(-1.0+x)'
8989

9090
### Available operators, constants and functions
9191

92-
| Expression | Example | Output
93-
| ---------- | ------- | ------
94-
| + | ``parser.parse('2 + 2').evaluate({})`` | 4
95-
| - | ``parser.parse('3 - 1').evaluate({})`` | 2
96-
| `*` | ``parser.parse('2 * 3').evaluate({})`` | 6
97-
| / | ``parser.parse('5 / 2').evaluate({})`` | 2.5
98-
| % | ``parser.parse('5 % 2').evaluate({})`` | 1
99-
| ^ | ``parser.parse('5 ^ 2').evaluate({})`` | 25.0
100-
| PI | ``parser.parse('PI').evaluate({})`` | 3.141592653589793
101-
| E | ``parser.parse('E').evaluate({})`` | 2.718281828459045
102-
| sin(x) | ``parser.parse('sin(0)').evaluate({})`` | 0.0
103-
| cos(x) | ``parser.parse('cos(PI)').evaluate({})`` | - 1.0
104-
| tan(x) | ``parser.parse('tan(0)').evaluate({})`` | 0.0
92+
| Expression | Example | Output
93+
| ---------- | ------- | ------
94+
| + | ``parser.parse('2 + 2').evaluate({})`` | 4
95+
| - | ``parser.parse('3 - 1').evaluate({})`` | 2
96+
| `*` | ``parser.parse('2 * 3').evaluate({})`` | 6
97+
| / | ``parser.parse('5 / 2').evaluate({})`` | 2.5
98+
| % | ``parser.parse('5 % 2').evaluate({})`` | 1
99+
| ^ | ``parser.parse('5 ^ 2').evaluate({})`` | 25.0
100+
| PI | ``parser.parse('PI').evaluate({})`` | 3.141592653589793
101+
| E | ``parser.parse('E').evaluate({})`` | 2.718281828459045
102+
| sin(x) | ``parser.parse('sin(0)').evaluate({})`` | 0.0
103+
| cos(x) | ``parser.parse('cos(PI)').evaluate({})`` | - 1.0
104+
| tan(x) | ``parser.parse('tan(0)').evaluate({})`` | 0.0
105105
| asin(x) | ``parser.parse('asin(0)').evaluate({})`` | 0.0
106106
| acos(x) | ``parser.parse('acos(-1)').evaluate({})`` | 3.141592653589793
107-
| atan(x) | ``parser.parse('atan(PI)').evaluate({})`` | 1.2626272556789118
108-
| log(x) | ``parser.parse('log(1)').evaluate({})`` | 0.0
109-
| log(x, base) | ``parser.parse('log(16, 2)').evaluate({})`` | 4.0
110-
| abs(x) | ``parser.parse('abs(-1)').evaluate({})`` | 1
111-
| ceil(x) | ``parser.parse('ceil(2.7)').evaluate({})`` | 3.0
107+
| atan(x) | ``parser.parse('atan(PI)').evaluate({})`` | 1.2626272556789118
108+
| log(x) | ``parser.parse('log(1)').evaluate({})`` | 0.0
109+
| log(x, base)| ``parser.parse('log(16, 2)').evaluate({})`` | 4.0
110+
| abs(x) | ``parser.parse('abs(-1)').evaluate({})`` | 1
111+
| ceil(x) | ``parser.parse('ceil(2.7)').evaluate({})`` | 3.0
112112
| floor(x) | ``parser.parse('floor(2.7)').evaluate({})`` | 2.0
113113
| round(x) | ``parser.parse('round(2.7)').evaluate({})`` | 3.0
114-
| exp(x) | ``parser.parse('exp(2)').evaluate({})`` | 7.38905609893065
115-
| and | ``parser.parse('a and b').evaluate({'a':True, 'b':True})`` | True
116-
| or | ``parser.parse('a or b').evaluate({'a':True, 'b':True})`` | True
117-
| xor | ``parser.parse('a xor b').evaluate({'a':True, 'b':True})`` | False
118-
| not | ``parser.parse('a and not b').evaluate({'a':True, 'b':True})`` | False
114+
| exp(x) | ``parser.parse('exp(2)').evaluate({})`` | 7.38905609893065
115+
| and | ``parser.parse('a and b').evaluate({'a':True, 'b':True})`` | True
116+
| or | ``parser.parse('a or b').evaluate({'a':True, 'b':True})`` | True
117+
| xor | ``parser.parse('a xor b').evaluate({'a':True, 'b':True})`` | False
118+
| not | ``parser.parse('a and not b').evaluate({'a':True, 'b':True})`` | False
119+
| in | ``parser.parse('1 in (1,2,3)').evaluate({})`` | True
119120

120121
## Examples
121122

@@ -188,6 +189,9 @@ parser.parse('log(E)').evaluate({}) # 1.0
188189
parser.parse('cos(PI)').evaluate({}) # -1.0
189190

190191
parser.parse('x||y').evaluate({'x': 2, 'y': 3}) # '23'
192+
193+
parser.parse('num in (1,2,3)').evaluate({'num': 1}) # True
194+
parser.parse('"word" in "word in sentence"').evaluate({}) # True
191195
```
192196

193197
## Upload package to PyPi

py_expression_eval/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,9 @@ def orOperator (self, a, b ):
275275
def xorOperator (self, a, b ):
276276
return ( a ^ b )
277277

278+
def inOperator(self, a, b):
279+
return a in b
280+
278281
def notOperator(self, a):
279282
return not a
280283

@@ -382,6 +385,7 @@ def __init__(self):
382385
"and": self.andOperator,
383386
"or": self.orOperator,
384387
"xor": self.xorOperator,
388+
"in": self.inOperator,
385389
"D": self.roll
386390
}
387391

@@ -552,7 +556,7 @@ def evaluate(self, expr, variables):
552556

553557
def error_parsing(self, column, msg):
554558
self.success = False
555-
self.errormsg = 'parse error [column ' + str(column) + ']: ' + msg
559+
self.errormsg = 'parse error [column ' + str(column) + ']: ' + msg + ', expression: ' + self.expression
556560
raise Exception(self.errormsg)
557561

558562
def addfunc(self, tokenstack, operstack, type_):
@@ -706,6 +710,7 @@ def isOperator(self):
706710
('>=', 3, '>='),
707711
('<', 3, '<'),
708712
('>', 3, '>'),
713+
('in', 3, 'in'),
709714
('not ', 2, 'not'),
710715
('and ', 1, 'and'),
711716
('xor ', 0, 'xor'),

py_expression_eval/tests.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ def test_parser(self):
8181
# check precedents: AND should evaluate before OR
8282
self.assertExactEqual(parser.parse('a or b and not a').evaluate({'a': True, 'b': False}), True)
8383

84+
# in operations
85+
self.assertExactEqual(parser.parse('"ab" in ("ab", "cd")').evaluate({}), True)
86+
self.assertExactEqual(parser.parse('"ee" in ("ab", "cd")').evaluate({}), False)
87+
self.assertExactEqual(parser.parse('1 in (1, 2, 3)').evaluate({}), True)
88+
self.assertExactEqual(parser.parse('"ab" in ("ab", "cd") and 1 in (1,2,3)').evaluate({}), True)
89+
self.assertExactEqual(parser.parse('"word" in "word in sentence"').evaluate({}), True)
90+
8491
# functions
8592
self.assertExactEqual(parser.parse('pyt(2 , 0)').evaluate({}), 2.0)
8693
self.assertEqual(parser.parse("concat('Hello',' ','world')").evaluate({}), 'Hello world')
@@ -200,8 +207,8 @@ def count(increment):
200207
self.assertEqual(parser.parse("mean(xs)").variables(), ["xs"])
201208
self.assertEqual(parser.parse("mean(xs)").symbols(), ["mean", "xs"])
202209
self.assertEqual(parser.evaluate("mean(xs)", variables={"xs": [1, 2, 3]}), 2)
203-
self.assertExactEqual(parser.evaluate("count(inc)", variables={"inc": 5}), 5)
204-
self.assertExactEqual(parser.evaluate("count(inc)", variables={"inc": 5}), 10)
210+
self.assertExactEqual(parser.evaluate("count(num)", variables={"num": 5}), 5)
211+
self.assertExactEqual(parser.evaluate("count(num)", variables={"num": 5}), 10)
205212

206213
def test_custom_functions_with_inline_strings(self):
207214
parser = Parser()

0 commit comments

Comments
 (0)