Show More
@@ -713,6 +713,9 b' class sessionvars(templateutil.wrapped):' | |||||
713 | def __copy__(self): |
|
713 | def __copy__(self): | |
714 | return sessionvars(copy.copy(self._vars), self._start) |
|
714 | return sessionvars(copy.copy(self._vars), self._start) | |
715 |
|
715 | |||
|
716 | def getmember(self, context, mapping, key): | |||
|
717 | return self._vars.get(key) | |||
|
718 | ||||
716 | def itermaps(self, context): |
|
719 | def itermaps(self, context): | |
717 | separator = self._start |
|
720 | separator = self._start | |
718 | for key, value in sorted(self._vars.iteritems()): |
|
721 | for key, value in sorted(self._vars.iteritems()): |
@@ -262,12 +262,13 b' def get(context, mapping, args):' | |||||
262 | raise error.ParseError(_("get() expects two arguments")) |
|
262 | raise error.ParseError(_("get() expects two arguments")) | |
263 |
|
263 | |||
264 | dictarg = evalwrapped(context, mapping, args[0]) |
|
264 | dictarg = evalwrapped(context, mapping, args[0]) | |
265 | if not util.safehasattr(dictarg, 'getmember'): |
|
265 | key = evalfuncarg(context, mapping, args[1]) | |
|
266 | try: | |||
|
267 | return dictarg.getmember(context, mapping, key) | |||
|
268 | except error.ParseError as err: | |||
266 | # i18n: "get" is a keyword |
|
269 | # i18n: "get" is a keyword | |
267 |
|
|
270 | hint = _("get() expects a dict as first argument") | |
268 |
|
271 | raise error.ParseError(bytes(err), hint=hint) | ||
269 | key = evalfuncarg(context, mapping, args[1]) |
|
|||
270 | return dictarg.getmember(context, mapping, key) |
|
|||
271 |
|
272 | |||
272 | @templatefunc('if(expr, then[, else])') |
|
273 | @templatefunc('if(expr, then[, else])') | |
273 | def if_(context, mapping, args): |
|
274 | def if_(context, mapping, args): |
@@ -38,6 +38,14 b' class wrapped(object):' | |||||
38 | __metaclass__ = abc.ABCMeta |
|
38 | __metaclass__ = abc.ABCMeta | |
39 |
|
39 | |||
40 | @abc.abstractmethod |
|
40 | @abc.abstractmethod | |
|
41 | def getmember(self, context, mapping, key): | |||
|
42 | """Return a member item for the specified key | |||
|
43 | ||||
|
44 | A returned object may be either a wrapped object or a pure value | |||
|
45 | depending on the self type. | |||
|
46 | """ | |||
|
47 | ||||
|
48 | @abc.abstractmethod | |||
41 | def itermaps(self, context): |
|
49 | def itermaps(self, context): | |
42 | """Yield each template mapping""" |
|
50 | """Yield each template mapping""" | |
43 |
|
51 | |||
@@ -72,6 +80,10 b' class wrappedbytes(wrapped):' | |||||
72 | def __init__(self, value): |
|
80 | def __init__(self, value): | |
73 | self._value = value |
|
81 | self._value = value | |
74 |
|
82 | |||
|
83 | def getmember(self, context, mapping, key): | |||
|
84 | raise error.ParseError(_('%r is not a dictionary') | |||
|
85 | % pycompat.bytestr(self._value)) | |||
|
86 | ||||
75 | def itermaps(self, context): |
|
87 | def itermaps(self, context): | |
76 | raise error.ParseError(_('%r is not iterable of mappings') |
|
88 | raise error.ParseError(_('%r is not iterable of mappings') | |
77 | % pycompat.bytestr(self._value)) |
|
89 | % pycompat.bytestr(self._value)) | |
@@ -91,6 +103,9 b' class wrappedvalue(wrapped):' | |||||
91 | def __init__(self, value): |
|
103 | def __init__(self, value): | |
92 | self._value = value |
|
104 | self._value = value | |
93 |
|
105 | |||
|
106 | def getmember(self, context, mapping, key): | |||
|
107 | raise error.ParseError(_('%r is not a dictionary') % self._value) | |||
|
108 | ||||
94 | def itermaps(self, context): |
|
109 | def itermaps(self, context): | |
95 | raise error.ParseError(_('%r is not iterable of mappings') |
|
110 | raise error.ParseError(_('%r is not iterable of mappings') | |
96 | % self._value) |
|
111 | % self._value) | |
@@ -196,6 +211,10 b' class mappable(wrapped):' | |||||
196 | def tomap(self): |
|
211 | def tomap(self): | |
197 | return self._makemap(self._key) |
|
212 | return self._makemap(self._key) | |
198 |
|
213 | |||
|
214 | def getmember(self, context, mapping, key): | |||
|
215 | w = makewrapped(context, mapping, self._value) | |||
|
216 | return w.getmember(context, mapping, key) | |||
|
217 | ||||
199 | def itermaps(self, context): |
|
218 | def itermaps(self, context): | |
200 | yield self.tomap() |
|
219 | yield self.tomap() | |
201 |
|
220 | |||
@@ -231,6 +250,9 b' class _mappingsequence(wrapped):' | |||||
231 | self._tmpl = tmpl |
|
250 | self._tmpl = tmpl | |
232 | self._defaultsep = sep |
|
251 | self._defaultsep = sep | |
233 |
|
252 | |||
|
253 | def getmember(self, context, mapping, key): | |||
|
254 | raise error.ParseError(_('not a dictionary')) | |||
|
255 | ||||
234 | def join(self, context, mapping, sep): |
|
256 | def join(self, context, mapping, sep): | |
235 | mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context)) |
|
257 | mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context)) | |
236 | if self._name: |
|
258 | if self._name: | |
@@ -294,6 +316,9 b' class mappedgenerator(wrapped):' | |||||
294 | def _gen(self, context): |
|
316 | def _gen(self, context): | |
295 | return self._make(context, *self._args) |
|
317 | return self._make(context, *self._args) | |
296 |
|
318 | |||
|
319 | def getmember(self, context, mapping, key): | |||
|
320 | raise error.ParseError(_('not a dictionary')) | |||
|
321 | ||||
297 | def itermaps(self, context): |
|
322 | def itermaps(self, context): | |
298 | raise error.ParseError(_('list of strings is not mappable')) |
|
323 | raise error.ParseError(_('list of strings is not mappable')) | |
299 |
|
324 | |||
@@ -678,15 +703,13 b' def runmember(context, mapping, data):' | |||||
678 | lm = context.overlaymap(mapping, d.tomap()) |
|
703 | lm = context.overlaymap(mapping, d.tomap()) | |
679 | return runsymbol(context, lm, memb) |
|
704 | return runsymbol(context, lm, memb) | |
680 | try: |
|
705 | try: | |
681 | if util.safehasattr(d, 'getmember'): |
|
706 | return d.getmember(context, mapping, memb) | |
682 | return d.getmember(context, mapping, memb) |
|
707 | except error.ParseError as err: | |
683 | raise error.ParseError |
|
|||
684 | except error.ParseError: |
|
|||
685 | sym = findsymbolicname(darg) |
|
708 | sym = findsymbolicname(darg) | |
686 | if sym: |
|
709 | if not sym: | |
687 | raise error.ParseError(_("keyword '%s' has no member") % sym) |
|
710 | raise | |
688 | else: |
|
711 | hint = _("keyword '%s' does not support member operation") % sym | |
689 | raise error.ParseError(_("%r has no member") % pycompat.bytestr(d)) |
|
712 | raise error.ParseError(bytes(err), hint=hint) | |
690 |
|
713 | |||
691 | def runnegate(context, mapping, data): |
|
714 | def runnegate(context, mapping, data): | |
692 | data = evalinteger(context, mapping, data, |
|
715 | data = evalinteger(context, mapping, data, |
@@ -3345,10 +3345,11 b' Test evaluation of dot operator:' | |||||
3345 | default |
|
3345 | default | |
3346 |
|
3346 | |||
3347 | $ hg log -R latesttag -l1 -T '{author.invalid}\n' |
|
3347 | $ hg log -R latesttag -l1 -T '{author.invalid}\n' | |
3348 |
hg: parse error: |
|
3348 | hg: parse error: 'test' is not a dictionary | |
|
3349 | (keyword 'author' does not support member operation) | |||
3349 | [255] |
|
3350 | [255] | |
3350 | $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n' |
|
3351 | $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n' | |
3351 |
hg: parse error: 'a' |
|
3352 | hg: parse error: 'a' is not a dictionary | |
3352 | [255] |
|
3353 | [255] | |
3353 |
|
3354 | |||
3354 | Test the sub function of templating for expansion: |
|
3355 | Test the sub function of templating for expansion: | |
@@ -3851,7 +3852,8 b' Test get function:' | |||||
3851 | $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n' |
|
3852 | $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n' | |
3852 | default |
|
3853 | default | |
3853 | $ hg log -r 0 --template '{get(files, "should_fail")}\n' |
|
3854 | $ hg log -r 0 --template '{get(files, "should_fail")}\n' | |
3854 |
hg: parse error: |
|
3855 | hg: parse error: not a dictionary | |
|
3856 | (get() expects a dict as first argument) | |||
3855 | [255] |
|
3857 | [255] | |
3856 |
|
3858 | |||
3857 | Test json filter applied to hybrid object: |
|
3859 | Test json filter applied to hybrid object: |
General Comments 0
You need to be logged in to leave comments.
Login now