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.
--- 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)
--- a/tests/test-command-template.t Mon Apr 03 22:54:06 2017 +0900
+++ b/tests/test-command-template.t Sat Apr 08 23:33:32 2017 +0900
@@ -2684,6 +2684,14 @@
hg: parse error: date expects a date information
[255]
+ $ hg tip -T '{author|email|shortdate}\n'
+ abort: template filter 'shortdate' is not compatible with keyword 'author'
+ [255]
+
+ $ hg tip -T '{get(extras, "branch")|shortdate}\n'
+ abort: incompatible use of template filter 'shortdate'
+ [255]
+
Error in nested template:
$ hg log -T '{"date'