def create_inp_build_instructions(inpA, inpB, path, filename, comments=''): """ pass in two inp file paths and produce a spreadsheet showing the differences found in each of the INP sections. These differences should then be used whenever we need to rebuild this model from the baseline reference model. Note: this should be split into a func that creates a overall model "diff" that can then be written as a BI file or used programmatically """ allsections_a = funcs.complete_inp_headers(inpA) modela = swmmio.Model(inpA) modelb = swmmio.Model(inpB) #create build insructions folder if not os.path.exists(path): os.makedirs(path) filepath = os.path.join(path, filename) + '.txt' # xlpath = os.path.join(path, filename) + '.xlsx' # excelwriter = pd.ExcelWriter(xlpath) # vc_utils.create_change_info_sheet(excelwriter, modela, modelb) problem_sections = [ '[TITLE]', '[CURVES]', '[TIMESERIES]', '[RDII]', '[HYDROGRAPHS]' ] with open(filepath, 'w') as newf: #write meta data metadata = { #'Baseline Model':modela.inp.path, #'ID':filename, 'Parent Models': { 'Baseline': { inpA: vc_utils.modification_date(inpA) }, 'Alternatives': { inpB: vc_utils.modification_date(inpB) } }, 'Log': { filename: comments } } #print metadata vc_utils.write_meta_data(newf, metadata) for section in allsections_a['order']: if section not in problem_sections: #calculate the changes in the current section changes = INPDiff(modela, modelb, section) data = pd.concat( [changes.removed, changes.added, changes.altered]) #vc_utils.write_excel_inp_section(excelwriter, allsections_a, section, data) vc_utils.write_inp_section( newf, allsections_a, section, data, pad_top=False, na_fill='NaN') #na fill fixes SNOWPACK blanks spaces issue
def search_for_duplicates(inp_path, verbose=False): """ scan an inp file and determine if any element IDs are duplicated in any section. Method: count the uniques and compare to total length """ headers = funcs.complete_inp_headers(inp_path)['headers'] dups_found = False for header, cols, in headers.items(): if cols != 'blob': df = dataframes.create_dataframeINP(inp_path, section=header) elements = df.index n_unique = len(elements.unique()) #number of unique elements n_total = len(elements) #total number of elements if verbose: print('{} -> (uniques, total) -> ({}, {})'.format( header, n_unique, n_total)) if n_unique != n_total: dups = ', '.join( df[df.index.duplicated()].index.unique().tolist()) print('duplicate found in {}\nsection: {}\n{}'.format( inp_path, header, dups)) dups_found = True return dups_found
def build(self, baseline_dir, target_path): """ build a complete INP file with the build instructions committed to a baseline model. """ basemodel = swmmio.Model(baseline_dir) allheaders = funcs.complete_inp_headers(basemodel.inp.path) #new_inp = os.path.join(target_dir, 'model.inp') with open (target_path, 'w') as f: for section in allheaders['order']: #check if the section is not in problem_sections and there are changes #in self.instructions and commit changes to it from baseline accordingly if (section not in problem_sections and allheaders['headers'][section] != 'blob' and section in self.instructions): #df of baseline model section basedf = create_dataframeINP(basemodel.inp.path, section) #grab the changes to changes = self.instructions[section] #remove elements that have alterations and or tagged for removal remove_ids = changes.removed.index | changes.altered.index new_section = basedf.drop(remove_ids) #add elements new_section = pd.concat([new_section, changes.altered, changes.added]) else: #section is not well understood or is problematic, just blindly copy new_section = create_dataframeINP(basemodel.inp.path, section=section) #write the section vc_utils.write_inp_section(f, allheaders, section, new_section)
def test_complete_headers(test_model): headers = functions.complete_inp_headers(test_model.inp.path) sections_in_inp = [ '[TITLE]', '[OPTIONS]', '[EVAPORATION]', '[RAINGAGES]', '[SUBCATCHMENTS]', '[SUBAREAS]', '[INFILTRATION]', '[JUNCTIONS]', '[OUTFALLS]', '[STORAGE]', '[CONDUITS]', '[PUMPS]', '[WEIRS]', '[XSECTIONS]', '[INFLOWS]', '[CURVES]', '[TIMESERIES]', '[REPORT]', '[TAGS]', '[MAP]', '[COORDINATES]', '[VERTICES]', '[Polygons]', '[SYMBOLS]' ] assert (all(section in headers['headers'] for section in sections_in_inp))
def inline_comments_in_inp(filepath, overwrite=False): """ with an existing INP file, shift any comments that have been placed above the element (behavoir from saving in GUI) and place them to the right, inline with the element. To improve readability """ newfilename = os.path.splitext( os.path.basename(filepath))[0] + '_unGUI.inp' newfilepath = os.path.join(os.path.dirname(filepath), newfilename) allheaders = complete_inp_headers(filepath) with open(filepath) as oldf: with open(newfilepath, 'w') as new: comment_concat = [ ] #to hold list of comments (handles multiline comments) current_section = allheaders['order'][0] for line in oldf: #determine what section we are in by noting when we pass double brackets if '[' and ']' in line: current_section = line.strip() #if line.count(';') == 1 and line.strip()[0]==';': if len(line.strip()) > 1: if line.strip()[0] == ';' and ''.join( line.strip()[:2]) != ';;': #print line.strip()[:2] #this is a comment bc first char is ; and there #seconf char is not (which would resember the header section) words = line.split() hdrs = allheaders['headers'][current_section].split( ) #headerrow.split() perc_match_to_header = float( len([x for x in words if x in hdrs])) / float( len(hdrs)) if perc_match_to_header <= 0.75: comment_concat.append(line.strip()) else: #print comment_concat #this row has data, tack any comment to the line end comment_string = '' if len(comment_concat) > 0: comment_string = r' '.join(comment_concat) newlinestring = line.strip() + comment_string + '\n' new.write(newlinestring) comment_concat = [] else: #write the short line new.write(line) #rename files and remove old if we should overwrite if overwrite: os.remove(filepath) os.rename(newfilepath, filepath)
def test_complete_headers(test_model): headers = functions.complete_inp_headers(test_model.inp.path) sections_in_inp = [ '[TITLE]', '[OPTIONS]', '[EVAPORATION]', '[RAINGAGES]', '[SUBCATCHMENTS]', '[SUBAREAS]', '[INFILTRATION]', '[JUNCTIONS]', '[OUTFALLS]', '[STORAGE]', '[CONDUITS]', '[PUMPS]', '[WEIRS]', '[XSECTIONS]', '[INFLOWS]', '[CURVES]', '[TIMESERIES]', '[REPORT]', '[TAGS]', '[MAP]', '[COORDINATES]', '[VERTICES]', '[Polygons]', '[SYMBOLS]' ] assert (all(section in headers['headers'] for section in sections_in_inp))
def test_complete_inp_headers(): headers = [ '[TITLE]', '[OPTIONS]', '[EVAPORATION]', '[JUNCTIONS]', '[OUTFALLS]', '[CONDUITS]', '[XSECTIONS]', '[DWF]', '[REPORT]', '[TAGS]', '[MAP]', '[COORDINATES]', '[VERTICES]', ] h1 = funcs.complete_inp_headers(MODEL_XSECTION_BASELINE) assert(all(h in h1['headers'] for h in headers)) assert(h1['order'] == headers)
def inline_comments_in_inp(filepath, overwrite=False): """ with an existing INP file, shift any comments that have been placed above the element (behavoir from saving in GUI) and place them to the right, inline with the element. To improve readability """ newfilename = os.path.splitext(os.path.basename(filepath))[0] + '_unGUI.inp' newfilepath = os.path.join(os.path.dirname(filepath), newfilename) allheaders = complete_inp_headers(filepath) with open(filepath) as oldf: with open(newfilepath, 'w') as new: comment_concat = [] #to hold list of comments (handles multiline comments) current_section = allheaders['order'][0] for line in oldf: #determine what section we are in by noting when we pass double brackets if '[' and ']' in line: current_section = line.strip() #if line.count(';') == 1 and line.strip()[0]==';': if len(line.strip()) > 1: if line.strip()[0]==';' and ''.join(line.strip()[:2]) != ';;': #print line.strip()[:2] #this is a comment bc first char is ; and there #seconf char is not (which would resember the header section) words = line.split() hdrs = allheaders['headers'][current_section].split()#headerrow.split() perc_match_to_header = float(len([x for x in words if x in hdrs])) / float(len(hdrs)) if perc_match_to_header <= 0.75: comment_concat.append(line.strip()) else: #print comment_concat #this row has data, tack any comment to the line end comment_string = '' if len(comment_concat) > 0: comment_string = r' '.join(comment_concat) newlinestring = line.strip() + comment_string + '\n' new.write(newlinestring) comment_concat = [] else: #write the short line new.write(line) #rename files and remove old if we should overwrite if overwrite: os.remove(filepath) os.rename(newfilepath, filepath)
def create_dataframeBI(bi_path, section='[CONDUITS]'): """ given a path to a biuld instructions file, create a dataframe of data in a given section """ headerdefs = funcs.complete_inp_headers(bi_path) headerlist = headerdefs['headers'][section].split() + [';', 'Comment', 'Origin'] tempfilepath = txt.extract_section_from_inp(bi_path, section, headerdefs=headerdefs, skipheaders=True) df = pd.read_table(tempfilepath, header=None, delim_whitespace=True, skiprows=[0], index_col=0, names=headerlist, comment=None) os.remove(tempfilepath) # clean up return df
def __init__(self, build_instr_file=None): #create a change object for each section that is different from baseline self.instructions = {} self.metadata = {} if build_instr_file: #read the instructions and create a dictionary of Change objects allheaders = funcs.complete_inp_headers(build_instr_file) instructions = {} for section in allheaders['order']: change = INPDiff(build_instr_file=build_instr_file, section=section) instructions.update({section:change}) self.instructions = instructions #read the meta data self.metadata = vc_utils.read_meta_data(build_instr_file)
def create_inp_build_instructions(inpA, inpB, path, filename, comments=''): """ pass in two inp file paths and produce a spreadsheet showing the differences found in each of the INP sections. These differences should then be used whenever we need to rebuild this model from the baseline reference model. Note: this should be split into a func that creates a overall model "diff" that can then be written as a BI file or used programmatically """ allsections_a = funcs.complete_inp_headers(inpA) modela = swmmio.Model(inpA) modelb = swmmio.Model(inpB) #create build insructions folder if not os.path.exists(path): os.makedirs(path) filepath = os.path.join(path, filename) + '.txt' # xlpath = os.path.join(path, filename) + '.xlsx' # excelwriter = pd.ExcelWriter(xlpath) # vc_utils.create_change_info_sheet(excelwriter, modela, modelb) problem_sections = ['[TITLE]', '[CURVES]', '[TIMESERIES]', '[RDII]', '[HYDROGRAPHS]'] with open (filepath, 'w') as newf: #write meta data metadata = { #'Baseline Model':modela.inp.path, #'ID':filename, 'Parent Models':{ 'Baseline':{inpA:vc_utils.modification_date(inpA)}, 'Alternatives':{inpB:vc_utils.modification_date(inpB)} }, 'Log':{filename:comments} } #print metadata vc_utils.write_meta_data(newf, metadata) for section in allsections_a['order']: if section not in problem_sections: #calculate the changes in the current section changes = INPDiff(modela, modelb, section) data = pd.concat([changes.removed, changes.added, changes.altered]) #vc_utils.write_excel_inp_section(excelwriter, allsections_a, section, data) vc_utils.write_inp_section(newf, allsections_a, section, data, pad_top=False, na_fill='NaN') #na fill fixes SNOWPACK blanks spaces issue
def create_dataframeINP(inp_path, section='[CONDUITS]', ignore_comments=True, comment_str=';', comment_cols=True): """ given a path to an INP file, create a dataframe of data in the given section. """ # find all the headers and their defs (section title with cleaned one-liner column headers) headerdefs = funcs.complete_inp_headers(inp_path) # create temp file with section isolated from inp file tempfilepath = txt.extract_section_from_inp(inp_path, section, headerdefs=headerdefs, ignore_comments=ignore_comments) if ignore_comments: comment_str = None if not tempfilepath: # if this head (section) was not found in the textfile, return a # blank dataframe with the appropriate schema print('header "{}" not found in "{}"'.format(section, inp_path)) print('returning empty dataframe') headerlist = headerdefs['headers'].get(section, 'blob').split() + [';', 'Comment', 'Origin'] blank_df = pd.DataFrame(data=None, columns=headerlist).set_index(headerlist[0]) return blank_df if headerdefs['headers'][section] == 'blob': # return the whole row, without specifc col headers df = pd.read_table(tempfilepath, delim_whitespace=False, comment=comment_str) elif section == '[CURVES]' or section == '[TIMESERIES]': # return the whole row, without specifc col headers df = pd.read_table(tempfilepath, delim_whitespace=False) # , index_col=0)#, skiprows=[0]) else: # this section header is recognized and will be organized into known columns headerlist = headerdefs['headers'][section].split() if comment_cols: headerlist = headerlist + [';', 'Comment', 'Origin'] df = pd.read_table(tempfilepath, header=None, delim_whitespace=True, skiprows=[0], index_col=0, names=headerlist, comment=comment_str) if comment_cols: # add new blank comment column after a semicolon column df[';'] = ';' os.remove(tempfilepath) return df.rename(index=str)
def __init__(self, build_instr_file=None): #create a change object for each section that is different from baseline self.instructions = {} self.metadata = {} if build_instr_file: #read the instructions and create a dictionary of Change objects allheaders = funcs.complete_inp_headers(build_instr_file) instructions = {} for section in allheaders['order']: change = Change(build_instr_file=build_instr_file, section=section) instructions.update({section: change}) self.instructions = instructions #read the meta data self.metadata = vc_utils.read_meta_data(build_instr_file)
def test_complete_inp_headers(): headers = [ '[TITLE]', '[OPTIONS]', '[EVAPORATION]', '[JUNCTIONS]', '[OUTFALLS]', '[CONDUITS]', '[XSECTIONS]', '[DWF]', '[REPORT]', '[TAGS]', '[MAP]', '[COORDINATES]', '[VERTICES]', ] h1 = funcs.complete_inp_headers(MODEL_XSECTION_BASELINE) assert (all(h in h1['headers'] for h in headers)) assert (h1['order'] == headers)
def search_for_duplicates(inp_path, verbose = False): """ scan an inp file and determine if any element IDs are duplicated in any section. Method: count the uniques and compare to total length """ headers = funcs.complete_inp_headers(inp_path)['headers'] dups_found = False for header, cols, in headers.items(): if cols != 'blob': df = dataframes.create_dataframeINP(inp_path, section=header) elements = df.index n_unique = len(elements.unique()) #number of unique elements n_total = len(elements) #total number of elements if verbose: print('{} -> (uniques, total) -> ({}, {})'.format(header, n_unique , n_total)) if n_unique != n_total: dups = ', '.join(df[df.index.duplicated()].index.unique().tolist()) print('duplicate found in {}\nsection: {}\n{}'.format(inp_path, header, dups)) dups_found = True return dups_found
def build(self, baseline_dir, target_path): """ build a complete INP file with the build instructions committed to a baseline model. """ basemodel = swmmio.Model(baseline_dir) allheaders = funcs.complete_inp_headers(basemodel.inp.filePath) #new_inp = os.path.join(target_dir, 'model.inp') with open(target_path, 'w') as f: for section in allheaders['order']: #check if the section is not in problem_sections and there are changes #in self.instructions and commit changes to it from baseline accordingly if (section not in problem_sections and allheaders['headers'][section] != 'blob' and section in self.instructions): #df of baseline model section basedf = create_dataframeINP(basemodel.inp, section) #grab the changes to changes = self.instructions[section] #remove elements that have alterations and or tagged for removal remove_ids = changes.removed.index | changes.altered.index new_section = basedf.drop(remove_ids) #add elements new_section = pd.concat( [new_section, changes.altered, changes.added]) else: #section is not well understood or is problematic, just blindly copy new_section = create_dataframeINP(basemodel.inp, section=section) #write the section vc_utils.write_inp_section(f, allheaders, section, new_section)
def extract_section_from_inp(filepath, sectionheader, cleanheaders=True, startfile=False, headerdefs=None, ignore_comments=False, return_string=False, skiprows=0, skipheaders=False): """ INPUT path to text file (inp, rpt, etc) and a text string matchig the section header of the to be extracted creates a new text file in the same directory as the filepath and returns the path to the new file. optionally inserts row at begining of file with one-line headers that are defined in swmmio.defs.sectionheaders (useful for creating dataframes) """ #headers = she.complete_inp_headers(inp)['headers'] if not headerdefs: allheaders = complete_inp_headers(filepath)['headers'] else: allheaders = headerdefs['headers'] with open(filepath) as f: startfound = False endfound = False #outFilePath = inp.dir + "\\" + inp.name + "_" + section + ".txt" wd = os.path.dirname(filepath) newfname = sectionheader + '_' + random_alphanumeric(6) outfilepath = os.path.join(wd, newfname + txt) out_string = '' #populate if we only want a string returned line_count = 0 with open(outfilepath, 'w') as newf: for line in f: if startfound and line.strip() in allheaders: endfound = True #print 'end found: {}'.format(line.strip()) break elif not startfound and sectionheader in line: startfound = True #replace line with usable headers if cleanheaders: if allheaders[sectionheader] != 'blob': line = allheaders[sectionheader] + '\n' else: line = sectionheader + '\n' if startfound: if ignore_comments: #ignore anything after a comment #THIS IS HACK GARBAGE if ';' in line: s = line.split(';')[0] + '\n' out_string += s #build the overall out string (optional use) newf.write(s) else: newf.write(line) out_string += line elif skipheaders: #check if we're at a inp header row with ';;' or the section #header e.g. [XSECTIONS]. If so, skip the row bc skipheader = True if line.strip()[:2] != ";;" and line.strip() != sectionheader: newf.write(line) out_string += line elif line_count >= skiprows: newf.write(line) out_string += line line_count += 1 if not startfound: #input section header was not found in the file os.remove(outfilepath) return None if return_string: #return a string rep of the extracted section os.remove(outfilepath) #not needed so delete (maybe wasteful to make in 1st place) return out_string if startfile: os.startfile(outfilepath) return outfilepath
def generate_inp_from_diffs(basemodel, inpdiffs, target_dir): """ create a new inp with respect to a baseline inp and changes instructed with a list of inp diff files (build instructions). This saves having to recalculate the differences of each model from the baseline whenever we want to combine versions. """ #step 1 --> combine the diff/build instructions allheaders = funcs.complete_inp_headers(basemodel.inp.filePath) combi_build_instr_file = os.path.join(target_dir, 'build_instructions.txt') newinp = os.path.join(target_dir, 'new.inp') with open(combi_build_instr_file, 'w') as f: for header in allheaders['order']: s = '' section_header_written = False for inp in inpdiffs: sect_s = None if not section_header_written: sect_s = text.extract_section_from_inp(inp, header, cleanheaders=False, return_string=True, skipheaders=False) section_header_written = True else: sect_s = text.extract_section_from_inp(inp, header, cleanheaders=False, return_string=True, skipheaders=True) if sect_s: #remove the extra space between data in the same table #coming from diffrent models. if sect_s[-2:] == '\n\n': #NOTE Check this section... s += sect_s[:-1] else: s += sect_s f.write(s + '\n') #step 2 --> clean up the new combined diff instructions df_dict = clean_inp_diff_formatting( combi_build_instr_file) #makes more human readable #step 3 --> create a new inp based on the baseline, with the inp_diff #instructions applied with open(newinp, 'w') as f: for section in allheaders['order']: print section if section not in problem_sections and allheaders['headers'][ section] != 'blob': #check if a changes from baseline spreadheet exists, and use this #information if available to create the changes array df = create_dataframeINP(basemodel.inp, section) df['Origin'] = '' #add the origin column if not there if section in df_dict: df_change = df_dict[section] ids_to_drop = df_change.loc[df_change['Comment'].isin( ['Removed', 'Altered'])].index df = df.drop(ids_to_drop) df = df.append(df_change.loc[df_change['Comment'].isin( ['Added', 'Altered'])]) new_section = df else: #blindly copy this section from the base model new_section = create_dataframeINP(basemodel.inp, section=section) #write the section into the inp file and the excel file vc_utils.write_inp_section(f, allheaders, section, new_section)
def generate_inp_from_diffs(basemodel, inpdiffs, target_dir): """ create a new inp with respect to a baseline inp and changes instructed with a list of inp diff files (build instructions). This saves having to recalculate the differences of each model from the baseline whenever we want to combine versions. NOTE THIS ISN'T USED ANYWHERE. DELETE ???? """ #step 1 --> combine the diff/build instructions allheaders = funcs.complete_inp_headers(basemodel.inp.path) combi_build_instr_file = os.path.join(target_dir, 'build_instructions.txt') newinp = os.path.join(target_dir, 'new.inp') with open (combi_build_instr_file, 'w') as f: for header in allheaders['order']: s = '' section_header_written = False for inp in inpdiffs: sect_s = None if not section_header_written: sect_s = text.extract_section_from_inp(inp, header, cleanheaders=False, return_string=True, skipheaders=False) section_header_written = True else: sect_s = text.extract_section_from_inp(inp, header, cleanheaders=False, return_string=True, skipheaders=True) if sect_s: #remove the extra space between data in the same table #coming from diffrent models. if sect_s[-2:] == '\n\n': #NOTE Check this section... s += sect_s[:-1] else: s += sect_s f.write(s + '\n') #step 2 --> clean up the new combined diff instructions # df_dict = clean_inp_diff_formatting(combi_build_instr_file) #makes more human readable #step 3 --> create a new inp based on the baseline, with the inp_diff #instructions applied with open (newinp, 'w') as f: for section in allheaders['order']: print(section) if section not in problem_sections and allheaders['headers'][section] != 'blob': #check if a changes from baseline spreadheet exists, and use this #information if available to create the changes array df = create_dataframeINP(basemodel.inp.path, section) df['Origin'] = '' #add the origin column if not there if section in df_dict: df_change = df_dict[section] ids_to_drop = df_change.loc[df_change['Comment'].isin(['Removed', 'Altered'])].index df = df.drop(ids_to_drop) df = df.append(df_change.loc[df_change['Comment'].isin(['Added', 'Altered'])]) new_section = df else: #blindly copy this section from the base model new_section = create_dataframeINP(basemodel.inp.path, section=section) #write the section into the inp file and the excel file vc_utils.write_inp_section(f, allheaders, section, new_section)
def replace_inp_section(inp_path, modified_section_header, new_data, overwrite=True): """ modify an existing model by passing in new data (Pandas Dataframe) and the section header that should be modified. This funciton will overwrite all data in the old section with the passed data """ tmpfilename = os.path.splitext(os.path.basename(inp_path))[0] + '_mod.inp' wd = os.path.dirname(inp_path) tmpfilepath = os.path.join(os.path.dirname(inp_path), tmpfilename) allheaders = complete_inp_headers(inp_path) basemodel = swmmio.Model(inp_path) with open(inp_path) as oldf: with open(tmpfilepath, 'w') as new: #create the companion excel file #create the MS Excel writer object # xlpath = os.path.join(wd, basemodel.inp.name + '_modified.xlsx') # excelwriter = pd.ExcelWriter(xlpath) # vc_utils.create_info_sheet(excelwriter, basemodel) #write each line as is from the original model until we find the #header of the section we wish to overwrite found_section = False found_next_section = False for line in oldf: if modified_section_header in line: #write the replacement data in the new file now vc_utils.write_inp_section(new, allheaders, modified_section_header, new_data, pad_top=False) found_section = True if (found_section and not found_next_section and line.strip() in allheaders['headers'] and modified_section_header != line.strip()): found_next_section = True new.write('\n\n') #add some space before the next section if found_next_section or not found_section: #write the lines from the original file #if we haven't found the section to modify. #if we have found the section and we've found the NEXT section #continue writing original file's lines new.write(line) if not found_section: #the header doesn't exist in the old model #so we should append it to the bottom of file vc_utils.write_inp_section(new, allheaders, modified_section_header, new_data) # excelwriter.save() #rename files and remove old if we should overwrite if overwrite: os.remove(inp_path) os.rename(tmpfilepath, inp_path) return swmmio.Model(inp_path)
def extract_section_from_inp(filepath, sectionheader, cleanheaders=True, startfile=False, headerdefs=None, ignore_comments=False, return_string=False, skiprows=0, skipheaders=False): """ INPUT path to text file (inp, rpt, etc) and a text string matchig the section header of the to be extracted creates a new text file in the same directory as the filepath and returns the path to the new file. optionally inserts row at begining of file with one-line headers that are defined in swmmio.defs.sectionheaders (useful for creating dataframes) """ #headers = she.complete_inp_headers(inp)['headers'] if not headerdefs: allheaders = complete_inp_headers(filepath)['headers'] else: allheaders = headerdefs['headers'] with open(filepath) as f: startfound = False endfound = False #outFilePath = inp.dir + "\\" + inp.name + "_" + section + ".txt" wd = os.path.dirname(filepath) newfname = sectionheader + '_' + random_alphanumeric(6) outfilepath = os.path.join(wd, newfname + txt) out_string = '' #populate if we only want a string returned line_count = 0 with open(outfilepath, 'w') as newf: for line in f: if startfound and line.strip() in allheaders: endfound = True #print 'end found: {}'.format(line.strip()) break elif not startfound and sectionheader in line: startfound = True #replace line with usable headers if cleanheaders: if allheaders[sectionheader] != 'blob': line = allheaders[sectionheader] + '\n' else: line = sectionheader + '\n' if startfound: if ignore_comments: #ignore anything after a comment #THIS IS HACK GARBAGE if ';' in line: s = line.split(';')[0] + '\n' out_string += s #build the overall out string (optional use) newf.write(s) else: newf.write(line) out_string += line elif skipheaders: #check if we're at a inp header row with ';;' or the section #header e.g. [XSECTIONS]. If so, skip the row bc skipheader = True if line.strip()[:2] != ";;" and line.strip( ) != sectionheader: newf.write(line) out_string += line elif line_count >= skiprows: newf.write(line) out_string += line line_count += 1 if not startfound: #input section header was not found in the file os.remove(outfilepath) return None if return_string: #return a string rep of the extracted section os.remove( outfilepath ) #not needed so delete (maybe wasteful to make in 1st place) return out_string if startfile: os.startfile(outfilepath) return outfilepath