Patchwork [2,of,4] templater: remove __iter__() from _hybrid, resolve it explicitly

login
register
mail settings
Submitter Yuya Nishihara
Date April 4, 2017, 4 p.m.
Message ID <1c90b99b7e835b4f8d65.1491321657@mimosa>
Download mbox | patch
Permalink /patch/19954/
State Accepted
Headers show

Comments

Yuya Nishihara - April 4, 2017, 4 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1491311942 -32400
#      Tue Apr 04 22:19:02 2017 +0900
# Node ID 1c90b99b7e835b4f8d65329170a4830370ab2f04
# Parent  41891582b5c66541a40147e30e55153b6a0f2d79
templater: remove __iter__() from _hybrid, resolve it explicitly

The goal is to fix "{hybrid_obj|json}" output.

A _hybrid object must act as a list or a dict as well as a generator of
legacy template strings. Before, _hybrid.__iter__() was assigned for legacy
template, which conflicted with list.__iter__() API.

This patch drops _hybrid.__iter__() and makes stringify/flatten functions
unwrap a generator instead.

Patch

diff --git a/mercurial/templatefilters.py b/mercurial/templatefilters.py
--- a/mercurial/templatefilters.py
+++ b/mercurial/templatefilters.py
@@ -350,6 +350,7 @@  def stringify(thing):
     """Any type. Turns the value into text by converting values into
     text and concatenating them.
     """
+    thing = templatekw.unwraphybrid(thing)
     if util.safehasattr(thing, '__iter__') and not isinstance(thing, str):
         return "".join([stringify(t) for t in thing if t is not None])
     if thing is None:
diff --git a/mercurial/templatekw.py b/mercurial/templatekw.py
--- a/mercurial/templatekw.py
+++ b/mercurial/templatekw.py
@@ -35,8 +35,6 @@  class _hybrid(object):
         self.values = values
         self._makemap = makemap
         self.joinfmt = joinfmt
-    def __iter__(self):
-        return self.gen
     def itermaps(self):
         makemap = self._makemap
         for x in self.values:
@@ -50,6 +48,13 @@  class _hybrid(object):
             raise AttributeError(name)
         return getattr(self.values, name)
 
+def unwraphybrid(thing):
+    """Return an object which can be stringified possibly by using a legacy
+    template"""
+    if not util.safehasattr(thing, 'gen'):
+        return thing
+    return thing.gen
+
 def showlist(name, values, plural=None, element=None, separator=' ', **args):
     if not element:
         element = name
diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -1018,6 +1018,7 @@  stringify = templatefilters.stringify
 
 def _flatten(thing):
     '''yield a single stream from a possibly nested set of iterators'''
+    thing = templatekw.unwraphybrid(thing)
     if isinstance(thing, str):
         yield thing
     elif thing is None:
@@ -1026,6 +1027,7 @@  def _flatten(thing):
         yield str(thing)
     else:
         for i in thing:
+            i = templatekw.unwraphybrid(i)
             if isinstance(i, str):
                 yield i
             elif i is None: