changeset 530:28191d61b042

FIX: Handle non-cacheable interpolations properly. Currently all non-default namespaces prohibit interpolation caching.
author Franz Glasner <f.glasner@feldmann-mg.com>
date Mon, 20 Dec 2021 14:33:54 +0100
parents 9976ff66c439
children be740ed67d16
files configmix/config.py
diffstat 1 files changed, 43 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/configmix/config.py	Mon Dec 20 14:33:09 2021 +0100
+++ b/configmix/config.py	Mon Dec 20 14:33:54 2021 +0100
@@ -631,6 +631,29 @@
             else:
                 return default
 
+    def _getvar_s_with_cache_info(self, varname):
+        """Internal variant of :meth:`~.getvar_s` that returns some information
+        whether caching of interpolated values is allowed
+
+        Caching is currently not allowed when namespaces are used.
+
+        Currently used by :meth:`~.interpolate_variables`.
+
+        """
+        varns, varname = self._split_ns(varname)
+        if not varns:
+            cacheable = True
+            if varname:
+                varnameparts = tuple([unquote(vp)
+                                      for vp in varname.split(_HIER_SEPARATOR)])
+            else:
+                varnameparts = tuple()
+        else:
+            cacheable = False
+            varnameparts = (varname,)
+        obj = self.getvarl(*varnameparts, namespace=varns)
+        return (self.substitute_variables_in_obj(obj), cacheable)
+
     def getfirstvar_s(self, *varnames, **kwds):
         """A variant of :meth:`~.getvar_s` that returns the first found
         variable in the list of given variables in `varnames`.
@@ -776,11 +799,20 @@
             return s
         res = self.__interpolation_cache.get(s, _MARKER)
         if res is not _MARKER:
-            return res
+            if res is _MISSING:
+                warnings.warn("Cannot interpolate variables in string "
+                              "%r (cached)" % (s, ),
+                              UserWarning,
+                              stacklevel=1)
+                raise KeyError("Cannot interpolate variables in string "
+                               "%r (cached)" % (s, ))
+            else:
+                return res
         len_s = len(s)
         res = []
         res_append = res.append
         rest = 0
+        use_cache = True
         while start != -1:
             res_append(s[rest:start])
             end = s.find(_ENDTOK, start)
@@ -790,18 +822,22 @@
             varname, filters = self._split_filters(
                 s[start+2:end])
             try:
-                varvalue = self.getvar_s(varname)
+                varvalue, cacheable = self._getvar_s_with_cache_info(varname)
             except KeyError:
+                cacheable = True
                 if NONE_FILTER in filters:
                     varvalue = None
                 elif EMPTY_FILTER in filters:
                     varvalue = _EMPTY_STR
                 else:
-                    warnings.warn("Cannot expand variable %r in string "
+                    self.__interpolation_cache[s] = _MISSING
+                    warnings.warn("Cannot interpolate variable %r in string "
                                   "%r" % (varname, s, ),
                                   UserWarning,
                                   stacklevel=1)
                     raise
+            if not cacheable:
+                use_cache = False
             varvalue = self._apply_filters(filters, varvalue)
             rest = end + 2
             #
@@ -809,7 +845,8 @@
             # the whole `s` is just one expansion
             #
             if (start == 0) and (rest == len_s):
-                self.__interpolation_cache[s] = varvalue
+                if use_cache:
+                    self.__interpolation_cache[s] = varvalue
                 return varvalue
             if varvalue is None:
                 pass
@@ -819,7 +856,8 @@
             start = s.find(_STARTTOK, rest)
         res_append(s[rest:])
         res = _EMPTY_STR.join(res)
-        self.__interpolation_cache[s] = res
+        if use_cache:
+            self.__interpolation_cache[s] = res
         return res
 
     def _apply_filters(self, filters, value):