<s> import os <EOL> import re <EOL> from . import SectionNotFoundError <EOL> class ConfigFileWriter ( object ) : <EOL> SECTION_REGEX = re . compile ( r'<STR_LIT>' ) <EOL> OPTION_REGEX = re . compile ( <EOL> r'<STR_LIT>' <EOL> r'<STR_LIT>' <EOL> r'<STR_LIT>' <EOL> ) <EOL> def update_config ( self , new_values , config_filename ) : <EOL> """<STR_LIT>""" <EOL> section_name = new_values . pop ( '<STR_LIT>' , '<STR_LIT:default>' ) <EOL> if not os . path . isfile ( config_filename ) : <EOL> self . _create_file ( config_filename ) <EOL> self . _write_new_section ( section_name , new_values , config_filename ) <EOL> return <EOL> with open ( config_filename , '<STR_LIT:r>' ) as f : <EOL> contents = f . readlines ( ) <EOL> try : <EOL> self . _update_section_contents ( contents , section_name , new_values ) <EOL> with open ( config_filename , '<STR_LIT:w>' ) as f : <EOL> f . write ( '<STR_LIT>' . join ( contents ) ) <EOL> except SectionNotFoundError : <EOL> self . _write_new_section ( section_name , new_values , config_filename ) <EOL> def _create_file ( self , config_filename ) : <EOL> dirname = os . path . split ( config_filename ) [ <NUM_LIT:0> ] <EOL> if not os . path . isdir ( dirname ) : <EOL> os . makedirs ( dirname ) <EOL> with os . fdopen ( os . open ( config_filename , <EOL> os . O_WRONLY | os . O_CREAT , <NUM_LIT> ) , '<STR_LIT:w>' ) : <EOL> pass <EOL> def _write_new_section ( self , section_name , new_values , config_filename ) : <EOL> with open ( config_filename , '<STR_LIT:a>' ) as f : <EOL> f . write ( '<STR_LIT>' % section_name ) <EOL> contents = [ ] <EOL> self . _insert_new_values ( line_number = <NUM_LIT:0> , <EOL> contents = contents , <EOL> new_values = new_values ) <EOL> f . write ( '<STR_LIT>' . join ( contents ) ) <EOL> def _find_section_start ( self , contents , section_name ) : <EOL> for i in range ( len ( contents ) ) : <EOL> line = contents [ i ] <EOL> if line . strip ( ) . startswith ( ( '<STR_LIT:#>' , '<STR_LIT:;>' ) ) : <EOL> continue <EOL> match = self . SECTION_REGEX . search ( line ) <EOL> if match is not None and self . _matches_section ( match , <EOL> section_name ) : <EOL> return i <EOL> raise SectionNotFoundError ( section_name ) <EOL> def _update_section_contents ( self , contents , section_name , new_values ) : <EOL> new_values = new_values . copy ( ) <EOL> section_start_line_num = self . _find_section_start ( contents , <EOL> section_name ) <EOL> last_matching_line = section_start_line_num <EOL> j = last_matching_line + <NUM_LIT:1> <EOL> while j < len ( contents ) : <EOL> line = contents [ j ] <EOL> if self . SECTION_REGEX . search ( line ) is not None : <EOL> self . _insert_new_values ( line_number = last_matching_line , <EOL> contents = contents , <EOL> new_values = new_values ) <EOL> return <EOL> match = self . OPTION_REGEX . search ( line ) <EOL> if match is not None : <EOL> last_matching_line = j <EOL> key_name = match . group ( <NUM_LIT:1> ) . strip ( ) <EOL> if key_name in new_values : <EOL> if not isinstance ( new_values [ key_name ] , dict ) : <EOL> option_value = new_values [ key_name ] <EOL> new_line = '<STR_LIT>' % ( key_name , option_value ) <EOL> contents [ j ] = new_line <EOL> del new_values [ key_name ] <EOL> else : <EOL> j = self . _update_subattributes ( <EOL> j , contents , new_values [ key_name ] , <EOL> len ( match . group ( <NUM_LIT:1> ) ) - len ( match . group ( <NUM_LIT:1> ) . lstrip ( ) ) ) <EOL> return <EOL> j += <NUM_LIT:1> <EOL> if new_values : <EOL> if not contents [ - <NUM_LIT:1> ] . endswith ( '<STR_LIT:\n>' ) : <EOL> contents . append ( '<STR_LIT:\n>' ) <EOL> self . _insert_new_values ( line_number = last_matching_line + <NUM_LIT:1> , <EOL> contents = contents , <EOL> new_values = new_values ) <EOL> def _update_subattributes ( self , index , contents , values , starting_indent ) : <EOL> index += <NUM_LIT:1> <EOL> for i in range ( index , len ( contents ) ) : <EOL> line = contents [ i ] <EOL> match = self . OPTION_REGEX . search ( line ) <EOL> if match is not None : <EOL> current_indent = len ( <EOL> match . group ( <NUM_LIT:1> ) ) - len ( match . group ( <NUM_LIT:1> ) . lstrip ( ) ) <EOL> key_name = match . group ( <NUM_LIT:1> ) . strip ( ) <EOL> if key_name in values : <EOL> option_value = values [ key_name ] <EOL> new_line = '<STR_LIT>' % ( '<STR_LIT:U+0020>' * current_indent , <EOL> key_name , option_value ) <EOL> contents [ i ] = new_line <EOL> del values [ key_name ] <EOL> if starting_indent == current_indent or self . SECTION_REGEX . search ( line ) is not None : <EOL> self . _insert_new_values ( i - <NUM_LIT:1> , contents , values , '<STR_LIT:U+0020>' ) <EOL> break <EOL> else : <EOL> if starting_indent != current_indent : <EOL> self . _insert_new_values ( i , contents , values , '<STR_LIT:U+0020>' ) <EOL> return i <EOL> def _insert_new_values ( self , line_number , contents , new_values , indent = '<STR_LIT>' ) : <EOL> new_contents = [ ] <EOL> for key , value in list ( new_values . items ( ) ) : <EOL> if isinstance ( value , dict ) : <EOL> subindent = indent + '<STR_LIT:U+0020>' <EOL> new_contents . append ( '<STR_LIT>' % ( indent , key ) ) <EOL> for subkey , subval in list ( value . items ( ) ) : <EOL> new_contents . append ( '<STR_LIT>' % ( subindent , subkey , <EOL> subval ) ) <EOL> else : <EOL> new_contents . append ( '<STR_LIT>' % ( indent , key , value ) ) <EOL> del new_values [ key ] <EOL> contents . insert ( line_number + <NUM_LIT:1> , '<STR_LIT>' . join ( new_contents ) ) <EOL> def _matches_section ( self , match , section_name ) : <EOL> parts = section_name . split ( '<STR_LIT:U+0020>' ) <EOL> unquoted_match = match . group ( <NUM_LIT:0> ) == '<STR_LIT>' % section_name <EOL> if len ( parts ) > <NUM_LIT:1> : <EOL> quoted_match = match . group ( <NUM_LIT:0> ) == '<STR_LIT>' % ( <EOL> parts [ <NUM_LIT:0> ] , '<STR_LIT:U+0020>' . join ( parts [ <NUM_LIT:1> : ] ) ) <EOL> return unquoted_match or quoted_match <EOL> return unquoted_match </s>
