1 # -*- coding: utf-8 -*-
2 ###########################################################################
3 # Copyright (C) 2008 by Andrew Mahone
4 # <andrew.mahone@gmail.com>
6 # Copyright: See COPYING file that comes with this distribution
8 ###########################################################################
12 from RestrictedPython
.RCompile
import RExpression
13 from RestrictedPython
.MutatingWalker
import walk
14 from RestrictedPython
.Guards
import safe_builtins
as eval_builtins
15 from string
import maketrans
16 from compiler
import ast
18 _breakre
= re
.compile("\(|\)|\$\$|\$(?P<nosan>/)?(?P<label>[a-z]+)?(?P<paren>\()?|(?P<raw>[rR])?(?P<quote>'|\")|\\\\.")
19 pathseptrans
= unicode(maketrans('/', '_')[:48])
20 pathtrans
= unicode(maketrans(r
'/\[]?=+<>;",*|', os
.path
.sep
+ '_' * 13)[:125])
22 eval_builtins
= eval_builtins
.copy()
23 eval_builtins
.update(filter=filter, map=map, max=max, min=min, reduce=reduce, reversed=reversed, slice=slice, sorted=sorted)
24 del eval_builtins
['delattr']
25 del eval_builtins
['setattr']
26 eval_globals
= {'__builtins__':eval_builtins
, '_getattr_':getattr, '_getitem_': lambda x
, y
: x
[y
]}
28 def underscorereplace_errors(e
):
29 return (u
'_' * (e
.end
- e
.start
), e
.end
)
31 codecs
.register_error('underscorereplace', underscorereplace_errors
)
33 def evaluate(item
, cdict
):
34 if isinstance(item
, Expr
):
35 return item
.evaluate(cdict
)
39 class InlineFuncsVisitor
:
40 def __init__(self
, filename
, baseexpr
):
41 self
.filename
= filename
42 self
.baseexpr
= baseexpr
43 def visitCallFunc(self
, node
, *args
):
44 if not hasattr(node
, 'node'):
46 if not isinstance(node
.node
, ast
.Name
):
48 handler
= getattr(self
, '_' + node
.node
.name
, None)
50 return handler(node
, *args
)
53 def _first(self
, node
, *args
):
54 clocals
= ast
.Const(locals)
55 clocals
.lineno
= node
.lineno
56 clocals
= ast
.CallFunc(clocals
, [], None, None)
57 clocals
.lineno
= node
.lineno
59 exp
.lineno
= node
.lineno
60 for item
in node
.args
:
61 if not isinstance(item
, ast
.Const
) or isinstance(item
.value
, basestring
):
62 if isinstance(item
, ast
.Const
):
64 item
= self
.baseexpr(item
, self
.filename
)
65 item
= ast
.Const(item
.evaluate
)
66 item
.lineno
= node
.lineno
67 item
= ast
.CallFunc(item
, [clocals
])
68 item
.lineno
= node
.lineno
69 exp
.nodes
.append(item
)
72 class Expr(RExpression
, object):
73 _globals
= eval_globals
76 def __new__(cls
, source
, filename
="", baseexpr
=None):
77 key
= (cls
, source
, filename
, baseexpr
)
78 if isinstance(source
, basestring
):
79 if key
not in cls
._cache
:
80 cls
._cache
[key
] = object.__new
__(cls
)
81 return cls
._cache
[key
]
82 elif isinstance(source
, ast
.Node
):
83 return object.__new
__(cls
)
84 elif isinstance(source
, cls
):
87 def __init__(self
, source
, filename
="", baseexpr
=None):
88 if hasattr(self
, '_compiled'):
91 self
._baseexpr
= baseexpr
or getattr(self
.__class
__, '_baseexpr', None) or self
.__class
__
92 self
._filename
= filename
93 if not isinstance(source
, ast
.Node
):
94 RExpression
.__init
__(self
, source
, filename
)
95 source
= self
._get
_tree
()
97 if not (isinstance(source
, ast
.Expression
)):
98 source
= ast
.Expression(source
)
99 source
.filename
= filename
100 walk(source
, InlineFuncsVisitor(self
._filename
, self
._baseexpr
))
101 gen
= self
.CodeGeneratorClass(source
)
102 self
._compiled
= gen
.getCode()
105 return hash(self
._compiled
)
108 tree
= RExpression
._get
_tree
(self
)
109 walk(tree
, InlineFuncsVisitor(self
.filename
, self
._baseexpr
))
112 def evaluate(self
, cdict
):
114 return eval(self
._compiled
, self
._globals
, cdict
)
118 class StringExpr(Expr
):
119 def evaluate(self
, cdict
):
120 ret
= super(self
.__class
__, self
).evaluate(cdict
)
125 class SanitizedExpr(Expr
):
126 def evaluate(self
, cdict
):
127 ret
= super(self
.__class
__, self
).evaluate(cdict
)
129 ret
= unicode(ret
).translate(pathseptrans
)
136 clocals
= ast
.Const(locals)
138 clocals
= ast
.CallFunc(clocals
, [], None, None)
140 items
= self
._parse
()
146 if isinstance(item
, Expr
):
147 item
= ast
.Const(item
.evaluate
)
149 item
= ast
.CallFunc(item
, [clocals
])
151 ta
.nodes
.append(item
)
152 te
.nodes
.append(item
)
154 item
= ast
.Const(item
)
156 ta
.nodes
.append(item
)
157 result
= ast
.Const(''.join
)
159 result
= ast
.CallFunc(result
, [ta
], None, None)
161 none
= ast
.Name('None')
163 test
= ast
.Compare(none
, [('in', te
)])
165 result
= ast
.IfExp(test
, none
, result
)
167 result
= ast
.Expression(result
)
169 result
.filename
= self
._filename
177 for m
in _breakre
.finditer(self
._source
):
178 # import pdb; pdb.set_trace()
181 if m
.start() > prevend
:
182 cur
.append(self
._source
[prevend
:m
.start()])
187 elif mt
.startswith('$'):
188 if not (mg
['label'] or mg
['paren']):
192 result
.append(''.join(cur
))
195 if mg
['nosan'] or not self
._sanitize
:
196 result
.append(StringExpr(mg
['label'], self
._filename
, self
._baseexpr
))
198 result
.append(SanitizedExpr(mg
['label'], self
._filename
, self
._baseexpr
))
200 if mg
['nosan'] or not self
._sanitize
:
201 cur
.append(StringExpr
)
203 cur
.append(SanitizedExpr
)
205 cur
.append(mg
['label'])
216 state
.append(mg
['quote'])
217 elif mt
.endswith('('):
220 if mg
['quote'] == state
[-1]:
223 result
.append(cur
[0](''.join(cur
[1:]), self
._filename
, self
._baseexpr
))
225 cur
.append(self
._source
[prevend
:])
227 raise SyntaxError('unexpected EOF while parsing', (self
._filename
, 1, len(self
._source
), self
._source
))
229 result
.append(''.join(cur
))
232 class SanitizedFormat(Format
):
235 class FileFormat(SanitizedFormat
):
236 _baseexpr
= SanitizedFormat
237 def evaluate(self
, cdict
):
238 ret
= super(self
.__class
__, self
).evaluate(cdict
)
240 ret
= ret
.translate(pathtrans
)
245 def unique(testset
, expr
, evalexpr
): pass
247 __all__
= ['Format', 'FileFormat', 'Expr', 'evaluate']