def _time_step_from_minutes_months(self, minutes, months): if minutes != 0 and months != 0: raise ParsingError("Invalid time step") elif minutes != 0: return str(minutes) + "min" else: return str(months) + "M"
def _handle_error(self, exc: Optional[E], fpname: str, lineno: int, line: str) -> Union[ParsingError, E]: e = exc or ParsingError(fpname) if hasattr(e, "append"): e.append(lineno, repr(line)) # type: ignore[union-attr] # ^ the typechecker cannot handle hasattr return e
def test_simulate_parsing_error_when_saving(update_file, tmp_path): """Simulate a parsing error when saving an INI file.""" update_file.side_effect = ParsingError( source="simulating a captured error") original_file = """ [flake8] existing = value """ ProjectMock(tmp_path).style(f""" ["{SETUP_CFG}".flake8] new = "value" """).setup_cfg(original_file).api_fix().assert_violations( Fuss( True, SETUP_CFG, 324, ": section [flake8] has some missing key/value pairs. Use this:", """ [flake8] new = value """, ), Fuss( False, SETUP_CFG, Violations.PARSING_ERROR.code, ": parsing error (ParsingError): Source contains parsing errors: 'simulating a captured error'", ), ).assert_file_contents(SETUP_CFG, original_file)
def read_minutes_months(self, s): """Return a (minutes, months) tuple after parsing a "M,N" string.""" try: (minutes, months) = [int(x.strip()) for x in s.split(",")] return minutes, months except Exception: raise ParsingError(('Value should be "minutes, months"'))
def __init__(self, sectionname="baseconfig"): try: if not self.logger.handlers: handler = RotatingFileHandler("bespoke.log", mode="a", maxBytes=500000, backupCount=5) self.logger.addHandler(handler) self.logger.setLevel(logging.ERROR) self.logger.info("configuration init started") file = os.path.join(os.path.dirname(__file__), "bespoke.cfg") self.sectionname = sectionname config = ConfigParser() config.read(file) self.productschemaname = config.get(section=sectionname, option="product") self.orderschemaname = config.get(section=sectionname, option="order") self.customerschemaname = config.get(section=sectionname, option="customer") self.loglevel = config.get(section=sectionname, option="loglevel") self.logpath = config.get(sectionname, option="logpath") except Exception as ex: raise ParsingError(source="configuration load for bespoke failed", filename="bespoke.cfg") self.logger.exception(ex) finally: self.logger.info("configuration init complete")
def get_altitude(self, name, value): self._ensure_location_attribute_exists() try: items = value.split() self.meta["location"]["altitude"] = float(items[0]) self.meta["location"]["asrid"] = int(items[1]) if len(items) > 1 else None except (IndexError, ValueError): raise ParsingError("Invalid altitude")
def get_location(self, name, value): self._ensure_location_attribute_exists() try: items = value.split() self.meta["location"]["abscissa"] = float(items[0]) self.meta["location"]["ordinate"] = float(items[1]) self.meta["location"]["srid"] = int(items[2]) except (IndexError, ValueError): raise ParsingError("Invalid location")
def read_config_file(self) -> None: """TODO: Doku.""" if not file_exists(self.config_file_path): raise FileNotFoundError("config file '{}' not found".format(self.config_file_path)) try: self.configlib.read(self.config_file_path) except ParsingError as exc: raise ParsingError( "{} is not readable by RawConfigParser. \n inner exception: {}".format( self.config_file_path, format_exception(exc)))
def __init__(self, config_file_path: str) -> None: if not file_exists(config_file_path): raise FileNotFoundError("config file '{}' not found".format(config_file_path)) self.config_file_path = config_file_path self.configlib = RawConfigParser() try: self.configlib.read(self.config_file_path) except ParsingError as exc: raise ParsingError( "{} is not readable by RawConfigParser. \n inner exception: {}".format( config_file_path, format_exception(exc)))
def get_plot_configs(cfg_path=None): """returns a config object with plotting settings""" defaults = dict(xlabel_fontsize=14, ylabel_fontsize=14, xtick_fontsize=12, ytick_fontsize=12, xlabel_pad=0.01, ylabel_pad=0.01) figwidths = { '1-way plot': 2.25, '2-way plot': 9, '3-way plot': 9, '4-way plot': 9, 'summary plot': 9, 'grid': 8 } figsizes = { '1-way plot': (9, 3), '2-way plot': (9, 9), '3-way plot': (9, 9), '4-way plot': (9, 9), 'summary plot': (9, 9), 'grid': (8, 8) } config = RawConfigParser() for section in [ '1-way plot', '2-way plot', '3-way plot', '4-way plot', 'summary plot', 'grid' ]: config.add_section(section) config.set(section, 'figwidth', figwidths[section]) config.set(section, 'figsize', figsizes[section]) for arg, default in list(defaults.items()): config.set(section, arg, default) if cfg_path: # load the user provided config user_config = RawConfigParser(allow_no_value=True) try: user_config.read(cfg_path) except ParsingError as err: msg = 'Could not parse %s: %s' % (cfg_path, err) raise ParsingError(msg) # update the default settings for section in config.sections(): for key, val in config.items(section): try: new_val = user_config.get(section, key) config.set(section, key, eval(new_val)) except (NoSectionError, NoOptionError): pass return config
def from_file(cls, filename): conf = SiteConfig() if not conf.read([filename]): raise ParsingError("Failed to parse file: %s" % filename) # Check sections for section in cls.required_sections: if not conf.has_section(section): raise NoSectionError("Missing section: %s" % section) return conf
def _config_file_2_dict(self, defaults, files, previous_run=False): """ parse config files files, the last one have precedence on the previous on so on, and return a dict with properties, values. The defaults is just used to know the type of the properties and cast them. It is not used to fill the dict with default values. :param defaults: the macsyfinder defaults value :type defaults: a :class:`macsypy.config.MacsyDefaults` object :param files: the configuration files to parse :type files: list of string :return: dict """ parser = ConfigParser() parse_meth = { int: parser.getint, float: parser.getfloat, bool: parser.getboolean } try: used_files = parser.read(files) _log.debug( f"Files parsed for configuration: {', '.join(used_files)}") except ParsingError as err: raise ParsingError( f"A macsyfinder configuration file is not well formed: {err}" ) from None opts = {} sections = [s for s in parser.sections() if s != 'models'] for section in sections: for option in parser.options(section): if previous_run and option == 'out_dir': # set the out_dir from the previous_run is a non sense continue opt_type = type(defaults.get(option, None)) try: opt_value = parse_meth.get(opt_type, parser.get)(section, option) except (ValueError, TypeError) as err: raise ValueError( f"Invalid value in config_file for option '{option}': {err}" ) opts[option] = opt_value try: opts['models'] = parser.items('models') except NoSectionError: pass return opts
def __init__(self, settings_config=None): if settings_config is not None: if os.path.exists(settings_config): self._config_name = settings_config else: raise FileNotFoundError self._config = ConfigParser() try: self._config.read(self._config_name) except OSError: logging.error("Файл {0} не найден".format(self._config_name)) raise OSError except ParsingError: print("Файл настроек {0} содержит ошибки".format( self._config_name)) raise ParsingError()
def parse_configs(section, required_keys=[]): """ Let's get the API access details from the config.ini file at the root of the application (one level above this file) :param section: str: which API details? TwilioAPI or SMAPI? :param required_keys: which keys are required (sm_voice needs SMAPI:access_token+api_key Twilio:auth_token+account_sid) :return: dict: configuration dictionary """ cfg = ConfigParser() cfg.read("config.ini") try: configuration = dict(cfg.items(section)) if not configuration.keys() >= set(required_keys): # if the config keys aren't a superset of the required keys raise ParsingError("config.ini") except ParsingError as e: print("Couldn't load %s configs" % section) print(e) exit() return configuration
def read_meta_line(self, f): """Read one line from a file format header and return a (name, value) tuple, where name is lowercased. Returns ('', '') if the next line is blank. Raises ParsingError if next line in f is not a valid header line.""" line = f.readline() if isinstance(line, bytes): line = line.decode("utf-8-sig") name, value = "", "" if line.isspace(): return (name, value) if line.find("=") > 0: name, value = line.split("=", 1) name = name.rstrip().lower() value = value.strip() name = "" if any([c.isspace() for c in name]) else name if not name: raise ParsingError("Invalid file header line") return (name, value)
def get_config(forge): og = f"{Path(__file__).parent.parent.parent}/example.cfg" path = f"{os.path.expanduser('~/.gitforge.cfg')}" if not os.path.exists(path): if not os.path.exists(og): raise FileNotFoundError(og) logging.debug(f"Copying {og} to {path}...") copyfile(og, path) logging.debug(f"Looking for configuration at {path}...") try: config = ConfigParser() config.read(path) except Exception as error: logging.error(error) raise ParsingError(f"Failed to retrieve configuration from {path}.") logging.info(f"Found default configuration at {path}.") # https://stackoverflow.com/a/56119373/11133327 readline.set_completer_delims(" \t\n=") readline.parse_and_bind("tab: complete") if config[forge]["destination"] == "/path/to/directory/to/store/repos": config[forge]["destination"] = input( f"{color.fg.yellow}{forge}{color.fg.cyan} Destination Directory:{color.reset} " ) config[forge]["destination"] = chkdir(config[forge]["destination"]) with open(path, "w") as configfile: config.write(configfile) if config[forge]["token"] == f"{forge.upper()}-PERSONAL-ACCESS-TOKEN": readline.parse_and_bind("tab: complete") config[forge]["token"] = input( f"{color.fg.yellow}{forge}{color.fg.cyan} Personal Access Token:{color.reset} " ) with open(path, "w") as configfile: config.write(configfile) return config[forge]
def _config_file_2_dict(self, file): """ Parse a configuration file in ini format in dictionnary :param str file: path to the configuration file :return: the parsed options :rtype: dict """ parser = ConfigParser() parse_meth = { int: parser.getint, float: parser.getfloat, bool: parser.getboolean } try: parser.read([file]) _log.debug(f"Configuration file {file} parsed.") except ParsingError as err: raise ParsingError( f"The macsyfinder configuration file '{file}' is not well formed: {err}" ) from None opts = {} sections = list(parser.sections()) for section in sections: for option in parser.options(section): opt_type = type(self._defaults.get(option, None)) if option == 'log_level': self._set_log_level(parser.get(section, option)) else: try: opt_value = parse_meth.get(opt_type, parser.get)(section, option) except (ValueError, TypeError) as err: raise ValueError( f"Invalid value in config_file for option '{option}': {err}" ) opts[option] = opt_value return opts
def get_precision(self, name, value): try: self.meta[name] = int(value) except ValueError as e: raise ParsingError(e.args)
def get_interval_type(self, name, value): value = value.lower() if value not in ("sum", "average", "maximum", "minimum", "vector_average"): raise ParsingError(("Invalid interval type")) self.meta[name] = value
def _handle_error(self, exc, fpname, lineno, line): if not exc: exc = ParsingError(fpname) exc.append(lineno, repr(line)) return exc
def _readfp(self, fp): cur_section = None cur_option = None cur_section_name = None cur_option_name = None pending_lines = [] pending_empty_lines = False try: fname = fp.name except AttributeError: fname = "<???>" linecount = 0 exc = None line = None for line in readline_iterator(fp): # Check for BOM on first line if linecount == 0: if line[0] == "\ufeff": line = line[1:] self._bom = True lineobj = self._parse(line) linecount += 1 if not cur_section and not isinstance(lineobj, (CommentLine, EmptyLine, SectionLine)): if self._parse_exc: raise MissingSectionHeaderError(fname, linecount, line) else: lineobj = make_comment(line) if lineobj is None: if self._parse_exc: if exc is None: exc = ParsingError(fname) exc.append(linecount, line) lineobj = make_comment(line) if isinstance(lineobj, ContinuationLine): if cur_option: if pending_lines: cur_option.extend(pending_lines) pending_lines = [] if pending_empty_lines: optobj._compat_skip_empty_lines.add(cur_option_name) pending_empty_lines = False cur_option.add(lineobj) else: # illegal continuation line - convert to comment if self._parse_exc: if exc is None: exc = ParsingError(fname) exc.append(linecount, line) lineobj = make_comment(line) if isinstance(lineobj, OptionLine): if pending_lines: cur_section.extend(pending_lines) pending_lines = [] pending_empty_lines = False cur_option = LineContainer(lineobj) cur_section.add(cur_option) if self._optionxform: cur_option_name = self._optionxform(cur_option.name) else: cur_option_name = cur_option.name if cur_section_name == DEFAULTSECT: optobj = self._defaults else: optobj = self._sections[cur_section_name] optobj._options[cur_option_name] = cur_option if isinstance(lineobj, SectionLine): self._data.extend(pending_lines) pending_lines = [] pending_empty_lines = False cur_section = LineContainer(lineobj) self._data.add(cur_section) cur_option = None cur_option_name = None if cur_section.name == DEFAULTSECT: self._defaults._lines.append(cur_section) cur_section_name = DEFAULTSECT else: if self._sectionxform: cur_section_name = self._sectionxform(cur_section.name) else: cur_section_name = cur_section.name if cur_section_name not in self._sections: self._sections[cur_section_name] = INISection( cur_section, defaults=self._defaults, optionxformsource=self ) else: self._sections[cur_section_name]._lines.append(cur_section) if isinstance(lineobj, (CommentLine, EmptyLine)): pending_lines.append(lineobj) if isinstance(lineobj, EmptyLine): pending_empty_lines = True self._data.extend(pending_lines) if line and line[-1] == "\n": self._data.add(EmptyLine()) if exc: raise exc
def _read(self, fp, fpname): """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. """ if self.main_section in self._sections: cursect = self._sections[self.main_section] else: cursect = self._dict() cursect['__name__'] = self.main_section self._sections[self.main_section] = cursect optname = None lineno = 0 e = None # None, or an exception while True: line = 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 optname: value = line.strip() if value: cursect[optname].append(value) # an option line? else: mo = self._optcre.match(line) if mo: optname, vi, optval = mo.group('option', 'vi', 'value') optname = self.optionxform(optname.rstrip()) # This check is fine because the OPTCRE cannot # match if it would set optval to None if optval is not None: if vi 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(): optval = optval[:pos] optval = optval.strip() # allow empty values if optval == '""': optval = '' self._handle_set_option(cursect, optname, optval) else: # valueless option handling cursect[optname] = optval 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 e: e = ParsingError(fpname) e.append(lineno, repr(line)) # if any parsing errors occurred, raise an exception if e: raise e # join the multi-line values collected while reading all_sections = [self._defaults] all_sections.extend(list(self._sections.values())) for options in all_sections: for name, val in list(options.items()): if isinstance(val, list): options[name] = '\n'.join(val)
def readfp(self, fp): cur_section = None cur_option = None cur_section_name = None cur_option_name = None pending_lines = [] try: fname = fp.name except AttributeError: fname = '<???>' linecount = 0 exc = None line = None for line in readline_iterator(fp): lineobj = self._parse(line) linecount += 1 if not cur_section and not isinstance(lineobj, (CommentLine, EmptyLine, SectionLine)): if self._parse_exc: raise MissingSectionHeaderError(fname, linecount, line) else: lineobj = make_comment(line) if lineobj is None: if self._parse_exc: if exc is None: exc = ParsingError(fname) exc.append(linecount, line) lineobj = make_comment(line) if isinstance(lineobj, ContinuationLine): if cur_option: cur_option.extend(pending_lines) pending_lines = [] cur_option.add(lineobj) else: # illegal continuation line - convert to comment if self._parse_exc: if exc is None: exc = ParsingError(fname) exc.append(linecount, line) lineobj = make_comment(line) if isinstance(lineobj, OptionLine): cur_section.extend(pending_lines) pending_lines = [] cur_option = LineContainer(lineobj) cur_section.add(cur_option) if self._optionxform: cur_option_name = self._optionxform(cur_option.name) else: cur_option_name = cur_option.name if cur_section_name == DEFAULTSECT: optobj = self._defaults else: optobj = self._sections[cur_section_name] optobj._options[cur_option_name] = cur_option if isinstance(lineobj, SectionLine): self._data.extend(pending_lines) pending_lines = [] cur_section = LineContainer(lineobj) self._data.add(cur_section) cur_option = None cur_option_name = None if cur_section.name == DEFAULTSECT: self._defaults._lines.append(cur_section) cur_section_name = DEFAULTSECT else: if self._sectionxform: cur_section_name = self._sectionxform(cur_section.name) else: cur_section_name = cur_section.name if cur_section_name not in self._sections: self._sections[cur_section_name] = \ INISection(cur_section, defaults=self._defaults, optionxformsource=self) else: self._sections[cur_section_name]._lines.append(cur_section) if isinstance(lineobj, (CommentLine, EmptyLine)): pending_lines.append(lineobj) self._data.extend(pending_lines) if line and line[-1]=='\n': self._data.add(EmptyLine()) if exc: raise exc
def _read(self, fp, fpname): cursect = None # None, or a dictionary optname = None lineno = 0 e = None # None, or an exception while True: line = fp.readline() if not line: break 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: cursect[optname].append(value) # a section header or option header? else: # is it a section header? mo = self.SECTCRE.match(line) if mo: sectname = mo.group('header') if sectname in self._sections: # we're extending/overriding, we're good 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 MissingSectionHeaderError(fpname, lineno, line) # an option line? else: try: mo = self._optcre.match(line) # 2.7 except AttributeError: mo = self.OPTCRE.match(line) # 2.6 if mo: optname, vi, optval = mo.group('option', 'vi', 'value') optname = self.optionxform(optname.rstrip()) # We don't want to override. if optname in cursect: continue # This check is fine because the OPTCRE cannot # match if it would set optval to None if optval is not None: if vi 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(): optval = optval[:pos] optval = optval.strip() # allow empty values if optval == '""': optval = '' cursect[optname] = [optval] else: # valueless option handling cursect[optname] = optval 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 e: e = ParsingError(fpname) e.append(lineno, repr(line)) # if any parsing errors occurred, raise an exception if e: raise e # join the multi-line values collected while reading all_sections = [self._defaults] all_sections.extend(self._sections.values()) for options in all_sections: for name, val in options.items(): if isinstance(val, list): options[name] = '\n'.join(val)
def _read(self, fp, fpname): """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 e = None # None, or an exception while True: line = fp.readline() if not line: break 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: cursect[optname] = "%s\n%s" % (cursect[optname], value) # a section header or option header? else: # is it a section header? mo = self.SECTCRE.match(line) if mo: sectname = mo.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 MissingSectionHeaderError(fpname, lineno, line) # an option line? else: mo = self.OPTCRE.match(line) if mo: optname, vi, optval = mo.group('option', 'vi', 'value') if vi 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(): optval = optval[:pos] optval = optval.strip() # allow empty values if optval == '""': optval = '' optname = self.optionxform(optname.rstrip()) if cursect.get(optname): if not isinstance(cursect[optname], list): cursect[optname] = [cursect[optname]] cursect[optname].append(optval) else: cursect[optname] = optval 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 e: e = ParsingError(fpname) e.append(lineno, repr(line)) # if any parsing errors occurred, raise an exception if e: raise e
def _read(self, fp, fpname): """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 e = None # None, or an exception while True: line = fp.readline() line = line.replace( '%', '%%' ) # python 3 uses % as system symbol, if it is double percent "%%" it automatically replaces to "%" 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('\n') if value: cursect[optname].append(value) # a section header or option header? else: # is it a section header? mo = self.SECTCRE.match(line) if mo: sectname = mo.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 MissingSectionHeaderError(fpname, lineno, line) # an option line? else: mo = self._optcre.match(line) if mo: optname, vi, optval = mo.group('option', 'vi', 'value') optname = self.optionxform(optname.rstrip()) # This check is fine because the OPTCRE cannot # match if it would set optval to None if optval is not None: if vi 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(): optval = optval[:pos] optval = optval.strip() # allow empty values if optval == '""': optval = '' cursect[optname] = [optval] else: # valueless option handling cursect[optname] = optval 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 e: e = ParsingError(fpname) e.append(lineno, repr(line)) # if any parsing errors occurred, raise an exception if e: raise e # join the multi-line values collected while reading all_sections = [self._defaults] all_sections.extend(list(self._sections.values())) for options in all_sections: for name, val in options.items(): if isinstance(val, list): options[name] = '\n'.join(val)
def _read(self, fp, fpname): cursect = None # None, or a dictionary optname = None lineno = 0 e = None # None, or an exception while True: line = fp.readline() if not line: break 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: cursect[optname].append(value) # a section header or option header? else: # is it a section header? mo = self.SECTCRE.match(line) if mo: sectname = mo.group('header') if sectname in self._sections: # we're extending/overriding, we're good 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 MissingSectionHeaderError(fpname, lineno, line) # an option line? else: try: mo = self._optcre.match(line) # 2.7 except AttributeError: mo = self.OPTCRE.match(line) # 2.6 if mo: optname, vi, optval = mo.group('option', 'vi', 'value') self.optionxform = text_type optname = self.optionxform(optname.rstrip()) # We don't want to override. if optname in cursect: continue # This check is fine because the OPTCRE cannot # match if it would set optval to None if optval is not None: if vi 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(): optval = optval[:pos] optval = optval.strip() # allow empty values if optval == '""': optval = '' cursect[optname] = [optval] else: # valueless option handling cursect[optname] = optval 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 e: e = ParsingError(fpname) e.append(lineno, repr(line)) # if any parsing errors occurred, raise an exception if e: raise e # join the multi-line values collected while reading all_sections = [self._defaults] all_sections.extend(self._sections.values()) for options in all_sections: for name, val in options.items(): if isinstance(val, list): options[name] = '\n'.join(val)
def _read(self, fp, fpname): """ Override the built-in _read() method to read comments """ from configparser import DEFAULTSECT, MissingSectionHeaderError, ParsingError cursect = None # None, or a dictionary optname = None lineno = 0 e = None # None, or an exception ######## tab_update ######## comment_index = 0 self.top_comments = [] self.fields_outside_stanza = [] add_space_to_next_line = False ############################ while True: line = fp.readline() if not line: break lineno = lineno + 1 line = line.strip(" ") # comment or blank line? if line.strip() == '' or line[0] in COMMENT_PREFIX: ######## tab_update ######## # save the lineno & comments if cursect: name = "{}{}".format(COMMENT_KEY, comment_index) comment_index += 1 cursect[name] = line else: self.top_comments.append(line) continue ############################ if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR": # no leading whitespace continue # continuation line? ######## tab_update ######## # support multiline with \ if add_space_to_next_line: line = " " + line if line.strip().endswith("\\"): line = line.rstrip("\\ ") add_space_to_next_line = True else: add_space_to_next_line = False ############################ if line[0].isspace() and cursect is not None and optname: value = line.strip() if value: cursect[optname].append(value) # a section header or option header? else: # is it a section header? mo = self.SECTCRE.match(line) if mo: sectname = mo.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: ######## tab_update ######## # disable the exception since splunk allows the field outside stanzas # raise MissingSectionHeaderError(fpname, lineno, line) self.fields_outside_stanza.append(line) ############################ # an option line? else: mo = self._optcre.match(line) if mo: optname, vi, optval = mo.group('option', 'vi', 'value') optname = self.optionxform(optname.rstrip()) # This check is fine because the OPTCRE cannot # match if it would set optval to None if optval is not None: if vi 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(): optval = optval[:pos] optval = optval.strip() # allow empty values if optval == '""': optval = '' cursect[optname] = [optval] else: # valueless option handling cursect[optname] = optval 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 e: e = ParsingError(fpname) e.append(lineno, repr(line)) # if any parsing errors occurred, raise an exception if e: raise e # join the multi-line values collected while reading all_sections = [self._defaults] all_sections.extend(list(self._sections.values())) for options in all_sections: for name, val in list(options.items()): if isinstance(val, list): options[name] = '\n'.join(val)
def _readfp(self, fp): cur_section = None cur_option = None cur_section_name = None cur_option_name = None pending_lines = [] pending_empty_lines = False try: fname = fp.name except AttributeError: fname = '<???>' linecount = 0 exc = None line = None for line in readline_iterator(fp): # Check for BOM on first line if linecount == 0 and isinstance(line, str): if line[0] == '\ufeff': line = line[1:] self._bom = True lineobj = self._parse(line) linecount += 1 if not cur_section and not isinstance( lineobj, (CommentLine, EmptyLine, SectionLine)): if self._parse_exc: raise MissingSectionHeaderError(fname, linecount, line) else: lineobj = make_comment(line) if lineobj is None: if self._parse_exc: if exc is None: exc = ParsingError(fname) exc.append(linecount, line) lineobj = make_comment(line) if isinstance(lineobj, ContinuationLine): if cur_option: if pending_lines: cur_option.extend(pending_lines) pending_lines = [] if pending_empty_lines: optobj._compat_skip_empty_lines.add( cur_option_name) pending_empty_lines = False cur_option.add(lineobj) else: # illegal continuation line - convert to comment if self._parse_exc: if exc is None: exc = ParsingError(fname) exc.append(linecount, line) lineobj = make_comment(line) if isinstance(lineobj, OptionLine): if pending_lines: cur_section.extend(pending_lines) pending_lines = [] pending_empty_lines = False cur_option = LineContainer(lineobj) cur_section.add(cur_option) if self._optionxform: cur_option_name = self._optionxform(cur_option.name) else: cur_option_name = cur_option.name if cur_section_name == DEFAULTSECT: optobj = self._defaults else: optobj = self._sections[cur_section_name] optobj._options[cur_option_name] = cur_option if isinstance(lineobj, SectionLine): self._data.extend(pending_lines) pending_lines = [] pending_empty_lines = False cur_section = LineContainer(lineobj) self._data.add(cur_section) cur_option = None cur_option_name = None if cur_section.name == DEFAULTSECT: self._defaults._lines.append(cur_section) cur_section_name = DEFAULTSECT else: if self._sectionxform: cur_section_name = self._sectionxform(cur_section.name) else: cur_section_name = cur_section.name if cur_section_name not in self._sections: self._sections[cur_section_name] = \ INISection(cur_section, defaults=self._defaults, optionxformsource=self) else: self._sections[cur_section_name]._lines.append( cur_section) if isinstance(lineobj, (CommentLine, EmptyLine)): pending_lines.append(lineobj) if isinstance(lineobj, EmptyLine): pending_empty_lines = True self._data.extend(pending_lines) if line and line[-1] == '\n': self._data.add(EmptyLine()) if exc: raise exc