1
2 """
3 Application class that implements pyFoamFromTemplate
4 """
5
6 import sys
7
8 from optparse import OptionGroup
9
10 from .PyFoamApplication import PyFoamApplication
11
12 from PyFoam.Basics.TemplateFile import TemplateFile,TemplateFileOldFormat
13 from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile
14
15 from .CommonPickledDataInput import CommonPickledDataInput
16 from .CommonTemplateFormat import CommonTemplateFormat
17
18 from PyFoam.ThirdParty.six import print_,iteritems
19
20 from os import path
21
22 -class FromTemplate(PyFoamApplication,
23 CommonPickledDataInput,
24 CommonTemplateFormat):
25 - def __init__(self,args=None,parameters={}):
26 description="""\
27 Generates a file from a template file. Usually the name of the
28 template file is the name of the file with the extension '.template'
29 (unless specified otherwise). The file is generated by replacing
30 everything in the template file that is enclosed by $ $ with
31 calculated expression. values are given in a Python-dictionary. Lines
32 in the template file that start with $$ are used as definitons for
33 intermediate expressions.
34
35 This format is used if the two arguments are used. If the template
36 file and the data is specified via options then a more advanced
37 template format that allows branches and loops is used via the
38 template-engine pyratemp (see
39 http://www.simple-is-better.org/template/pyratemp.html). If data is
40 read from a pickled-input then it looks for the keys "template" and "values" and
41 uses these.
42
43 In the new format expressions are delimited by |- at the start and -|
44 at the end. These defaults can be changed
45
46 @param parameters: Dictionary with parameters (only usable
47 when called from a script)
48 """
49
50 self.parameters=parameters.copy()
51
52 PyFoamApplication.__init__(self,
53 args=args,
54 description=description,
55 usage="%prog [options] (<file> <vals>|)",
56 nr=0,
57 changeVersion=False,
58 interspersed=True,
59 exactNr=False)
60
62 CommonPickledDataInput.addOptions(self)
63
64 inputs=OptionGroup(self.parser,
65 "Inputs",
66 "Inputs for the templating process")
67 self.parser.add_option_group(inputs)
68
69 inputs.add_option("--template-file",
70 action="store",
71 default=None,
72 dest="template",
73 help="Name of the template file. Also overwrites the standard for the old format (<filename>.template). If this is set to 'stdin' then the template is read from the standard-input to allow using the pipe into it.")
74 inputs.add_option("--values-string",
75 action="store",
76 default=None,
77 dest="values",
78 help="String with the values that are to be inserted into the template as a dictionaty in Python-format. If specified this is the first choice")
79 inputs.add_option("--values-dictionary",
80 action="store",
81 default=None,
82 dest="valuesDict",
83 help="Name of a dictionary-file in OpenFOAM-format. If this is unspecified too then values are taken from the pickled-input")
84 inputs.add_option("--no-defaults-file",
85 action="store_false",
86 default=True,
87 dest="useDefaults",
88 help="If a file with the same name as the template file but the extension '.defaults' is found then it is loaded before the other values are read. This option switches this off")
89
90 outputs=OptionGroup(self.parser,
91 "Outputs",
92 "Outputs of the templating process")
93 self.parser.add_option_group(outputs)
94 outputs.add_option("--stdout",
95 action="store_true",
96 dest="stdout",
97 default=False,
98 help="Doesn't write to the file, but outputs the result on stdout")
99 outputs.add_option("--dump-used-values",
100 action="store_true",
101 dest="dumpUsed",
102 default=False,
103 help="Print the used parameters")
104 outputs.add_option("--output-file",
105 action="store",
106 default=None,
107 dest="outputFile",
108 help="File to which the output will be written. Only for the new format")
109
110 CommonTemplateFormat.addOptions(self)
111
112 behaviour=OptionGroup(self.parser,
113 "Behaviour",
114 "The behaviour of the parser")
115 self.parser.add_option_group(behaviour)
116 behaviour.add_option("--tolerant-expression-evaluation",
117 action="store_true",
118 default=False,
119 dest="tolerantRender",
120 help="Instead of failing when encountering a problem during an evaluation a string with the error message is inserted into the output")
121 behaviour.add_option("--allow-exec-instead-of-assignment",
122 action="store_true",
123 default=False,
124 dest="allowExec",
125 help="Allows exectution of non-assignments in $$-lines. This is potentially unsafe as it allows 'import' and calling of external programs")
126
128 if self.opts.template=="stdin" and self.opts.pickledFileRead=="stdin":
129 self.error("Can't simultanously read pickled data and the tempalte from the standard input")
130
131 content=None
132 if self.opts.template=="stdin":
133 content=sys.stdin.read()
134 data=None
135 if self.opts.pickledFileRead:
136 data=self.readPickledData()
137 fName=None
138
139 if len(self.parser.getArgs())==2:
140 if self.opts.pickledFileRead:
141 self.error("old-format mode does not work with pickled input")
142 if self.opts.outputFile:
143 self.error("--output-file is not valid for the old format")
144
145 fName=self.parser.getArgs()[0]
146 vals=eval(self.parser.getArgs()[1])
147 if type(vals)==str:
148
149 vals=eval(vals)
150
151 if self.opts.template==None:
152 template=fName+".template"
153 else:
154 template=self.opts.template
155
156 if content:
157 t=TemplateFileOldFormat(content=content)
158 else:
159 t=TemplateFileOldFormat(name=template)
160 elif len(self.parser.getArgs())==0:
161 if self.opts.template==None and self.opts.outputFile!=None and self.opts.outputFile!="stdin":
162 self.opts.template=self.opts.outputFile+".template"
163 self.warning("Automatically setting template to",self.opts.template)
164 vals={}
165 if self.opts.useDefaults and self.opts.template!=None and self.opts.template!="stdin":
166 name,ext=path.splitext(self.opts.template)
167 defaultName=name+".defaults"
168 if path.exists(defaultName):
169 self.warning("Reading default values from",defaultName)
170 vals=ParsedParameterFile(defaultName,
171 noHeader=True,
172 doMacroExpansion=True).getValueDict()
173
174 vals.update(self.parameters)
175
176 if self.opts.values:
177 vals.update(eval(self.opts.values))
178 elif self.opts.valuesDict:
179 vals.update(ParsedParameterFile(self.opts.valuesDict,
180 noHeader=True,
181 doMacroExpansion=True).getValueDict())
182 elif data:
183 vals.update(data["values"])
184 elif len(self.parameters)==0:
185 self.error("Either specify the values with --values-string or --values-dictionary or in the pickled input data")
186
187 if self.opts.dumpUsed:
188 maxLen=max([len(k) for k in vals.keys()])
189 formatString=" %%%ds | %%s" % maxLen
190 print_("Used values")
191 print_(formatString % ("Name","Value"))
192 print_("-"*(maxLen+30))
193 for k,v in iteritems(vals):
194 print_(formatString % (k,v))
195
196 if content:
197 t=TemplateFile(content=content,
198 tolerantRender=self.opts.tolerantRender,
199 allowExec=self.opts.allowExec,
200 expressionDelimiter=self.opts.expressionDelimiter,
201 assignmentLineStart=self.opts.assignmentLineStart)
202 elif data:
203 t=TemplateFile(content=data["template"],
204 tolerantRender=self.opts.tolerantRender,
205 allowExec=self.opts.allowExec,
206 expressionDelimiter=self.opts.expressionDelimiter,
207 assignmentLineStart=self.opts.assignmentLineStart)
208 elif self.opts.template:
209 t=TemplateFile(name=self.opts.template,
210 tolerantRender=self.opts.tolerantRender,
211 allowExec=self.opts.allowExec,
212 expressionDelimiter=self.opts.expressionDelimiter,
213 assignmentLineStart=self.opts.assignmentLineStart)
214 else:
215 self.error("Template unspecified")
216
217 if self.opts.outputFile:
218 fName=self.opts.outputFile
219 else:
220 self.error("Either specify 2 arguments (file and values) for old format or no arguments for the new format")
221
222 if self.opts.stdout:
223 print_(t.getString(vals))
224 elif fName:
225 try:
226 t.writeToFile(fName,vals)
227 except (NameError,SyntaxError):
228 e = sys.exc_info()[1]
229 print_("While processing file",fName)
230 raise e
231 else:
232 self.error("No destination for the output specified")
233
234
235