@@ -670,6 +670,7 @@ def __init__(self, defaults=None, dict_type=_default_dict,
670670                self ._optcre  =  re .compile (self ._OPT_TMPL .format (delim = d ),
671671                                          re .VERBOSE )
672672        self ._comments  =  _CommentSpec (comment_prefixes  or  (), inline_comment_prefixes  or  ())
673+         self ._loaded_sources  =  []
673674        self ._strict  =  strict 
674675        self ._allow_no_value  =  allow_no_value 
675676        self ._empty_lines_in_values  =  empty_lines_in_values 
@@ -690,6 +691,7 @@ def __init__(self, defaults=None, dict_type=_default_dict,
690691            self ._read_defaults (defaults )
691692        self ._allow_unnamed_section  =  allow_unnamed_section 
692693
694+ 
693695    def  defaults (self ):
694696        return  self ._defaults 
695697
@@ -752,6 +754,7 @@ def read(self, filenames, encoding=None):
752754            try :
753755                with  open (filename , encoding = encoding ) as  fp :
754756                    self ._read (fp , filename )
757+                     self ._loaded_sources .append (filename )
755758            except  OSError :
756759                continue 
757760            if  isinstance (filename , os .PathLike ):
@@ -773,11 +776,13 @@ def read_file(self, f, source=None):
773776            except  AttributeError :
774777                source  =  '<???>' 
775778        self ._read (f , source )
779+         self ._loaded_sources .append (source )
776780
777781    def  read_string (self , string , source = '<string>' ):
778782        """Read configuration from a given string.""" 
779783        sfile  =  io .StringIO (string )
780784        self .read_file (sfile , source )
785+         self ._loaded_sources .append (source )
781786
782787    def  read_dict (self , dictionary , source = '<dict>' ):
783788        """Read configuration from a dictionary. 
@@ -809,6 +814,7 @@ def read_dict(self, dictionary, source='<dict>'):
809814                    raise  DuplicateOptionError (section , key , source )
810815                elements_added .add ((section , key ))
811816                self .set (section , key , value )
817+         self ._loaded_sources .append (source )
812818
813819    def  get (self , section , option , * , raw = False , vars = None , fallback = _UNSET ):
814820        """Get an option value for a given section. 
@@ -1048,6 +1054,39 @@ def __iter__(self):
10481054        # XXX does it break when underlying container state changed? 
10491055        return  itertools .chain ((self .default_section ,), self ._sections .keys ())
10501056
1057+     def  __str__ (self ):
1058+         config_dict  =  {
1059+             section : {key : value  for  key , value  in  self .items (section , raw = True )}
1060+             for  section  in  self .sections ()
1061+         }
1062+         return  f"<ConfigParser: { config_dict }  
1063+ 
1064+ 
1065+     def  __repr__ (self ):
1066+         init_params  =  {
1067+             "defaults" : self ._defaults  if  self ._defaults  else  None ,
1068+             "dict_type" : type (self ._dict ).__name__ ,
1069+             "allow_no_value" : self ._allow_no_value ,
1070+             "delimiters" : self ._delimiters ,
1071+             "strict" : self ._strict ,
1072+             "default_section" : self .default_section ,
1073+             "interpolation" : type (self ._interpolation ).__name__ ,
1074+         }
1075+         init_params  =  {k : v  for  k , v  in  init_params .items () if  v  is  not None }
1076+         state_summary  =  {
1077+             "loaded_sources" : self ._loaded_sources ,
1078+             "sections_count" : len (self ._sections ),
1079+             "sections" : list (self ._sections .keys ())[:5 ],  # Limit to 5 section names for readability 
1080+         }
1081+ 
1082+         if  len (self ._sections ) >  5 :
1083+             state_summary ["sections_truncated" ] =  f"...and { len (self ._sections ) -  5 }  
1084+ 
1085+         return  (f"<{ self .__class__ .__name__ }  
1086+                 f"params={ init_params }  
1087+                 f"state={ state_summary }  )
1088+ 
1089+ 
10511090    def  _read (self , fp , fpname ):
10521091        """Parse a sectioned configuration file. 
10531092
0 commit comments