[PATCH 1 of 8] templater: pass context down to unwraphybrid()

Yuya Nishihara yuya at tcha.org
Sat Mar 31 22:45:58 EDT 2018


# HG changeset patch
# User Yuya Nishihara <yuya at tcha.org>
# Date 1521284945 -32400
#      Sat Mar 17 20:09:05 2018 +0900
# Node ID 529838f7858556c0f9d180a276b483578c6d55d4
# Parent  02079695afdd39020b13f238c69691dce14b932f
templater: pass context down to unwraphybrid()

See the subsequent patches for why.

Unlike eval*() functions, flatten(), stringify(), and unwraphybrid() don't
take a mapping since these functions may be applied to a tree of generators
where each node should be bound to the mapping when it was evaluated.

diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py
--- a/mercurial/templatefuncs.py
+++ b/mercurial/templatefuncs.py
@@ -283,7 +283,7 @@ def ifcontains(context, mapping, args):
     keytype = getattr(haystack, 'keytype', None)
     try:
         needle = evalrawexp(context, mapping, args[0])
-        needle = templateutil.unwrapastype(needle, keytype or bytes)
+        needle = templateutil.unwrapastype(context, needle, keytype or bytes)
         found = (needle in haystack)
     except error.ParseError:
         found = False
diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -679,7 +679,7 @@ class engine(object):
         if extramapping:
             extramapping.update(mapping)
             mapping = extramapping
-        return templateutil.flatten(func(self, mapping, data))
+        return templateutil.flatten(self, func(self, mapping, data))
 
 engines = {'default': engine}
 
diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py
--- a/mercurial/templateutil.py
+++ b/mercurial/templateutil.py
@@ -120,7 +120,7 @@ def hybridlist(data, name, fmt=None, gen
         prefmt = pycompat.bytestr
     return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x))
 
-def unwraphybrid(thing):
+def unwraphybrid(context, thing):
     """Return an object which can be stringified possibly by using a legacy
     template"""
     gen = getattr(thing, 'gen', None)
@@ -241,9 +241,9 @@ def _showcompatlist(context, mapping, na
     if context.preload(endname):
         yield context.process(endname, mapping)
 
-def flatten(thing):
+def flatten(context, thing):
     """Yield a single stream from a possibly nested set of iterators"""
-    thing = unwraphybrid(thing)
+    thing = unwraphybrid(context, thing)
     if isinstance(thing, bytes):
         yield thing
     elif isinstance(thing, str):
@@ -257,7 +257,7 @@ def flatten(thing):
         yield pycompat.bytestr(thing)
     else:
         for i in thing:
-            i = unwraphybrid(i)
+            i = unwraphybrid(context, i)
             if isinstance(i, bytes):
                 yield i
             elif i is None:
@@ -265,14 +265,14 @@ def flatten(thing):
             elif not util.safehasattr(i, '__iter__'):
                 yield pycompat.bytestr(i)
             else:
-                for j in flatten(i):
+                for j in flatten(context, i):
                     yield j
 
-def stringify(thing):
+def stringify(context, thing):
     """Turn values into bytes by converting into text and concatenating them"""
     if isinstance(thing, bytes):
         return thing  # retain localstr to be round-tripped
-    return b''.join(flatten(thing))
+    return b''.join(flatten(context, thing))
 
 def findsymbolicname(arg):
     """Find symbolic name for the given compiled expression; returns None
@@ -294,17 +294,17 @@ def evalrawexp(context, mapping, arg):
 
 def evalfuncarg(context, mapping, arg):
     """Evaluate given argument as value type"""
-    return _unwrapvalue(evalrawexp(context, mapping, arg))
+    return _unwrapvalue(context, evalrawexp(context, mapping, arg))
 
 # TODO: unify this with unwrapvalue() once the bug of templatefunc.join()
 # is fixed. we can't do that right now because join() has to take a generator
 # of byte strings as it is, not a lazy byte string.
-def _unwrapvalue(thing):
+def _unwrapvalue(context, thing):
     thing = unwrapvalue(thing)
     # evalrawexp() may return string, generator of strings or arbitrary object
     # such as date tuple, but filter does not want generator.
     if isinstance(thing, types.GeneratorType):
-        thing = stringify(thing)
+        thing = stringify(context, thing)
     return thing
 
 def evalboolean(context, mapping, arg):
@@ -322,15 +322,15 @@ def evalboolean(context, mapping, arg):
         return thing
     # other objects are evaluated as strings, which means 0 is True, but
     # empty dict/list should be False as they are expected to be ''
-    return bool(stringify(thing))
+    return bool(stringify(context, thing))
 
 def evaldate(context, mapping, arg, err=None):
     """Evaluate given argument as a date tuple or a date string; returns
     a (unixtime, offset) tuple"""
-    return unwrapdate(evalrawexp(context, mapping, arg), err)
+    return unwrapdate(context, evalrawexp(context, mapping, arg), err)
 
-def unwrapdate(thing, err=None):
-    thing = _unwrapvalue(thing)
+def unwrapdate(context, thing, err=None):
+    thing = _unwrapvalue(context, thing)
     try:
         return dateutil.parsedate(thing)
     except AttributeError:
@@ -341,17 +341,17 @@ def unwrapdate(thing, err=None):
         raise error.ParseError(err)
 
 def evalinteger(context, mapping, arg, err=None):
-    return unwrapinteger(evalrawexp(context, mapping, arg), err)
+    return unwrapinteger(context, evalrawexp(context, mapping, arg), err)
 
-def unwrapinteger(thing, err=None):
-    thing = _unwrapvalue(thing)
+def unwrapinteger(context, thing, err=None):
+    thing = _unwrapvalue(context, thing)
     try:
         return int(thing)
     except (TypeError, ValueError):
         raise error.ParseError(err or _('not an integer'))
 
 def evalstring(context, mapping, arg):
-    return stringify(evalrawexp(context, mapping, arg))
+    return stringify(context, evalrawexp(context, mapping, arg))
 
 def evalstringliteral(context, mapping, arg):
     """Evaluate given argument as string template, but returns symbol name
@@ -361,7 +361,7 @@ def evalstringliteral(context, mapping, 
         thing = func(context, mapping, data, default=data)
     else:
         thing = func(context, mapping, data)
-    return stringify(thing)
+    return stringify(context, thing)
 
 _unwrapfuncbytype = {
     None: _unwrapvalue,
@@ -370,13 +370,13 @@ def evalstringliteral(context, mapping, 
     int: unwrapinteger,
 }
 
-def unwrapastype(thing, typ):
+def unwrapastype(context, thing, typ):
     """Move the inner value object out of the wrapper and coerce its type"""
     try:
         f = _unwrapfuncbytype[typ]
     except KeyError:
         raise error.ProgrammingError('invalid type specified: %r' % typ)
-    return f(thing)
+    return f(context, thing)
 
 def runinteger(context, mapping, data):
     return int(data)
@@ -426,7 +426,7 @@ def runfilter(context, mapping, data):
     arg, filt = data
     thing = evalrawexp(context, mapping, arg)
     try:
-        thing = unwrapastype(thing, getattr(filt, '_intype', None))
+        thing = unwrapastype(context, thing, getattr(filt, '_intype', None))
         return filt(thing)
     except error.ParseError as e:
         raise error.ParseError(bytes(e), hint=_formatfiltererror(arg, filt))
diff --git a/tests/test-template-engine.t b/tests/test-template-engine.t
--- a/tests/test-template-engine.t
+++ b/tests/test-template-engine.t
@@ -24,7 +24,7 @@
   >                 v = v(**pycompat.strkwargs(props))
   >             elif callable(v):
   >                 v = v(self, props)
-  >             v = templateutil.stringify(v)
+  >             v = templateutil.stringify(self, v)
   >             tmpl = tmpl.replace(b'{{%s}}' % k, v)
   >         yield tmpl
   > 


More information about the Mercurial-devel mailing list