diff mercurial/templater.py @ 31927:2abc556dbe92

templater: find keyword name more thoroughly on filtering error Before, it could spill an internal representation of compiled template such as [(<function runsymbol at 0x....>, 'extras'), ...]. Show less cryptic message if no symbol found. New findsymbolicname() function will be also used by dict() constructor.
author Yuya Nishihara <yuya@tcha.org>
date Sat, 08 Apr 2017 23:33:32 +0900
parents 932241b8c644
children 277b3e2d711b
line wrap: on
line diff
--- a/mercurial/templater.py	Mon Apr 03 22:54:06 2017 +0900
+++ b/mercurial/templater.py	Sat Apr 08 23:33:32 2017 +0900
@@ -284,6 +284,18 @@
         return context._load(exp[1])
     raise error.ParseError(_("expected template specifier"))
 
+def findsymbolicname(arg):
+    """Find symbolic name for the given compiled expression; returns None
+    if nothing found reliably"""
+    while True:
+        func, data = arg
+        if func is runsymbol:
+            return data
+        elif func is runfilter:
+            arg = data[0]
+        else:
+            return None
+
 def evalfuncarg(context, mapping, arg):
     func, data = arg
     # func() may return string, generator of strings or arbitrary object such
@@ -387,12 +399,13 @@
     try:
         return filt(thing)
     except (ValueError, AttributeError, TypeError):
-        if isinstance(arg[1], tuple):
-            dt = arg[1][1]
+        sym = findsymbolicname(arg)
+        if sym:
+            msg = (_("template filter '%s' is not compatible with keyword '%s'")
+                   % (filt.func_name, sym))
         else:
-            dt = arg[1]
-        raise error.Abort(_("template filter '%s' is not compatible with "
-                           "keyword '%s'") % (filt.func_name, dt))
+            msg = _("incompatible use of template filter '%s'") % filt.func_name
+        raise error.Abort(msg)
 
 def buildmap(exp, context):
     func, data = compileexp(exp[1], context, methods)