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 new_interpolate(cur_sect, cur_key, value, lookup_func): """Recursive interp >>> lookup = lambda s, x: '<'+x+'>' >>> new_interpolate('sect', 'key', 'text', lookup) 'text' >>> new_interpolate('sect', 'key', 'foo.${baz}.com', lookup) 'foo.<baz>.com' >>> new_interpolate('sect', 'key', 'foo.${baz.${goo}.zap}.com', lookup) 'foo.<baz.<goo>.zap>.com' """ if not value: return value pos = 0 dst = [] while pos < len(value): m = _NEW_VAR_OPEN_RX.search(value, pos) if not m: dst.append(value[pos:]) break pos2 = m.start() if pos2 > pos: dst.append(value[pos:pos2]) pos = m.end() tok = m.group(0) if tok == '$$': dst.append('$') elif tok == '${': subval, pos = _scan_key(cur_sect, cur_key, value, pos, lookup_func) dst.append(subval) else: raise InterpolationSyntaxError(cur_key, cur_sect, 'Interpolation parse error') return ''.join(dst)
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, 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 GetSpecial(self, section, option, path): parts = section.split(".") if (path == "Root"): return parts[0] elif (path == "Parent"): return ".".join(parts[1:-1]) elif (path == "ParentWithRoot"): return ".".join(parts[:-1]) elif (path == "GrantParent"): return ".".join(parts[1:-2]) elif (path == "Path"): return ".".join(parts[1:]) elif (path == "PathWithRoot"): return section elif (path == "Name"): return parts[-1] else: raise InterpolationSyntaxError( option, section, "Unknown keyword '{0}'in special operator.".format(path))
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)
def interpolate(self, parser, section, option, value, _, depth=0): if depth > MAX_INTERPOLATION_DEPTH: raise InterpolationDepthError(option, section, value) # short cut operations if empty or a normal string if (value == ""): # print("interpol: SHORT -> empty string") return "" elif (("$" not in value) and ("%" not in value)): # print("interpol: SHORT -> {0}".format(value)) return value # print("interpol: PREPARE section={0} option={1} value='{2}'".format(section, option, value)) rawValue = value rest = "" while (len(rawValue) > 0): beginPos = rawValue.find("%") if (beginPos < 0): rest += rawValue rawValue = "" else: rest += rawValue[:beginPos] if (rawValue[beginPos + 1] == "%"): rest += "%" rawValue = rawValue[1:] elif (rawValue[beginPos + 1] == "{"): endPos = rawValue.find("}", beginPos) if (endPos < 0): raise InterpolationSyntaxError( option, section, "bad interpolation variable reference {0!r}". format(rawValue)) path = rawValue[beginPos + 2:endPos] rawValue = rawValue[endPos + 1:] rest += self.GetSpecial(section, option, path) # print("interpol: BEGIN section={0} option={1} value='{2}'".format(section, option, rest)) result = "" while (len(rest) > 0): # print("interpol: LOOP rest='{0}'".format(rest)) beginPos = rest.find("$") if (beginPos < 0): result += rest rest = "" else: result += rest[:beginPos] if (rest[beginPos + 1] == "$"): result += "$" rest = rest[1:] elif (rest[beginPos + 1] == "{"): endPos = rest.find("}", beginPos) nextPos = rest.rfind("$", beginPos, endPos) if (endPos < 0): raise InterpolationSyntaxError( option, section, "bad interpolation variable reference {0!r}". format(rest)) if ((nextPos > 0) and (nextPos < endPos)): # an embedded $-sign path = rest[nextPos + 2:endPos] # print("interpol: path='{0}'".format(path)) innervalue = self.GetValue(parser, section, option, path) # innervalue = self.interpolate(parser, section, option, path, map, depth + 1) # print("interpol: innervalue='{0}'".format(innervalue)) rest = rest[beginPos:nextPos] + innervalue + rest[ endPos + 1:] # print("interpol: new rest='{0}'".format(rest)) else: path = rest[beginPos + 2:endPos] rest = rest[endPos + 1:] result += self.GetValue(parser, section, option, path) # print("interpol: LOOP END - result='{0}'".format(result)) # print("interpol: RESULT => '{0}'".format(result)) return result