#NEWLINE# def compare_config( config_paths ) : #NEWLINE# #INDENT# 'Prints out keys that are provided in at least two of the specified config_paths.\n\n  Emits a faux pants.ini-like output:\n\n  [section]\n  key: val1  # file1\n       val2  # file2\n       val3  # file3\n  ...\n  ' #NEWLINE# def load_config( p ) : #NEWLINE# #INDENT# "We need direct access to the underlying configparser, so we don't load via Config." #NEWLINE# cp = Config . _create_parser ( ) #NEWLINE# with open ( p , 'r' ) as ini : #NEWLINE# #INDENT# cp . readfp ( ini ) #NEWLINE# #UNINDENT# return cp #NEWLINE# #UNINDENT# configs = [ load_config ( path ) for path in config_paths ] #NEWLINE# def get_keys( c , s ) : #NEWLINE# #INDENT# 'Return all keys provided in section s of config c.' #NEWLINE# if ( s == 'DEFAULT' ) : #NEWLINE# #INDENT# return [ k for k in c . _defaults . keys ( ) ] #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if c . has_section ( s ) : #NEWLINE# #INDENT# return [ k for k in c . _sections [ section ] . keys ( ) if ( k != '__name__' ) ] #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# return [ ] #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# def get_vals( s , k ) : #NEWLINE# #INDENT# 'Returns a the values of key k in section s in each of the configs.\n\n    Return value is a list of (path, value). The value will be None if the config at path had no\n    value for the key.\n    ' #NEWLINE# def safe_get( c ) : #NEWLINE# #INDENT# if c . has_option ( s , k ) : #NEWLINE# #INDENT# return c . get ( s , k ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# return None #NEWLINE# #UNINDENT# #UNINDENT# return list ( ( ( p , safe_get ( config ) ) for ( p , config ) in zip ( config_paths , configs ) ) ) #NEWLINE# #UNINDENT# def uniq( it ) : #NEWLINE# #INDENT# 'Returns the unique items in it, sorting the items as a byproduct.' #NEWLINE# return [ x for ( x , _ ) in itertools . groupby ( sorted ( it ) ) ] #NEWLINE# #UNINDENT# all_sections = ( [ 'DEFAULT' ] + uniq ( itertools . chain . from_iterable ( ( config . sections ( ) for config in path ) ) ) ) #NEWLINE# compared_config = OrderedDict ( ) #NEWLINE# for section in all_sections : #NEWLINE# #INDENT# all_keys = uniq ( itertools . chain . from_iterable ( ( get_keys ( config , section ) for config in configs ) ) ) #NEWLINE# section_dict = OrderedDict ( ( ( key , get_vals ( section , key ) ) for key in all_keys ) ) #NEWLINE# compared_config [ section ] = section_dict #NEWLINE# #UNINDENT# def pretty( x ) : #NEWLINE# #INDENT# 'Indent the continuation lines of x, if any.' #NEWLINE# if ( x is None ) : #NEWLINE# #INDENT# return 'None' #NEWLINE# #UNINDENT# lines = x . decode ( 'utf8' ) . split ( '\n' ) #NEWLINE# if ( len ( lines ) > 1 ) : #NEWLINE# #INDENT# return '\n' . join ( ( ( [ lines [ 0 ] ] + [ '    {}' . format ( l ) for l in lines [ 1 : ( - 1 ) ] ] ) + [ '  {}' . format ( lines [ ( - 1 ) ] ) ] ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# return x #NEWLINE# #UNINDENT# #UNINDENT# def val_line( prefix , path_and_val ) : #NEWLINE# #INDENT# 'The value line, annotated with the path of the config which was the source of this value.' #NEWLINE# return '{}{}  # {}' . format ( prefix , pretty ( path_and_val [ 1 ] ) , path_and_val [ 0 ] ) . encode ( 'utf8' ) #NEWLINE# #UNINDENT# for ( section , section_dict ) in compared_config . items ( ) : #NEWLINE# #INDENT# section_header = '\n[{}]' . format ( section ) #NEWLINE# for ( key , vals ) in section_dict . items ( ) : #NEWLINE# #INDENT# if ( len ( [ v for v in vals if ( v [ 1 ] is not None ) ] ) > 1 ) : #NEWLINE# #INDENT# if section_header : #NEWLINE# #INDENT# print ( section_header ) #NEWLINE# section_header = None #NEWLINE# #UNINDENT# key_str = '{}: ' . format ( key ) #NEWLINE# indent = ( ' ' * len ( key_str ) ) #NEWLINE# print ( val_line ( key_str , vals [ 0 ] ) ) #NEWLINE# for v in vals [ 1 : ] : #NEWLINE# #INDENT# print ( val_line ( indent , v ) ) #NEWLINE# #UNINDENT# print ( b'' )