I am trying to write safyfied evaluator class, and get unexpected __builtins__
added to dictionary after evaluation. Can somebody explain why/how it happens?
import math
def echo(n):
print n
return n
def nothing(n):
return n
debug = nothing
class MathParser(object):
'''
Mathematical Expression Evaluator class.
call evaluate() function that will return you the result of the
mathematical expression given as a string when initializing.
math library functions allowed, no __ allowed
'''
__slots__ = 'expression', 'variables', 'math'
def __init__(self, expression, variables=None):
self.math = dict((a,b) for a,b in math.__dict__.items() if not a.startswith('__') and '__' not in str(b))
assert '__builtins__' not in self.math # passes
self.expression = expression
self.variables = variables
self.check()
def check(self):
if any(any('__' in debug(str(n)) for n in d)
for d in (self.expression.split(), self.math.keys(), self.math.values(), self.variables.keys(), self.variables.values())):
raise ValueError('__ not allowed')
return True
def evaluate(self, variables=None):
""" Evaluate the mathematical expression given as a string in the expression member variable.
"""
if not variables is None:
self.variables.update(variables)
if self.check():
return eval(self.expression, self.math, self.variables)
def __str__(self):
return str((str(self.expression), str(self.variables), str(self.math)))
if __name__ == "__main__":
variables = {'x':1.5, 'y':2.0}
g = 3
for expr in '1+ 2+sin (x+ y)/e+pi', '1+2+sin( x + y)/abc(x)', "[]+__import__('os').listdir('/')", "dir()", 'g+x' :
try:
p = MathParser(expr, variables)
assert '__builtins__' not in p.math # passes
print('%s = %s' % (expr, p.evaluate()))
assert '__builtins__' not in p.math # does not pass
except (NameError, ValueError) as e:
print(e)
# update variable in evaluate
debug = echo
print(p.expression)
print('%s = %s' % (expr, p.evaluate()))
print('%s = %s' % (expr, p.evaluate({'builtins':__builtins__})))
So only the assert after p.evaluate() is failing.