--- a/mercurial/templateutil.py Wed Mar 21 01:39:44 2018 +0900
+++ b/mercurial/templateutil.py Wed Mar 21 11:30:21 2018 +0900
@@ -38,6 +38,14 @@
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
+ def getmember(self, context, mapping, key):
+ """Return a member item for the specified key
+
+ A returned object may be either a wrapped object or a pure value
+ depending on the self type.
+ """
+
+ @abc.abstractmethod
def itermaps(self, context):
"""Yield each template mapping"""
@@ -72,6 +80,10 @@
def __init__(self, value):
self._value = value
+ def getmember(self, context, mapping, key):
+ raise error.ParseError(_('%r is not a dictionary')
+ % pycompat.bytestr(self._value))
+
def itermaps(self, context):
raise error.ParseError(_('%r is not iterable of mappings')
% pycompat.bytestr(self._value))
@@ -91,6 +103,9 @@
def __init__(self, value):
self._value = value
+ def getmember(self, context, mapping, key):
+ raise error.ParseError(_('%r is not a dictionary') % self._value)
+
def itermaps(self, context):
raise error.ParseError(_('%r is not iterable of mappings')
% self._value)
@@ -196,6 +211,10 @@
def tomap(self):
return self._makemap(self._key)
+ def getmember(self, context, mapping, key):
+ w = makewrapped(context, mapping, self._value)
+ return w.getmember(context, mapping, key)
+
def itermaps(self, context):
yield self.tomap()
@@ -231,6 +250,9 @@
self._tmpl = tmpl
self._defaultsep = sep
+ def getmember(self, context, mapping, key):
+ raise error.ParseError(_('not a dictionary'))
+
def join(self, context, mapping, sep):
mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
if self._name:
@@ -294,6 +316,9 @@
def _gen(self, context):
return self._make(context, *self._args)
+ def getmember(self, context, mapping, key):
+ raise error.ParseError(_('not a dictionary'))
+
def itermaps(self, context):
raise error.ParseError(_('list of strings is not mappable'))
@@ -678,15 +703,13 @@
lm = context.overlaymap(mapping, d.tomap())
return runsymbol(context, lm, memb)
try:
- if util.safehasattr(d, 'getmember'):
- return d.getmember(context, mapping, memb)
- raise error.ParseError
- except error.ParseError:
+ return d.getmember(context, mapping, memb)
+ except error.ParseError as err:
sym = findsymbolicname(darg)
- if sym:
- raise error.ParseError(_("keyword '%s' has no member") % sym)
- else:
- raise error.ParseError(_("%r has no member") % pycompat.bytestr(d))
+ if not sym:
+ raise
+ hint = _("keyword '%s' does not support member operation") % sym
+ raise error.ParseError(bytes(err), hint=hint)
def runnegate(context, mapping, data):
data = evalinteger(context, mapping, data,