Skip to content

Instantly share code, notes, and snippets.

@Jinmo
Created April 17, 2018 21:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jinmo/5bba8f5497c5f31734a3e3ded8c74412 to your computer and use it in GitHub Desktop.
Save Jinmo/5bba8f5497c5f31734a3e3ded8c74412 to your computer and use it in GitHub Desktop.
extensible literal_eval, which is a bit more dangerous
from ast import parse, iter_fields, AST
class NotAllowedException(Exception):
def __init__(self, cls):
self.cls = cls
pass
def __str__(self):
return '%r is not allowed for execution' % self.cls
class Executor(object):
def __init__(self, whitelist=None):
self.allowed_types = set()
if whitelist is not None:
for c in whitelist:
self.allow(c)
def allow(self, source):
node = parse(source)
self._allow_node(node)
def _allow_node(self, node):
if isinstance(node, list):
for x in node:
self._allow_node(x)
elif isinstance(node, AST):
self.allowed_types.add(node.__class__)
for name, field in iter_fields(node):
self._allow_node(field)
def check_allowed(self, node):
if isinstance(node, list):
for x in node:
self.check_allowed(x)
elif isinstance(node, AST):
if node.__class__ not in self.allowed_types:
raise NotAllowedException(node.__class__)
for name, field in iter_fields(node):
self.check_allowed(field)
def __call__(self, source): # execute
node = parse(source)
try:
self.check_allowed(node)
except NotAllowedException:
raise
return eval(source)
if __name__ == '__main__':
ex = Executor((
'1 - 1',
'1 + 1'
))
print ex('100 + 100')
print ex('1 * 1')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment