def test_parse_ini_file_missing_section_header(self, mock_config_parser_type): mock_config_parser = mock_config_parser_type() mock_config_parser.read.side_effect = \ configparser.MissingSectionHeaderError(mock.Mock(), 321, mock.Mock()) with self.assertRaises(configparser.MissingSectionHeaderError): utils.parse_ini_file('my_path')
def _read_duplicate(self, file_fp, fpname, dummy_overwrite_first=False): """Parse a sectioned setup file. The sections in setup file contains a title line at the top, indicated by a name in square brackets (`[]'), plus key/value options lines, indicated by `name: value' format lines. Continuations are represented by an embedded newline then leading whitespace. Blank lines, lines beginning with a '#', and just about everything else are ignored. """ cursect = None # None, or a dictionary optname = None lineno = 0 # None, or an exception exception = None seen = [] while True: line = file_fp.readline() if not line: break lineno = lineno + 1 # comment or blank line? if line.strip() == '' or line[0] in '#;': continue if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR": # no leading whitespace continue # continuation line? if line[0].isspace() and cursect is not None and optname: value = line.strip() if value: # pylint: disable=unsupported-assignment-operation # pylint: disable=unsubscriptable-object cursect[optname] = "%s\n%s" % (cursect[optname], value) # a section header or option header? else: # is it a section header? mo_header = self.SECTCRE.match(line) if mo_header: sectname = mo_header.group('header') if sectname in self._sections: cursect = self._sections[sectname] elif sectname == DEFAULTSECT: cursect = self._defaults else: cursect = self._dict() cursect['__name__'] = sectname self._sections[sectname] = cursect # So sections can't start with a continuation line optname = None # no section header in the file? elif cursect is None: raise configparser.MissingSectionHeaderError( fpname, lineno, line ) # an option line? else: mo_option = self.OPTCRE.match(line) if mo_option: optname, vi_sep, optval = mo_option.group( 'option', 'vi', 'value' ) if vi_sep in ('=', ':') and ';' in optval: # ';' is a comment delimiter only if it follows # a spacing character pos = optval.find(';') if ( pos != -1 and ( optval[pos - 1].isspace() or pos == 0 ) ): optval = optval[:pos] optval = optval.strip() # allow empty values if optval == '""': optval = '' optname = self.optionxform(optname.rstrip()) # if option already exists, append to a list # pylint: disable=unsubscriptable-object # pylint: disable=unsupported-membership-test # pylint: disable=unsupported-assignment-operation if optname in cursect and optname in seen: if isinstance(cursect[optname], list): cursect[optname].append(optval) else: cursect[optname] = [cursect[optname], optval] else: cursect[optname] = optval seen.append(optname) else: # a non-fatal parsing error occurred. set up the # exception but keep going. the exception will be # raised at the end of the file and will contain a # list of all bogus lines if not exception: exception = configparser.ParsingError(fpname) exception.append(lineno, repr(line)) # if any parsing errors occurred, raise an exception if exception is not None: raise exception # pylint: disable=raising-bad-type