Patchwork [7,of,8] templater: complain about invalid application of '%' operator (BC)

login
register
mail settings
Submitter Yuya Nishihara
Date April 5, 2018, 2:37 p.m.
Message ID <00c9dda81b49f4242f17.1522939045@mimosa>
Download mbox | patch
Permalink /patch/30382/
State Accepted
Headers show

Comments

Yuya Nishihara - April 5, 2018, 2:37 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1521374483 -32400
#      Sun Mar 18 21:01:23 2018 +0900
# Node ID 00c9dda81b49f4242f174fd218c68b5c8bbc5fea
# Parent  1c22443660286f711ea1c6993f6aef77d82a5c63
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.

Patch

diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py
--- a/mercurial/templateutil.py
+++ b/mercurial/templateutil.py
@@ -567,6 +567,20 @@  def _formatfiltererror(arg, filt):
     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 _iteroverlaymaps(context, origmappin
 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
diff --git a/tests/test-command-template.t b/tests/test-command-template.t
--- a/tests/test-command-template.t
+++ b/tests/test-command-template.t
@@ -3210,10 +3210,13 @@  Test new-style inline templating:
   
 
   $ 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 @@  Test new-style inline templating of non-
   $ 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