Created
April 17, 2018 21:19
-
-
Save Jinmo/5bba8f5497c5f31734a3e3ded8c74412 to your computer and use it in GitHub Desktop.
extensible literal_eval, which is a bit more dangerous
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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