1818 delimiters=('=', ':'), comment_prefixes=('#', ';'),
1919 inline_comment_prefixes=None, strict=True,
2020 empty_lines_in_values=True, default_section='DEFAULT',
21- interpolation=<unset>, converters=<unset>):
22-
21+ interpolation=<unset>, converters=<unset>,
22+ allow_unnamed_section=False):
2323 Create the parser. When `defaults` is given, it is initialized into the
2424 dictionary or intrinsic defaults. The keys must be strings, the values
2525 must be appropriate for %()s string interpolation.
6868 converter gets its corresponding get*() method on the parser object and
6969 section proxies.
7070
71+ When `allow_unnamed_section` is True (default: False), options
72+ without section are accepted: the section for these is
73+ ``configparser.UNNAMED_SECTION``.
74+
7175 sections()
7276 Return all the configuration section names, sans DEFAULT.
7377
156160 "ConfigParser" , "RawConfigParser" ,
157161 "Interpolation" , "BasicInterpolation" , "ExtendedInterpolation" ,
158162 "SectionProxy" , "ConverterMapping" ,
159- "DEFAULTSECT" , "MAX_INTERPOLATION_DEPTH" )
163+ "DEFAULTSECT" , "MAX_INTERPOLATION_DEPTH" , "UNNAMED_SECTION" )
160164
161165_default_dict = dict
162166DEFAULTSECT = "DEFAULT"
@@ -336,6 +340,15 @@ def __init__(self, filename, lineno, line):
336340 self .line = line
337341 self .args = (filename , lineno , line )
338342
343+ class _UnnamedSection :
344+
345+ def __repr__ (self ):
346+ return "<UNNAMED_SECTION>"
347+
348+
349+ UNNAMED_SECTION = _UnnamedSection ()
350+
351+
339352# Used in parser getters to indicate the default behaviour when a specific
340353# option is not found it to raise an exception. Created to enable `None` as
341354# a valid fallback value.
@@ -550,7 +563,8 @@ def __init__(self, defaults=None, dict_type=_default_dict,
550563 comment_prefixes = ('#' , ';' ), inline_comment_prefixes = None ,
551564 strict = True , empty_lines_in_values = True ,
552565 default_section = DEFAULTSECT ,
553- interpolation = _UNSET , converters = _UNSET ):
566+ interpolation = _UNSET , converters = _UNSET ,
567+ allow_unnamed_section = False ,):
554568
555569 self ._dict = dict_type
556570 self ._sections = self ._dict ()
@@ -589,6 +603,7 @@ def __init__(self, defaults=None, dict_type=_default_dict,
589603 self ._converters .update (converters )
590604 if defaults :
591605 self ._read_defaults (defaults )
606+ self ._allow_unnamed_section = allow_unnamed_section
592607
593608 def defaults (self ):
594609 return self ._defaults
@@ -862,13 +877,19 @@ def write(self, fp, space_around_delimiters=True):
862877 if self ._defaults :
863878 self ._write_section (fp , self .default_section ,
864879 self ._defaults .items (), d )
880+ if UNNAMED_SECTION in self ._sections :
881+ self ._write_section (fp , UNNAMED_SECTION , self ._sections [UNNAMED_SECTION ].items (), d , unnamed = True )
882+
865883 for section in self ._sections :
884+ if section is UNNAMED_SECTION :
885+ continue
866886 self ._write_section (fp , section ,
867887 self ._sections [section ].items (), d )
868888
869- def _write_section (self , fp , section_name , section_items , delimiter ):
870- """Write a single section to the specified `fp`."""
871- fp .write ("[{}]\n " .format (section_name ))
889+ def _write_section (self , fp , section_name , section_items , delimiter , unnamed = False ):
890+ """Write a single section to the specified `fp'."""
891+ if not unnamed :
892+ fp .write ("[{}]\n " .format (section_name ))
872893 for key , value in section_items :
873894 value = self ._interpolation .before_write (self , section_name , key ,
874895 value )
@@ -961,6 +982,7 @@ def _read(self, fp, fpname):
961982 lineno = 0
962983 indent_level = 0
963984 e = None # None, or an exception
985+
964986 try :
965987 for lineno , line in enumerate (fp , start = 1 ):
966988 comment_start = sys .maxsize
@@ -1007,6 +1029,13 @@ def _read(self, fp, fpname):
10071029 cursect [optname ].append (value )
10081030 # a section header or option header?
10091031 else :
1032+ if self ._allow_unnamed_section and cursect is None :
1033+ sectname = UNNAMED_SECTION
1034+ cursect = self ._dict ()
1035+ self ._sections [sectname ] = cursect
1036+ self ._proxies [sectname ] = SectionProxy (self , sectname )
1037+ elements_added .add (sectname )
1038+
10101039 indent_level = cur_indent_level
10111040 # is it a section header?
10121041 mo = self .SECTCRE .match (value )
@@ -1027,36 +1056,61 @@ def _read(self, fp, fpname):
10271056 elements_added .add (sectname )
10281057 # So sections can't start with a continuation line
10291058 optname = None
1030- # no section header in the file ?
1059+ # no section header?
10311060 elif cursect is None :
10321061 raise MissingSectionHeaderError (fpname , lineno , line )
1033- # an option line?
1062+ # an option line?
10341063 else :
1035- mo = self ._optcre .match (value )
1064+ indent_level = cur_indent_level
1065+ # is it a section header?
1066+ mo = self .SECTCRE .match (value )
10361067 if mo :
1037- optname , vi , optval = mo .group ('option' , 'vi' , 'value' )
1038- if not optname :
1039- e = self ._handle_error (e , fpname , lineno , line )
1040- optname = self .optionxform (optname .rstrip ())
1041- if (self ._strict and
1042- (sectname , optname ) in elements_added ):
1043- raise DuplicateOptionError (sectname , optname ,
1044- fpname , lineno )
1045- elements_added .add ((sectname , optname ))
1046- # This check is fine because the OPTCRE cannot
1047- # match if it would set optval to None
1048- if optval is not None :
1049- optval = optval .strip ()
1050- cursect [optname ] = [optval ]
1068+ sectname = mo .group ('header' )
1069+ if sectname in self ._sections :
1070+ if self ._strict and sectname in elements_added :
1071+ raise DuplicateSectionError (sectname , fpname ,
1072+ lineno )
1073+ cursect = self ._sections [sectname ]
1074+ elements_added .add (sectname )
1075+ elif sectname == self .default_section :
1076+ cursect = self ._defaults
10511077 else :
1052- # valueless option handling
1053- cursect [optname ] = None
1078+ cursect = self ._dict ()
1079+ self ._sections [sectname ] = cursect
1080+ self ._proxies [sectname ] = SectionProxy (self , sectname )
1081+ elements_added .add (sectname )
1082+ # So sections can't start with a continuation line
1083+ optname = None
1084+ # no section header in the file?
1085+ elif cursect is None :
1086+ raise MissingSectionHeaderError (fpname , lineno , line )
1087+ # an option line?
10541088 else :
1055- # a non-fatal parsing error occurred. set up the
1056- # exception but keep going. the exception will be
1057- # raised at the end of the file and will contain a
1058- # list of all bogus lines
1059- e = self ._handle_error (e , fpname , lineno , line )
1089+ mo = self ._optcre .match (value )
1090+ if mo :
1091+ optname , vi , optval = mo .group ('option' , 'vi' , 'value' )
1092+ if not optname :
1093+ e = self ._handle_error (e , fpname , lineno , line )
1094+ optname = self .optionxform (optname .rstrip ())
1095+ if (self ._strict and
1096+ (sectname , optname ) in elements_added ):
1097+ raise DuplicateOptionError (sectname , optname ,
1098+ fpname , lineno )
1099+ elements_added .add ((sectname , optname ))
1100+ # This check is fine because the OPTCRE cannot
1101+ # match if it would set optval to None
1102+ if optval is not None :
1103+ optval = optval .strip ()
1104+ cursect [optname ] = [optval ]
1105+ else :
1106+ # valueless option handling
1107+ cursect [optname ] = None
1108+ else :
1109+ # a non-fatal parsing error occurred. set up the
1110+ # exception but keep going. the exception will be
1111+ # raised at the end of the file and will contain a
1112+ # list of all bogus lines
1113+ e = self ._handle_error (e , fpname , lineno , line )
10601114 finally :
10611115 self ._join_multiline_values ()
10621116 # if any parsing errors occurred, raise an exception
0 commit comments