def compare_config(config_paths):
 def load_config(p):
  u"We need direct access to the underlying configparser, so we don't load via Config."
  cp = Config._create_parser()
  with open(p, u'r') as ini:
   cp.readfp(ini)
  return cp
 configs = [load_config(path) for path in config_paths]
 def get_keys(c, s):
  u'Return all keys provided in section s of config c.'
  if (s == u'DEFAULT'):
   return [k for k in c._defaults.keys()]
  elif c.has_section(s):
   return [k for k in c._sections[section].keys() if (k != u'__name__')]
  else:
   return []
 def get_vals(s, k):
  u'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    '
  def safe_get(c):
   if c.has_option(s, k):
    return c.get(s, k)
   else:
    return None
  return list(((p, safe_get(config)) for (p, config) in zip(config_paths, configs)))
 def uniq(it):
  u'Returns the unique items in it, sorting the items as a byproduct.'
  return [x for (x, _) in itertools.groupby(sorted(it))]
 all_sections = ([u'DEFAULT'] + uniq(itertools.chain.from_iterable((config.sections() for config in configs))))
 compared_config = OrderedDict()
 for section in all_sections:
  all_keys = uniq(itertools.chain.from_iterable((get_keys(config, section) for config in configs)))
  section_dict = OrderedDict(((key, get_vals(section, key)) for key in all_keys))
  compared_config[section] = section_dict
 def pretty(x):
  u'Indent the continuation lines of x, if any.'
  if (x is None):
   return u'None'
  lines = x.decode(u'utf8').split(u'\n')
  if (len(lines) > 1):
   return u'\n'.join((([lines[0]] + [u'    {}'.format(l) for l in lines[1:(-1)]]) + [u'  {}'.format(lines[(-1)])]))
  else:
   return x
 def val_line(prefix, path_and_val):
  u'The value line, annotated with the path of the config which was the source of this value.'
  return u'{}{}  # {}'.format(prefix, pretty(path_and_val[1]), path_and_val[0]).encode(u'utf8')
 for (section, section_dict) in compared_config.items():
  section_header = u'\n[{}]'.format(section)
  for (key, vals) in section_dict.items():
   if (len([v for v in vals if (v[1] is not None)]) > 1):
    if section_header:
     print(section_header)
     section_header = None
    key_str = u'{}: '.format(key)
    indent = (u' ' * len(key_str))
    print(val_line(key_str, vals[0]))
    for v in vals[1:]:
     print(val_line(indent, v))
    print('')

def compare_config ( config_paths ) : def load_config ( p ) : cp = Config . _create_parser ( ) with open ( p , u'r' ) as ini : cp . readfp ( ini ) return cp configs = [ load_config ( path ) for path in config_paths ] def get_keys ( c , s ) : if ( s == u'DEFAULT' ) : return [ k for k in c . _defaults . keys ( ) ] elif c . has_section ( s ) : return [ k for k in c . _sections [ section ] . keys ( ) if ( k != u'__name__' ) ] else : return [ ] def get_vals ( s , k ) : def safe_get ( c ) : if c . has_option ( s , k ) : return c . get ( s , k ) else : return None return list ( ( ( p , safe_get ( config ) ) for ( p , config ) in zip ( config_paths , configs ) ) ) def uniq ( it ) : return [ x for ( x , _ ) in itertools . groupby ( sorted ( it ) ) ] all_sections = ( [ u'DEFAULT' ] + uniq ( itertools . chain . from_iterable ( ( config . sections ( ) for config in configs ) ) ) ) compared_config = OrderedDict ( ) for section in all_sections : all_keys = uniq ( itertools . chain . from_iterable ( ( get_keys ( config , section ) for config in configs ) ) ) section_dict = OrderedDict ( ( ( key , get_vals ( section , key ) ) for key in all_keys ) ) compared_config [ section ] = section_dict def pretty ( x ) : if ( x is None ) : return u'None' lines = x . decode ( u'utf8' ) . split ( u'\n' ) if ( len ( lines ) > 1 ) : return u'\n' . join ( ( ( [ lines [ 0 ] ] + [ u'    {}' . format ( l ) for l in lines [ 1 : ( - 1 ) ] ] ) + [ u'  {}' . format ( lines [ ( - 1 ) ] ) ] ) ) else : return x def val_line ( prefix , path_and_val ) : return u'{}{}  # {}' . format ( prefix , pretty ( path_and_val [ 1 ] ) , path_and_val [ 0 ] ) . encode ( u'utf8' ) for ( section , section_dict ) in compared_config . items ( ) : section_header = u'\n[{}]' . format ( section ) for ( key , vals ) in section_dict . items ( ) : if ( len ( [ v for v in vals if ( v [ 1 ] is not None ) ] ) > 1 ) : if section_header : print ( section_header ) section_header = None key_str = u'{}: ' . format ( key ) indent = ( u' ' * len ( key_str ) ) print ( val_line ( key_str , vals [ 0 ] ) ) for v in vals [ 1 : ] : print ( val_line ( indent , v ) ) print ( '' )
returns the difference between the running config and the candidate config .