# HG changeset patch # User Yuya Nishihara <y...@tcha.org> # Date 1506843424 -3600 # Sun Oct 01 08:37:04 2017 +0100 # Node ID 743f288540ff52670eb36e5728c4bf35fcca2a07 # Parent 8de6dc4ab3304251a0bce4154603b784d4d519a0 formatter: fix default list/dict generator to be evaluated more than once
Before, _hybrid.gen must be a generator which could be consumed only once. It was okay in templatekw.py since template keywords are functions which create temporary hybrid objects, but the formatter doesn't work in that way. To work around the issue, this patch makes _hybrid.gen optionally be a function returning a generator. Thanks to Pulkit for finding this issue. diff --git a/mercurial/formatter.py b/mercurial/formatter.py --- a/mercurial/formatter.py +++ b/mercurial/formatter.py @@ -348,15 +348,14 @@ class _templateconverter(object): data = util.sortdict(_iteritems(data)) def f(): yield _plainconverter.formatdict(data, key, value, fmt, sep) - return templatekw.hybriddict(data, key=key, value=value, fmt=fmt, - gen=f()) + return templatekw.hybriddict(data, key=key, value=value, fmt=fmt, gen=f) @staticmethod def formatlist(data, name, fmt, sep): '''build object that can be evaluated as either plain string or list''' data = list(data) def f(): yield _plainconverter.formatlist(data, name, fmt, sep) - return templatekw.hybridlist(data, name=name, fmt=fmt, gen=f()) + return templatekw.hybridlist(data, name=name, fmt=fmt, gen=f) class templateformatter(baseformatter): def __init__(self, ui, out, topic, opts): diff --git a/mercurial/templatekw.py b/mercurial/templatekw.py --- a/mercurial/templatekw.py +++ b/mercurial/templatekw.py @@ -39,15 +39,12 @@ class _hybrid(object): def __init__(self, gen, values, makemap, joinfmt): if gen is not None: - self.gen = gen + self.gen = gen # generator or function returning generator self._values = values self._makemap = makemap self.joinfmt = joinfmt - @util.propertycache def gen(self): - return self._defaultgen() - def _defaultgen(self): - """Generator to stringify this as {join(self, ' ')}""" + """Default generator to stringify this as {join(self, ' ')}""" for i, x in enumerate(self._values): if i > 0: yield ' ' @@ -104,9 +101,12 @@ def hybridlist(data, name, fmt='%s', gen def unwraphybrid(thing): """Return an object which can be stringified possibly by using a legacy template""" - if not util.safehasattr(thing, 'gen'): + gen = getattr(thing, 'gen', None) + if gen is None: return thing - return thing.gen + if callable(gen): + return gen() + return gen def unwrapvalue(thing): """Move the inner value object out of the wrapper""" @@ -685,7 +685,7 @@ def showsuccessorssets(repo, ctx, **args # Format the successorssets def render(d): t = [] - for i in d.gen: + for i in d.gen(): t.append(i) return "".join(t) diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t --- a/tests/test-obsolete.t +++ b/tests/test-obsolete.t @@ -760,8 +760,12 @@ Template keywords 3de5eca88c00 ????-??-?? (glob) $ hg debugobsolete -r6 -T '{join(metadata % "{key}={value}", " ")}\n' user=test <t...@example.net> - $ hg debugobsolete -r6 -T '{metadata}\n' + $ hg debugobsolete -r6 -T '{metadata}\n{metadata}\n' + 'user': 'test <t...@example.net>' 'user': 'test <t...@example.net>' + $ hg debugobsolete -r6 -T '{succnodes}\n{succnodes}\n' + 3de5eca88c00aa039da7399a220f4a5221faa585 + 3de5eca88c00aa039da7399a220f4a5221faa585 $ hg debugobsolete -r6 -T '{flag} {get(metadata, "user")}\n' 0 test <t...@example.net> _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel