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 assignmentDebug=None,
66 specials=[]):
67 """Create the regexp once for performance reasons
68 @param dovarline: look for variable lines that start with $$
69 @param doexpr: substitute expressions that are between $
70 @param expressionDelimiter: character/string that is used before and after an
71 expression. After the expression the reverse of the string is used
72 @param assignmentLineStart: character sequence that signals an assignment line
73 @param assignmentDebug: Add a commented line to debug assignments. Prefix used is this parameter
74 @param allowExec: allows execution of code. This is potentially unsafe
75 @param specials: a list. If any expression starts with one of these values then
76 the full expression (including delimiters) is left verbatim in the template"""
77
78 self.clip=len(expressionDelimiter)
79 self.specials=specials
80
81 tmp=list(expressionDelimiter)
82 tmp.reverse()
83
84 self.expressionDelimiter=re.escape(expressionDelimiter)
85 self.expressionDelimiterEnd=re.escape("".join(tmp))
86 self.expressionDelimiterRaw=expressionDelimiter
87 self.expressionDelimiterEndRaw="".join(tmp)
88
89
90
91 self.assignmentLineStart=assignmentLineStart
92 self.assignmentDebug=assignmentDebug
93
94 self.expr=re.compile("%s[^$!\n]+?%s" % (self.expressionDelimiter,self.expressionDelimiterEnd))
95 self.dovarline=dovarline
96 self.doexpr=doexpr
97
98 self.allowExec=allowExec
99
101 """This does the actual work"""
102
103 if len(original)==0:
104 return original
105
106 lines=original.split("\n")
107 if lines[-1]=="":
108 lines=lines[:-1]
109
110 result=""
111
112 for l in lines:
113 if l[:len(self.assignmentLineStart)]==self.assignmentLineStart and self.dovarline:
114 tmp=l[len(self.assignmentLineStart):].split("=")
115 if len(tmp)!=2:
116 if self.allowExec:
117 execString=l[len(self.assignmentLineStart):].replace("\\","\\\\").replace("\"","\\\"")
118 result+='$!setvar("%s", "%s")!$#!' % (
119 "dummyVarForExecution",
120 execIdString+execString.strip()
121 )
122 result+="\n"
123 else:
124 error("Each definition must be of the form: <name>=<value>",
125 "The string",l,"is not")
126 else:
127
128
129 exprStr=tmp[1].replace("\\","\\\\").replace("\"","\\\"")
130 result+='$!setvar("%s", "%s")!$#!' % (tmp[0].strip(),exprStr.strip())
131 result+="\n"
132 if self.assignmentDebug and self.doexpr:
133 l=self.assignmentDebug+" "+tmp[0].strip()+" "+self.expressionDelimiterRaw+tmp[0].strip()+self.expressionDelimiterEndRaw
134 else:
135 continue
136 if self.doexpr:
137 nl=""
138 iStart=0
139 for m in self.expr.finditer(l):
140 inner=l[m.start()+self.clip:m.end()-self.clip]
141 hasSpecial=False
142 nl+=l[iStart:m.start()]
143 for k in self.specials:
144 if len(k)<=len(inner):
145 if inner[:len(k)]==k:
146 hasSpecial=True
147 substVarName="dummyVarForSubstitution"
148
149 nl+='$!setvar("%s", "%s")!$#!\n' % (
150 substVarName,
151 substituteIdString+l[m.start():m.end()]
152 )
153 nl+='$!'+substVarName+'!$'
154
155 if not hasSpecial:
156 nl+="$!"+inner+"!$"
157 iStart=m.end()
158 result+=nl+l[iStart:]+"\n"
159 else:
160 result+=l+"\n"
161
162
163 if original[-1]!='\n' and result[-1]=='\n':
164 result=result[:-1]
165
166 return result
167
255
257 """Add mathematical functions to the valid functons"""
259 EvalPseudoSandbox.__init__(self)
260 import math
261 for o in dir(math):
262 if o[0]!="_":
263 self.register(o,getattr(math,o))
264
265 from PyFoam.ThirdParty.six.moves import builtins as __builtin__
266 self.register("set",__builtin__.set)
267
268 if allowExec:
269 del self.eval_allowed_globals["__import__"]
270 self.register("__import__",__builtins__["__import__"])
271
272 - def compile(self, expr,mode="eval"):
273 """Compile a python-eval-expression. Overrides the default implementation
274 to allow '_[1]' as a valid name
275 """
276 if expr not in self._compile_cache:
277 c = compile(expr, "", mode)
278 for i in c.co_names:
279 if i[0] == '_':
280 if i[1]!='[' or i[-1]!=']':
281 raise NameError("Name '%s' is not allowed." %(i))
282 self._compile_cache[expr] = c
283 return self._compile_cache[expr]
284
285 - def eval(self, expr, locals):
286 """Eval a python-eval-expression.
287
288 Sets ``self.locals_ptr`` to ``locales`` and compiles the code
289 before evaluating.
290 """
291
292 if expr[:len(substituteIdString)]==substituteIdString:
293 goOn=True
294 replacement=expr[len(substituteIdString):]
295 while goOn:
296 try:
297 value=replacement % locals
298 goOn=False
299 except KeyError:
300 e = sys.exc_info()[1]
301 kExpr="%("+e.args[0]+")"
302 replacement=replacement.replace(kExpr,"%"+kExpr)
303
304 return value
305
306
307 sav = self.locals_ptr
308 self.locals_ptr = locals
309 doEval=True
310
311 if expr[:len(execIdString)]==execIdString:
312 doEval=False
313
314 if doEval:
315 globals= {"__builtins__":self.eval_allowed_globals}
316 x = eval(self.compile(expr),globals, locals)
317 else:
318
319 globals= {"__builtins__":__builtins__}
320 expr=expr[len(execIdString):]
321 exec_(self.compile(expr,mode="exec"),globs=globals,locs=locals)
322 x = None
323 self.locals_ptr = sav
324 return x
325
327 """Class that allows the import of packages"""
330
332 """Works on template files. Does calculations between $$.
333 Lines that start with $$ contain definitions"""
334
335 - def __init__(self,
336 name=None,
337 content=None,
338 encoding="utf-8",
339 expressionDelimiter="|",
340 assignmentLineStart="$$",
341 assignmentDebug=None,
342 specials=[],
343 renderer_class=None,
344 tolerantRender=False,
345 allowExec=False
346 ):
347 """Exactly one of the parameters must be specified
348 @param name: name of the template file.
349 @param content: Content of the template
350 @param expressionDelimiter: character/string that delimits expression strings.
351 @param assignmentLineStart: Start of a line that holds an assignment operation
352 @param assignmentDebug: Add a commented line to debug assignments. Prefix used is this parameter
353 @param allowExec: allow execution (and import). This is potentially unsafe
354 @param special: list with strings that leave expression untreated"""
355
356 self.expressionDelimiter=expressionDelimiter
357 self.assignmentLineStart=assignmentLineStart
358 self.assignmentDebug=assignmentDebug
359 self.specials=specials
360 self.allowExec=allowExec
361
362 super(TemplateFile,self).__init__(name=name,
363 content=content,
364 )
365
366 if renderer_class==None:
367 if tolerantRender:
368 class ConcreteTolerantRenderer(TolerantRenderer):
369 def __init__(self,evalfunc, escapefunc):
370 TolerantRenderer.__init__(self,
371 evalfunc,
372 escapefunc,filename=name)
373
374 renderer_class=ConcreteTolerantRenderer
375 else:
376 class ConcreteRenderWithFileName(RendererWithFilename):
377 def __init__(self,evalfunc, escapefunc):
378 RendererWithFilename.__init__(self,
379 evalfunc,
380 escapefunc,filename=name)
381
382 renderer_class=ConcreteRenderWithFileName
383
384 if allowExec:
385 sandbox=EvalPseudoSandboxWithMathWithImport
386 else:
387 sandbox=EvalPseudoSandboxWithMath
388
389 self.ptemplate=PyratempTemplate(string=self.template,
390 eval_class=sandbox,
391 renderer_class=renderer_class,
392 encoding=encoding,
393 escape=None
394 )
395
397 self.template=PyratempPreprocessor(assignmentLineStart=self.assignmentLineStart,
398 expressionDelimiter=self.expressionDelimiter,
399 assignmentDebug=self.assignmentDebug,
400 specials=self.specials,
401 allowExec=self.allowExec
402 )(template)
403
405 """In the template, replaces all the strings between $$
406 with the evaluation of the expressions
407 @param vals: dictionary with the values
408 @returns: The string with the replaced expressions"""
409
410 return self.ptemplate(**vals)
411
412
413