def GetValue(self, parser, section, option, path): path = path.split(":") if (len(path) == 1): sec = section opt = parser.optionxform(path[0]) elif (len(path) == 2): sec = path[0] opt = parser.optionxform(path[1]) else: raise InterpolationSyntaxError(option, section, "More than one ':' found.") try: return self.GetCached(sec, opt) except KeyError: pass try: value = parser.get(sec, opt, raw=True) # print("GetValue: successful parser access: '{0}'".format(value)) except (KeyError, NoSectionError, NoOptionError) as ex: raise InterpolationMissingOptionError(option, section, "", ":".join(path)) from ex if (("$" in value) or ("%" in value)): value = self.interpolate(parser, sec, opt, value, {}) self.UpdateCache(sec, opt, value) return value
def _interpolate_some(self, parser, option, accum, rest, section, map, depth): rawval = parser.get(section, option, raw=True, fallback=rest) if depth > MAX_INTERPOLATION_DEPTH: raise InterpolationDepthError(option, section, rawval) while rest: p = rest.find("$") if p < 0: accum.append(rest) return if p > 0: accum.append(rest[:p]) rest = rest[p:] # p is no longer used c = rest[1:2] if c == "$": accum.append("$") rest = rest[2:] elif c == "{": m = self._KEYCRE.match(rest) if m is None: raise InterpolationSyntaxError( option, section, "bad interpolation variable reference %r" % rest) path = m.group(1).split(':') rest = rest[m.end():] sect = section opt = option try: if len(path) == 1: opt = parser.optionxform(path[0]) v = self._resolve_option(opt, map) elif len(path) == 2: sect = path[0] opt = path[1] v = self._resolve_section_option(sect, opt, parser) else: raise InterpolationSyntaxError( option, section, "More than one ':' found: %r" % (rest, )) except (KeyError, NoSectionError, NoOptionError): raise InterpolationMissingOptionError( option, section, rawval, ":".join(path)) from None if "$" in v: self._interpolate_some(parser, opt, accum, v, sect, dict(parser.items(sect, raw=True)), depth + 1) else: accum.append(v) else: raise InterpolationSyntaxError( option, section, "'$' must be followed by '$' or '{', " "found: %r" % (rest, ))
def interpolate_section_names(self, **kwargs): """Interpolate a specific key in a section name using val """ for section in self.sections(): s = section for key in self._interpvar_re.findall(section): try: val = kwargs[key] except KeyError: raise InterpolationMissingOptionError( '[%s]' % section, section, key, '%%(%s)s' % key) s = section % {key: val} self._sections[s] = self._sections.pop(section)
def _interpolate(self, section, option, rawval, vars): # do the string interpolation value = rawval depth = MAX_INTERPOLATION_DEPTH while depth: # Loop through this until it's done depth -= 1 if "%(" in value: try: value = value % vars except KeyError as e: raise InterpolationMissingOptionError( option, section, rawval, e.args[0]) else: break if value.find("%(") != -1: raise InterpolationDepthError(option, section, rawval) return value
def _interpolate_some(self, option, accum, rest, section, map, depth): if depth > MAX_INTERPOLATION_DEPTH: raise InterpolationDepthError(option, section, rest) while rest: p = rest.find("%") if p < 0: accum.append(rest) return if p > 0: accum.append(rest[:p]) rest = rest[p:] # p is no longer used c = rest[1:2] if c == "%": accum.append("%") rest = rest[2:] elif c == "(": m = self._interpvar_match(rest) if m is None: raise InterpolationSyntaxError( option, section, "bad interpolation variable reference %r" % rest) var = m.group(1) rest = rest[m.end():] try: v = map[var] except KeyError: raise InterpolationMissingOptionError( option, section, rest, var) if "%" in v: self._interpolate_some(option, accum, v, section, map, depth + 1) else: accum.append(v) else: raise InterpolationSyntaxError( option, section, "'%' must be followed by '%' or '(', found: " + repr(rest))
def before_get(self, parser, section, option, value, defaults): dollar_ind = value.find('$') if dollar_ind == -1: return value colon_ind = value.find('::') if colon_ind != -1 and value[dollar_ind + 1:colon_ind] == 'ENV': env_name = value[colon_ind + 2:] return parser.env.get(env_name) m = self._KEYCRE.match(value[dollar_ind:]) if m is None: raise InterpolationSyntaxError(option, section, f'bad interpolation variable reference {value}') var = parser.optionxform(m.group(1)) try: val = defaults[var] except KeyError: raise InterpolationMissingOptionError(option, section, value, var) from None # the resolved value can also contain variables val = self.before_get(parser, section, option, val, defaults) return val + value[m.end():]
def interpolate(self, parser, option, accum, rest, section, map, depth): # Mostly copy-pasted from the built-in configparser implementation. # We need to overwrite this method so we can add special handling for # block references :( All values produced here should be strings – # we need to wait until the whole config is interpreted anyways so # filling in incomplete values here is pointless. All we need is the # section reference so we can fetch it later. rawval = parser.get(section, option, raw=True, fallback=rest) if depth > MAX_INTERPOLATION_DEPTH: raise InterpolationDepthError(option, section, rawval) while rest: p = rest.find("$") if p < 0: accum.append(rest) return if p > 0: accum.append(rest[:p]) rest = rest[p:] # p is no longer used c = rest[1:2] if c == "$": accum.append("$") rest = rest[2:] elif c == "{": # We want to treat both ${a:b} and ${a.b} the same m = self._KEYCRE.match(rest) if m is None: err = f"bad interpolation variable reference {rest}" raise InterpolationSyntaxError(option, section, err) path = m.group(1).replace(":", ".").rsplit(".", 1) rest = rest[m.end():] sect = section opt = option try: if len(path) == 1: opt = parser.optionxform(path[0]) if opt in map: v = map[opt] else: # We have block reference, store it as a special key section_name = parser[parser.optionxform( path[0])]._name v = self._get_section_name(section_name) elif len(path) == 2: sect = path[0] opt = parser.optionxform(path[1]) fallback = "__FALLBACK__" v = parser.get(sect, opt, raw=True, fallback=fallback) # If a variable doesn't exist, try again and treat the # reference as a section if v == fallback: v = self._get_section_name( parser[f"{sect}.{opt}"]._name) else: err = f"More than one ':' found: {rest}" raise InterpolationSyntaxError(option, section, err) except (KeyError, NoSectionError, NoOptionError): raise InterpolationMissingOptionError( option, section, rawval, ":".join(path)) from None if "$" in v: new_map = dict(parser.items(sect, raw=True)) self.interpolate(parser, opt, accum, v, sect, new_map, depth + 1) else: accum.append(v) else: err = "'$' must be followed by '$' or '{', " "found: %r" % ( rest, ) raise InterpolationSyntaxError(option, section, err)