Package PyFoam :: Package Applications :: Module UpdateDictionary
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.Applications.UpdateDictionary

  1  #  ICE Revision: $Id$ 
  2  """ 
  3  Application class that implements pyFoamUpdateDictionary.py 
  4  """ 
  5   
  6  import sys 
  7   
  8  import re 
  9  from os import path 
 10   
 11  from .PyFoamApplication import PyFoamApplication 
 12   
 13  from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile 
 14  from PyFoam.Basics.DataStructures import DictProxy,TupleProxy 
 15   
 16  from PyFoam.Error import error,warning 
 17   
 18  from .CommonParserOptions import CommonParserOptions 
 19   
 20  from PyFoam.Basics.TerminalFormatter import TerminalFormatter 
 21   
 22  from PyFoam.ThirdParty.six import print_ 
 23  from PyFoam.ThirdParty.six.moves import input 
 24   
 25  f=TerminalFormatter() 
 26  f.getConfigFormat("source",shortName="src") 
 27  f.getConfigFormat("destination",shortName="dst") 
 28  f.getConfigFormat("difference",shortName="diff") 
 29  f.getConfigFormat("question",shortName="ask") 
 30  f.getConfigFormat("input") 
 31   
32 -class UpdateDictionary(PyFoamApplication, 33 CommonParserOptions):
34 - def __init__(self,args=None):
35 description="""\ 36 Takes two dictionary and modifies the second one after the example of 37 the first. If the dictionaries do not have the same name, it looks for 38 the destination file by searching the equivalent place in the 39 destination case 40 """ 41 42 PyFoamApplication.__init__(self, 43 args=args, 44 description=description, 45 usage="%prog [options] <source> <destination-case>", 46 nr=2, 47 changeVersion=False, 48 interspersed=True)
49
50 - def addOptions(self):
51 self.parser.add_option("--interactive", 52 action="store_true", 53 default=True, 54 dest="interactive", 55 help="Asks the user before applying changes") 56 57 self.parser.add_option("--batch", 58 action="store_false", 59 default=True, 60 dest="interactive", 61 help="Don't ask the user before applying changes") 62 63 self.parser.add_option("--clear-unused", 64 action="store_true", 65 default=False, 66 dest="clear", 67 help="Removes all the dictionary entries that are not in the source") 68 69 self.parser.add_option("--add-missing", 70 action="store_true", 71 default=False, 72 dest="add", 73 help="Add all the dictionary entries that are not in the destination") 74 75 self.parser.add_option("--append-lists", 76 action="store_true", 77 default=False, 78 dest="append", 79 help="Append to lists if they are shorter than the original") 80 81 self.parser.add_option("--shorten-lists", 82 action="store_true", 83 default=False, 84 dest="shorten", 85 help="Shortens lists if they are longer than the original") 86 87 self.parser.add_option("--all", 88 action="store_true", 89 default=False, 90 dest="all", 91 help="Do all the editing commands: clear, add, shorten and append") 92 93 self.parser.add_option("--test", 94 action="store_true", 95 default=False, 96 dest="test", 97 help="Does not write the file but only prints it to the screen") 98 99 self.parser.add_option("--not-equal", 100 action="store_true", 101 default=False, 102 dest="notequal", 103 help="Allow source and destination to have different names") 104 105 self.parser.add_option("--verbose", 106 action="store_true", 107 default=False, 108 dest="verbose", 109 help="Print every change that is being made") 110 111 self.parser.add_option("--min-recursion", 112 action="store", 113 default=0, 114 type="int", 115 dest="min", 116 help="Minimum depth of the recursive decent into dictionaries at which 'editing' should start (default: %default)") 117 118 self.parser.add_option("--max-recursion", 119 action="store", 120 default=100, 121 type="int", 122 dest="max", 123 help="Maximum depth of the recursive decent into dictionaries (default: %default)") 124 125 CommonParserOptions.addOptions(self)
126
127 - def ask(self,*question):
128 if not self.opts.interactive: 129 return False 130 else: 131 print_(f.ask,"QUESTION:",end="") 132 for q in question: 133 print_(q,end="") 134 135 answer=None 136 while answer!="y" and answer!="n": 137 answer=input(f.reset+f.ask+" [Y]es or [N]no ? "+f.input).strip()[0].lower() 138 print_(f.reset,end="") 139 return answer=="y"
140
141 - def workList(self,source,dest,depth):
142 if depth>self.opts.max: 143 if self.opts.verbose: 144 print_("- "*depth,"Recursion ended") 145 return 146 147 for i in range(min(len(source),len(dest))): 148 if type(source[i])==type(dest[i]) and type(source[i]) in [dict,DictProxy]: 149 if self.opts.verbose: 150 print_("- "*depth,"Entering dict nr.",i) 151 self.workDict(source[i],dest[i],depth+1) 152 if self.opts.verbose: 153 print_("- "*depth,"Leaving dict nr.",i) 154 elif type(source[i])==type(dest[i]) and type(source[i]) in [tuple,TupleProxy,list]: 155 if self.opts.verbose: 156 print_("- "*depth,"Entering tuple nr.",i) 157 self.workList(source[i],dest[i],depth+1) 158 if self.opts.verbose: 159 print_("- "*depth,"Leaving tuple nr.",i) 160 elif self.opts.interactive: 161 if source[i]!=dest[i]: 162 if self.ask("Replace for index",i,"the value",dest[i],"with the value",source[i]): 163 dest[i]=source[i] 164 165 if len(source)<len(dest) and self.opts.shorten: 166 if self.ask("Clip [",len(source),":] with the values ",dest[len(source):],"from the list"): 167 if self.opts.verbose: 168 print_("- "*depth,"Clipping",len(dest)-len(source),"entries starting with",len(source)) 169 dest=dest[0:len(source)] 170 elif len(source)>len(dest) and self.opts.append: 171 if self.ask("Append [",len(dest),":] with the values ",source[len(dest):],"to the list"): 172 if self.opts.verbose: 173 print_("- "*depth,"Appending",len(source)-len(dest),"entries starting with",len(dest)) 174 dest+=source[len(dest):]
175
176 - def workDict(self,source,dest,depth):
177 if depth>self.opts.max: 178 if self.opts.verbose: 179 print_("- "*depth,"Recursion ended") 180 return 181 182 if depth>=self.opts.min: 183 doIt=True 184 else: 185 doIt=False 186 187 for name in source: 188 if name not in dest: 189 if self.opts.add and doIt: 190 if self.ask("Add the key",name,"with value",source[name]): 191 if self.opts.verbose: 192 print_("- "*depth,"Adding",name) 193 dest[name]=source[name] 194 elif type(source[name]) in [dict,DictProxy]: 195 if type(dest[name]) not in [dict,DictProxy]: 196 error("Entry",name,"is not a dictionary in destination (but in source)") 197 if self.opts.verbose: 198 print_("- "*depth,"Entering dict ",name) 199 self.workDict(source[name],dest[name],depth+1) 200 if self.opts.verbose: 201 print_("- "*depth,"Leaving dict ",name) 202 elif type(source[name])==type(dest[name]) and type(dest[name]) in [tuple,TupleProxy,list]: 203 if self.opts.verbose: 204 print_("- "*depth,"Entering tuple ",name) 205 self.workList(source[name],dest[name],depth+1) 206 if self.opts.verbose: 207 print_("- "*depth,"Leaving tuple ",name) 208 elif self.opts.interactive: 209 if source[name]!=dest[name]: 210 if self.ask("Replace for key",name,"the value",dest[name],"with the value",source[name]): 211 dest[name]=source[name] 212 else: 213 if self.opts.verbose: 214 print_("- "*depth,"Nothing done for",name) 215 216 if self.opts.clear and doIt: 217 weg=[] 218 for name in dest: 219 if name not in source: 220 weg.append(name) 221 222 for name in weg: 223 if self.ask("Remove the key",name,"with the value",dest[name]): 224 if self.opts.verbose: 225 print_("- "*depth,"Removing",name) 226 del dest[name]
227
228 - def run(self):
229 sName=path.abspath(self.parser.getArgs()[0]) 230 dName=path.abspath(self.parser.getArgs()[1]) 231 232 if self.opts.all: 233 self.opts.append=True 234 self.opts.shorten=True 235 self.opts.add=True 236 self.opts.clear=True 237 238 try: 239 source=ParsedParameterFile(sName, 240 backup=False, 241 debug=self.opts.debugParser, 242 noBody=self.opts.noBody, 243 noHeader=self.opts.noHeader, 244 boundaryDict=self.opts.boundaryDict, 245 listDict=self.opts.listDict, 246 listDictWithHeader=self.opts.listDictWithHeader) 247 except IOError: 248 e = sys.exc_info()[1] # Needed because python 2.5 does not support 'as e' 249 self.error("Problem with file",sName,":",e) 250 251 if not self.opts.notequal and path.basename(sName)!=path.basename(dName): 252 found=False 253 parts=sName.split(path.sep) 254 for i in range(len(parts)): 255 tmp=path.join(*[dName]+parts[-(i+1):]) 256 257 if path.exists(tmp): 258 found=True 259 dName=tmp 260 warning("Found",dName,"and using this") 261 break 262 263 if not found: 264 error("Could not find a file named",path.basename(sName),"in",dName) 265 266 if path.samefile(sName,dName): 267 error("Source",sName,"and destination",dName,"are the same") 268 269 try: 270 dest=ParsedParameterFile(dName, 271 backup=False, 272 debug=self.opts.debugParser, 273 noBody=self.opts.noBody, 274 noHeader=self.opts.noHeader, 275 boundaryDict=self.opts.boundaryDict, 276 listDict=self.opts.listDict, 277 listDictWithHeader=self.opts.listDictWithHeader) 278 except IOError: 279 e = sys.exc_info()[1] # Needed because python 2.5 does not support 'as e' 280 self.error("Problem with file",dName,":",e) 281 282 dCase=dest.getCaseDir() 283 284 if self.opts.interactive: 285 self.opts.verbose=True 286 287 if not self.opts.boundaryDict and not self.opts.listDict and not self.opts.listDictWithHeader: 288 self.workDict(source.content,dest.content,1) 289 else: 290 self.workList(source.content,dest.content,1) 291 292 if self.opts.test or self.opts.interactive: 293 print_(str(dest)) 294 295 if not self.opts.test and self.ask("\n Write this file to disk"): 296 dest.writeFile() 297 if dCase!=None: 298 self.addToCaseLog(dCase,"Source",sName,"Destination:",dName)
299 300 # Should work with Python3 and Python2 301