1
2
3 import re
4 from math import *
5 import sys
6
7 from PyFoam.Error import error,warning
8 from PyFoam.ThirdParty.pyratemp import Template as PyratempTemplate
9 from PyFoam.ThirdParty.pyratemp import EvalPseudoSandbox,TemplateRenderError
10 from PyFoam.ThirdParty.pyratemp import Renderer as PyratempRenderer
11
12 from PyFoam.ThirdParty.six import iteritems,exec_,print_
13
15 """Usual renderer but report a filename"""
16
17 - def __init__(self, evalfunc, escapefunc,filename=None):
18 PyratempRenderer.__init__(self, evalfunc, escapefunc)
19
20 self.fileName = filename
21
23 result="Cannot eval expression '%s'. (%s: %s)" %(expr, err.__class__.__name__, err)
24 if self.fileName:
25 result+=" in file "+self.fileName
26 return result
27
28 - def _eval(self, expr, data):
29 """evalfunc with error-messages"""
30 try:
31 return self.evalfunc(expr, data)
32 except (TypeError,NameError,IndexError,KeyError,AttributeError, SyntaxError):
33 err = sys.exc_info()[1]
34 raise TemplateRenderError(self.reportString(expr,err))
35
37 """Variant of the renderer that doesn't choke on problems with evaluations"""
38
39 - def __init__(self, evalfunc, escapefunc,filename=None):
41
42 - def _eval(self, expr, data):
43 """evalfunc with error-messages"""
44 try:
45 return self.evalfunc(expr, data)
46 except (TypeError,NameError,IndexError,KeyError,AttributeError, SyntaxError):
47 err = sys.exc_info()[1]
48 warning(self.reportString(expr,err))
49 return "Template evaluation ERROR: "+self.reportString(expr,err)
50
51 execIdString="this is meant to be executed:"
52 substituteIdString="substitute current values into this string:"
53
55 """This class preprocesses the input that is give to it in such a
56 way that the old format (using $$ at the line beginnings and $
57 .. $ for expressions) is reworked into something that pyratemp understands
58 """
59 - def __init__(self,
60 dovarline=True,
61 doexpr=True,
62 expressionDelimiter="$",
63 assignmentLineStart="$$",
64 allowExec=False,
65 specials=[]):
66 """Create the regexp once for performance reasons
67 @param dovarline: look for variable lines that start with $$
68 @param doexpr: substitute expressions that are between $
69 @param expressionDelimiter: character/string that is used before and after an
70 expression. After the expression the reverse of the string is used
71 @param assignmentLineStart: character sequence that signals an assignment line
72 @param allowExec: allows execution of code. This is potentially unsafe
73 @param specials: a list. If any expression starts with one of these values then
74 the full expression (including delimiters) is left verbatim in the template"""
75
76 self.clip=len(expressionDelimiter)
77 self.specials=specials
78
79 tmp=list(expressionDelimiter)
80 tmp.reverse()
81
82 self.expressionDelimiter=re.escape(expressionDelimiter)
83 self.expressionDelimiterEnd=re.escape("".join(tmp))
84
85
86
87 self.assignmentLineStart=assignmentLineStart
88
89 self.expr=re.compile("%s[^$!\n]+?%s" % (self.expressionDelimiter,self.expressionDelimiterEnd))
90 self.dovarline=dovarline
91 self.doexpr=doexpr
92
93 self.allowExec=allowExec
94
96 """This does the actual work"""
97
98 if len(original)==0:
99 return original
100
101 lines=original.split("\n")
102 if lines[-1]=="":
103 lines=lines[:-1]
104
105 result=""
106
107 for l in lines:
108 if l[:len(self.assignmentLineStart)]==self.assignmentLineStart and self.dovarline:
109 tmp=l[len(self.assignmentLineStart):].split("=")
110 if len(tmp)!=2:
111 if self.allowExec:
112 execString=l[len(self.assignmentLineStart):].replace("\\","\\\\").replace("\"","\\\"")
113 result+='$!setvar("%s", "%s")!$#!' % (
114 "dummyVarForExecution",
115 execIdString+execString.strip()
116 )
117 result+="\n"
118 else:
119 error("Each definition must be of the form: <name>=<value>",
120 "The string",l,"is not")
121 else:
122
123
124 exprStr=tmp[1].replace("\\","\\\\").replace("\"","\\\"")
125 result+='$!setvar("%s", "%s")!$#!' % (tmp[0].strip(),exprStr.strip())
126 result+="\n"
127 elif self.doexpr:
128 nl=""
129 iStart=0
130 for m in self.expr.finditer(l):
131 inner=l[m.start()+self.clip:m.end()-self.clip]
132 hasSpecial=False
133 nl+=l[iStart:m.start()]
134 for k in self.specials:
135 if len(k)<=len(inner):
136 if inner[:len(k)]==k:
137 hasSpecial=True
138 substVarName="dummyVarForSubstitution"
139
140 nl+='$!setvar("%s", "%s")!$#!\n' % (
141 substVarName,
142 substituteIdString+l[m.start():m.end()]
143 )
144 nl+='$!'+substVarName+'!$'
145
146 if not hasSpecial:
147 nl+="$!"+inner+"!$"
148 iStart=m.end()
149 result+=nl+l[iStart:]+"\n"
150 else:
151 result+=l+"\n"
152
153
154 if original[-1]!='\n' and result[-1]=='\n':
155 result=result[:-1]
156
157 return result
158
246
248 """Add mathematical functions to the valid functons"""
250 EvalPseudoSandbox.__init__(self)
251 import math
252 for o in dir(math):
253 if o[0]!="_":
254 self.register(o,getattr(math,o))
255
256 from PyFoam.ThirdParty.six.moves import builtins as __builtin__
257 self.register("set",__builtin__.set)
258
259 if allowExec:
260 del self.eval_allowed_globals["__import__"]
261 self.register("__import__",__builtins__["__import__"])
262
263 - def compile(self, expr,mode="eval"):
264 """Compile a python-eval-expression. Overrides the default implementation
265 to allow '_[1]' as a valid name
266 """
267 if expr not in self._compile_cache:
268 c = compile(expr, "", mode)
269 for i in c.co_names:
270 if i[0] == '_':
271 if i[1]!='[' or i[-1]!=']':
272 raise NameError("Name '%s' is not allowed." %(i))
273 self._compile_cache[expr] = c
274 return self._compile_cache[expr]
275
276 - def eval(self, expr, locals):
277 """Eval a python-eval-expression.
278
279 Sets ``self.locals_ptr`` to ``locales`` and compiles the code
280 before evaluating.
281 """
282
283 if expr[:len(substituteIdString)]==substituteIdString:
284 goOn=True
285 replacement=expr[len(substituteIdString):]
286 while goOn:
287 try:
288 value=replacement % locals
289 goOn=False
290 except KeyError:
291 e = sys.exc_info()[1]
292 kExpr="%("+e.args[0]+")"
293 replacement=replacement.replace(kExpr,"%"+kExpr)
294
295 return value
296
297
298 sav = self.locals_ptr
299 self.locals_ptr = locals
300 doEval=True
301
302 if expr[:len(execIdString)]==execIdString:
303 doEval=False
304
305 if doEval:
306 globals= {"__builtins__":self.eval_allowed_globals}
307 x = eval(self.compile(expr),globals, locals)
308 else:
309
310 globals= {"__builtins__":__builtins__}
311 expr=expr[len(execIdString):]
312 exec_(self.compile(expr,mode="exec"),globs=globals,locs=locals)
313 x = None
314 self.locals_ptr = sav
315 return x
316
318 """Class that allows the import of packages"""
321
323 """Works on template files. Does calculations between $$.
324 Lines that start with $$ contain definitions"""
325
326 - def __init__(self,
327 name=None,
328 content=None,
329 encoding="utf-8",
330 expressionDelimiter="|",
331 assignmentLineStart="$$",
332 specials=[],
333 renderer_class=None,
334 tolerantRender=False,
335 allowExec=False
336 ):
337 """Exactly one of the parameters must be specified
338 @param name: name of the template file.
339 @param content: Content of the template
340 @param expressionDelimiter: character/string that delimits expression strings.
341 @param assignmentLineStart: Start of a line that holds an assignment operation
342 @param allowExec: allow execution (and import). This is potentially unsafe
343 @param special: list with strings that leave expression untreated"""
344
345 self.expressionDelimiter=expressionDelimiter
346 self.assignmentLineStart=assignmentLineStart
347 self.specials=specials
348 self.allowExec=allowExec
349
350 super(TemplateFile,self).__init__(name=name,
351 content=content,
352 )
353
354 if renderer_class==None:
355 if tolerantRender:
356 class ConcreteTolerantRenderer(TolerantRenderer):
357 def __init__(self,evalfunc, escapefunc):
358 TolerantRenderer.__init__(self,
359 evalfunc,
360 escapefunc,filename=name)
361
362 renderer_class=ConcreteTolerantRenderer
363 else:
364 class ConcreteRenderWithFileName(RendererWithFilename):
365 def __init__(self,evalfunc, escapefunc):
366 RendererWithFilename.__init__(self,
367 evalfunc,
368 escapefunc,filename=name)
369
370 renderer_class=ConcreteRenderWithFileName
371
372 if allowExec:
373 sandbox=EvalPseudoSandboxWithMathWithImport
374 else:
375 sandbox=EvalPseudoSandboxWithMath
376
377 self.ptemplate=PyratempTemplate(string=self.template,
378 eval_class=sandbox,
379 renderer_class=renderer_class,
380 encoding=encoding,
381 escape=None
382 )
383
385 self.template=PyratempPreprocessor(assignmentLineStart=self.assignmentLineStart,
386 expressionDelimiter=self.expressionDelimiter,
387 specials=self.specials,
388 allowExec=self.allowExec
389 )(template)
390
392 """In the template, replaces all the strings between $$
393 with the evaluation of the expressions
394 @param vals: dictionary with the values
395 @returns: The string with the replaced expressions"""
396
397 return self.ptemplate(**vals)
398
399
400