comparison 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
comparison
equal deleted inserted replaced
31926:932241b8c644 31927:2abc556dbe92
282 # even if it exists in mapping. this allows us to override mapping 282 # even if it exists in mapping. this allows us to override mapping
283 # by web templates, e.g. 'changelogtag' is redefined in map file. 283 # by web templates, e.g. 'changelogtag' is redefined in map file.
284 return context._load(exp[1]) 284 return context._load(exp[1])
285 raise error.ParseError(_("expected template specifier")) 285 raise error.ParseError(_("expected template specifier"))
286 286
287 def findsymbolicname(arg):
288 """Find symbolic name for the given compiled expression; returns None
289 if nothing found reliably"""
290 while True:
291 func, data = arg
292 if func is runsymbol:
293 return data
294 elif func is runfilter:
295 arg = data[0]
296 else:
297 return None
298
287 def evalfuncarg(context, mapping, arg): 299 def evalfuncarg(context, mapping, arg):
288 func, data = arg 300 func, data = arg
289 # func() may return string, generator of strings or arbitrary object such 301 # func() may return string, generator of strings or arbitrary object such
290 # as date tuple, but filter does not want generator. 302 # as date tuple, but filter does not want generator.
291 thing = func(context, mapping, data) 303 thing = func(context, mapping, data)
385 arg, filt = data 397 arg, filt = data
386 thing = evalfuncarg(context, mapping, arg) 398 thing = evalfuncarg(context, mapping, arg)
387 try: 399 try:
388 return filt(thing) 400 return filt(thing)
389 except (ValueError, AttributeError, TypeError): 401 except (ValueError, AttributeError, TypeError):
390 if isinstance(arg[1], tuple): 402 sym = findsymbolicname(arg)
391 dt = arg[1][1] 403 if sym:
404 msg = (_("template filter '%s' is not compatible with keyword '%s'")
405 % (filt.func_name, sym))
392 else: 406 else:
393 dt = arg[1] 407 msg = _("incompatible use of template filter '%s'") % filt.func_name
394 raise error.Abort(_("template filter '%s' is not compatible with " 408 raise error.Abort(msg)
395 "keyword '%s'") % (filt.func_name, dt))
396 409
397 def buildmap(exp, context): 410 def buildmap(exp, context):
398 func, data = compileexp(exp[1], context, methods) 411 func, data = compileexp(exp[1], context, methods)
399 tfunc, tdata = gettemplate(exp[2], context) 412 tfunc, tdata = gettemplate(exp[2], context)
400 return (runmap, (func, data, tfunc, tdata)) 413 return (runmap, (func, data, tfunc, tdata))