The pass loop moves the identifier list, input and output file lists, and table of contents from the pass frame to the master frame after each pass. This permits this data to be read by the next pass (while it is also regenerating the data for the pass after that).
Conceptually, the loop is said to converge when this data is the same twice in a row. However we do not test this yet because the state information is not complete.
To be complete, it must determine whether the input and output files have changed between passes. This will be done by comparing the file lists, and comparing the last modification dates on the files between passes.
Finally, output to simple files will be ignored. It is necessary to also add user controlled hooks into the convergence tests, because user script can have arbitrary side effects.
171: #line 216 "master_frame.ipk" 172: def run_passes(self, skiplist): 173: #print 'STARTING PASSES' 174: for passno in range(self.passes): 175: converged = self.process_pass(passno, skiplist) 176: if converged: break 177: #print 'FINISHED PASSES' 178: self.persistent_frames['options']=self.argument_frame.__dict__ 179: self.persistent_frames['include files']=self.include_files 180: self.persistent_frames['converged']=converged 181: if self.usecache: 182: try: 183: #print 'WRITING CACHE' 184: cache = self.platform.open(self.cache_name,'w') 185: pickle.dump(self.persistent_frames, cache) 186: cache.close() 187: del cache 188: except KeyboardInterrupt: raise 189: except: 190: print 'Pickle FAILURE saving cache',self.cache_name 191: if 'cache' in self.process.trace: 192: self.dump_cache() 193: 194: def __del__(self): 195: if 'frames' in self.process.trace: 196: self.process.release_object(self) 197: 198: def get_master_frame(self): 199: "Get the current master frame" 200: return self 201: 202: def get_persistent_frame(self, seq): 203: "Get the persistent frame object with given index" 204: if not self.persistent_frames.has_key(seq): 205: self.persistent_frames[seq]={} 206: return self.persistent_frames[seq] 207: 208: def set_title(self, title, **trlat): 209: "Specify the document title" 210: self.persistent_frames['title'] = title 211: apply(add_translation,(title,),trlat) 212: 213: def add_author(self, author, **data): 214: "Add an author to the list of document authors" 215: if not self.persistent_frames.has_key('authors'): 216: self.persistent_frames['authors']={} 217: if not self.persistent_frames['authors'].has_key(author): 218: self.persistent_frames['authors'][author]={} 219: self.persistent_frames['authors'][author].update(data) 220: 221: def get_title(self): 222: "Get the current document title" 223: return self.persistent_frames.get('title',None) 224: 225: def set_native_language(self, language): 226: "Set the native language in which this document is written" 227: self.persistent_frames['native_language']=language 228: 229: def get_native_language(self): 230: "Get the native language in which this document is written" 231: return self.persistent_frames.get('native_language','en') 232: 233: def set_document_data(self, key, data): 234: "Save some data under a key in the persistent store" 235: self.persistent_frames[key]=data 236: 237: def get_document_data(self,key): 238: "Retrive some data using a key from the persistent store" 239: return self.persistent_frames.get(key,None) 240: 241: def dump_cache(self): 242: "Dump out the persistent store to standard output" 243: print '--- CACHE DUMP ------------------------------', 244: self.dump_dict(self.persistent_frames, 0) 245: print 246: 247: def dump_sequence(self,s, level): 248: for entry in s[:-1]: 249: print 250: print ' ' * (level * 2), 251: self.dump_entry(entry,level) 252: print ',', 253: if len(s)>0: 254: print 255: print ' ' * (level * 2), 256: self.dump_entry(s[-1],level) 257: 258: def dump_dict(self,d, level): 259: keys = d.keys() 260: keys.sort() 261: for key in keys[:-1]: 262: print 263: if level == 0: print 264: print ' '*(level*2)+str(key),':', 265: v = d[key] 266: self.dump_entry(v, level) 267: print ',', 268: if len(keys)>0: 269: print 270: key = keys[-1] 271: print ' '*(level*2)+str(key),':', 272: v = d[key] 273: self.dump_entry(v, level) 274: 275: def dump_entry(self,e,level): 276: t = type(e) 277: if t is types.DictType: 278: print '<dict>', 279: self.dump_dict(e,level+1) 280: elif t is types.TupleType: 281: print '<tuple>', 282: self.dump_sequence(e, level+1) 283: elif t is types.ListType: 284: print '<list>', 285: self.dump_sequence(e, level+1) 286: else: 287: print repr(e), 288: 289: def process_pass(self, passno, skiplist): 290: curpass = pass_frame(self, passno, skiplist) 291: self.ids = curpass.ids # idlist 292: self.ftp_list = curpass.ftp_list # ftp list 293: self.flist = curpass.flist # output file list 294: self.iflist = curpass.iflist # input file list 295: self.toc = curpass.toc # table of contents 296: self.include_files = curpass.include_files # include files 297: self.classes = curpass.classes # classes 298: self.functions = curpass.functions # functions 299: self.tests = curpass.tests # functions 300: self.section_index = curpass.section_index # functions 301: 302: if self.sequence_limit == -1: 303: self.sequence_limit = curpass.sequence 304: elif self.sequence_limit != curpass.sequence: 305: print 'WARNING: SEQUENCE COUNTER DISPARITY BETWEEN PASSES' 306: fdict = curpass.fdict 307: del curpass 308: return self.check_convergence(passno, fdict) 309: 310: def check_convergence(self, passno, ds): 311: dd = self.fdict 312: 313: file_count = 0 314: stable_file_count = 0 315: unstable_file_count = 0 316: new_file_count = 0 317: for k in ds.keys(): 318: file_count = file_count + 1 319: #print 'Checking file',file_count,':',k,'Status',ds[k] 320: if not dd.has_key(k): 321: dd[k]=(ds[k],passno) 322: 323: if ds[k]=='original': 324: new_file_count = new_file_count + 1 325: elif ds[k]=='unchanged': 326: stable_file_count = stable_file_count + 1 327: else: 328: unstable_file_count = unstable_file_count + 1 329: if ds[k]!='unchanged' or dd[k][0]!='unchanged': 330: dd[k]=(ds[k],passno) 331: converged = file_count == stable_file_count 332: if converged: 333: print 'All',file_count,'output files stable on pass',passno+1,' -- breaking' 334: else: 335: print 'Pass',passno+1,'status: <not converged>' 336: print ' Files :',file_count 337: print ' New :',new_file_count 338: print ' Changed :',unstable_file_count 339: print ' Unchanged:',stable_file_count 340: return converged 341: 342: