changeset 37404:7c902a8345ef

templater: complain about invalid application of '%' operator (BC) Before, '{x % y % z ...}' was silently evaluated as '{x % y}'. We no longer need this hack since the web template bugs was fixed by earlier patches. At this point, the error message may contain '<generator *>', which will be fixed later.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 18 Mar 2018 21:01:23 +0900
parents 448f7ec247e2
children da8e9ecac4a4
files mercurial/templateutil.py tests/test-command-template.t
diffstat 2 files changed, 27 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/templateutil.py	Sun Mar 18 21:18:57 2018 +0900
+++ b/mercurial/templateutil.py	Sun Mar 18 21:01:23 2018 +0900
@@ -567,6 +567,20 @@
     return (_("template filter '%s' is not compatible with keyword '%s'")
             % (fn, sym))
 
+def _checkeditermaps(darg, d):
+    try:
+        for v in d:
+            if not isinstance(v, dict):
+                raise TypeError
+            yield v
+    except TypeError:
+        sym = findsymbolicname(darg)
+        if sym:
+            raise error.ParseError(_("keyword '%s' is not iterable of mappings")
+                                   % sym)
+        else:
+            raise error.ParseError(_("%r is not iterable of mappings") % d)
+
 def _iteroverlaymaps(context, origmapping, newmappings):
     """Generate combined mappings from the original mapping and an iterable
     of partial mappings to override the original"""
@@ -578,28 +592,17 @@
 def runmap(context, mapping, data):
     darg, targ = data
     d = evalrawexp(context, mapping, darg)
+    # TODO: a generator should be rejected because it is a thunk of lazy
+    # string, but we can't because hgweb abuses generator as a keyword
+    # that returns a list of dicts.
     if isinstance(d, wrapped):
         diter = d.itermaps(context)
     else:
-        try:
-            diter = iter(d)
-        except TypeError:
-            sym = findsymbolicname(darg)
-            if sym:
-                raise error.ParseError(_("keyword '%s' is not iterable") % sym)
-            else:
-                raise error.ParseError(_("%r is not iterable") % d)
-
+        diter = _checkeditermaps(darg, d)
     for i, v in enumerate(diter):
-        if isinstance(v, dict):
-            lm = context.overlaymap(mapping, v)
-            lm['index'] = i
-            yield evalrawexp(context, lm, targ)
-        else:
-            # v is not an iterable of dicts, this happen when 'key'
-            # has been fully expanded already and format is useless.
-            # If so, return the expanded value.
-            yield v
+        lm = context.overlaymap(mapping, v)
+        lm['index'] = i
+        yield evalrawexp(context, lm, targ)
 
 def runmember(context, mapping, data):
     darg, memb = data
--- a/tests/test-command-template.t	Sun Mar 18 21:18:57 2018 +0900
+++ b/tests/test-command-template.t	Sun Mar 18 21:01:23 2018 +0900
@@ -3210,10 +3210,13 @@
   
 
   $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
-  hg: parse error: keyword 'rev' is not iterable
+  hg: parse error: keyword 'rev' is not iterable of mappings
   [255]
   $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
-  hg: parse error: None is not iterable
+  hg: parse error: None is not iterable of mappings
+  [255]
+  $ hg log -R latesttag -r tip -T '{extras % "{key}\n" % "{key}\n"}'
+  hg: parse error: <generator *> is not iterable of mappings (glob)
   [255]
 
 Test new-style inline templating of non-list/dict type:
@@ -3228,7 +3231,7 @@
   $ hg log -R latesttag -r tip -T '{get(extras, "branch") % "{key}: {value}\n"}'
   branch: default
   $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "{key}\n"}'
-  hg: parse error: None is not iterable
+  hg: parse error: None is not iterable of mappings
   [255]
   $ hg log -R latesttag -r tip -T '{min(extras) % "{key}: {value}\n"}'
   branch: default