Skip to content

Commit

Permalink
Raise a reasonable exception when an operator is undefined
Browse files Browse the repository at this point in the history
  • Loading branch information
smurfix committed Jun 28, 2020
1 parent b3ea031 commit 2e9df55
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 5 deletions.
24 changes: 21 additions & 3 deletions simpleeval.py
Expand Up @@ -175,6 +175,17 @@ def __init__(self, attr, expression):
self.expression = expression


class OperatorNotDefined(InvalidExpression):
"""operator does not exist"""

def __init__(self, attr, expression):
self.message = \
"Operator '{0}' does not exist in expression '{1}'".format(
attr, expression)
self.attr = attr
self.expression = expression


class FeatureNotAvailable(InvalidExpression):
""" What you're trying to do is not allowed. """

Expand Down Expand Up @@ -392,11 +403,18 @@ def _eval_constant(node):
return node.value

def _eval_unaryop(self, node):
return self.operators[type(node.op)](self._eval(node.operand))
try:
op = self.operators[type(node.op)]
except KeyError:
raise OperatorNotDefined(node.op, self.expr)
return op(self._eval(node.operand))

def _eval_binop(self, node):
return self.operators[type(node.op)](self._eval(node.left),
self._eval(node.right))
try:
op = self.operators[type(node.op)]
except KeyError:
raise OperatorNotDefined(node.op, self.expr)
return op(self._eval(node.left), self._eval(node.right))

def _eval_boolop(self, node):
if isinstance(node.op, ast.And):
Expand Down
19 changes: 17 additions & 2 deletions test_simpleeval.py
Expand Up @@ -15,7 +15,7 @@
import warnings
from simpleeval import (
SimpleEval, EvalWithCompoundTypes, FeatureNotAvailable, FunctionNotDefined, NameNotDefined,
InvalidExpression, AttributeDoesNotExist, simple_eval
OperatorNotDefined, InvalidExpression, AttributeDoesNotExist, simple_eval
)


Expand Down Expand Up @@ -1080,13 +1080,28 @@ def test_functions_are_disallowed_in_expressions(self):
simpleeval.DEFAULT_FUNCTIONS = DF.copy()


class TestNoFunctions(DRYTest):
class TestNoEntries(DRYTest):
def test_no_functions(self):
self.s.eval('int(42)')
with self.assertRaises(FunctionNotDefined):
s = SimpleEval(functions={})
s.eval('int(42)')

# does not work, AST interprets built-ins directly
#
# def test_no_names(self):
# import pdb;pdb.set_trace()
# self.s.eval('True')
# with self.assertRaises(NameNotDefined):
# s = SimpleEval(names={})
# s.eval('True')

def test_no_operators(self):
self.s.eval('1+2')
with self.assertRaises(OperatorNotDefined):
s = SimpleEval(operators={})
s.eval('1+2')



if __name__ == '__main__': # pragma: no cover
Expand Down

0 comments on commit 2e9df55

Please sign in to comment.