2 ## http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/364469
5 class Unsafe_Source_Error(Exception):
6 def __init__(self
,error
,descr
= None,node
= None):
10 self
.lineno
= getattr(node
,"lineno",None)
13 return "Line %d. %s: %s" % (self
.lineno
, self
.error
, self
.descr
)
16 class SafeEval(object):
18 def visit(self
, node
,**kw
):
20 meth
= getattr(self
,'visit'+cls
.__name
__,self
.default
)
21 return meth(node
, **kw
)
23 def default(self
, node
, **kw
):
24 for child
in node
.getChildNodes():
25 return self
.visit(child
, **kw
)
27 visitExpression
= default
29 def visitConst(self
, node
, **kw
):
32 def visitDict(self
,node
,**kw
):
33 return dict([(self
.visit(k
),self
.visit(v
)) for k
,v
in node
.items
])
35 def visitTuple(self
,node
, **kw
):
36 return tuple(self
.visit(i
) for i
in node
.nodes
)
38 def visitList(self
,node
, **kw
):
39 return [self
.visit(i
) for i
in node
.nodes
]
41 def visitUnarySub(self
, node
, **kw
):
42 return - self
.visit (node
.getChildNodes ()[0])
44 class SafeEvalWithErrors(SafeEval
):
46 def default(self
, node
, **kw
):
47 raise Unsafe_Source_Error("Unsupported source construct",
50 def visitName(self
,node
, **kw
):
51 raise Unsafe_Source_Error("Strings must be quoted",
54 # Add more specific errors if desired
57 def safe_eval(source
, fail_on_error
= True):
58 walker
= fail_on_error
and SafeEvalWithErrors() or SafeEval()
60 ast
= compiler
.parse(source
,"eval")
61 except SyntaxError, err
:
64 return walker
.visit(ast
)
65 except Unsafe_Source_Error
, err
:
69 def safe_eval(source
, fail_on_error
= True):
70 walker
= fail_on_error
and SafeEvalWithErrors() or SafeEval()
72 ast
= compiler
.parse(source
,"eval")
73 except SyntaxError, err
:
76 return walker
.visit(ast
)
77 except Unsafe_Source_Error
, err
:
81 print safe_eval ('{1: [2,3], "4": (-1,2)}')
83 if __name__
== '__main__':