]> git.donarmstrong.com Git - lilypond.git/blob - python/safeeval.py
Doc-es: Update of Learning and Common-notation.
[lilypond.git] / python / safeeval.py
1
2 ## http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/364469
3 import compiler
4
5 class Unsafe_Source_Error(Exception):
6     def __init__(self,error,descr = None,node = None):
7         self.error = error
8         self.descr = descr
9         self.node = node
10         self.lineno = getattr(node,"lineno",None)
11         
12     def __repr__(self):
13         return "Line %d.  %s: %s" % (self.lineno, self.error, self.descr)
14     __str__ = __repr__    
15            
16 class SafeEval(object):
17     
18     def visit(self, node,**kw):
19         cls = node.__class__
20         meth = getattr(self,'visit'+cls.__name__,self.default)
21         return meth(node, **kw)
22             
23     def default(self, node, **kw):
24         for child in node.getChildNodes():
25             return self.visit(child, **kw)
26             
27     visitExpression = default
28     
29     def visitConst(self, node, **kw):
30         return node.value
31
32     def visitDict(self,node,**kw):
33         return dict([(self.visit(k),self.visit(v)) for k,v in node.items])
34         
35     def visitTuple(self,node, **kw):
36         return tuple(self.visit(i) for i in node.nodes)
37         
38     def visitList(self,node, **kw):
39         return [self.visit(i) for i in node.nodes]
40
41     def visitUnarySub(self, node, **kw):
42         return - self.visit (node.getChildNodes ()[0])
43
44 class SafeEvalWithErrors(SafeEval):
45
46     def default(self, node, **kw):
47         raise Unsafe_Source_Error("Unsupported source construct",
48                                 node.__class__,node)
49             
50     def visitName(self,node, **kw):
51         raise Unsafe_Source_Error("Strings must be quoted", 
52                                  node.name, node)
53                                  
54     # Add more specific errors if desired
55             
56
57 def safe_eval(source, fail_on_error = True):
58     walker = fail_on_error and SafeEvalWithErrors() or SafeEval()
59     try:
60         ast = compiler.parse(source,"eval")
61     except SyntaxError, err:
62         raise
63     try:
64         return walker.visit(ast)
65     except Unsafe_Source_Error, err:
66         raise
67
68
69 def safe_eval(source, fail_on_error = True):
70     walker = fail_on_error and SafeEvalWithErrors() or SafeEval()
71     try:
72         ast = compiler.parse(source,"eval")
73     except SyntaxError, err:
74         raise
75     try:
76         return walker.visit(ast)
77     except Unsafe_Source_Error, err:
78         raise
79
80 def test ():
81     print safe_eval ('{1: [2,3], "4": (-1,2)}')
82     
83 if __name__ == '__main__':
84     test ()