diff mercurial/pycompat.py @ 38576:152f4822d210

pycompat: move rapply() from util I want to use rapply() in utils.* modules, but that would introduce a reference cycle util -> utils.* -> util. Moving rapply() to pycompat should be okay since it mostly serves as a compatibility helper.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 10 Jun 2018 17:07:29 +0900
parents 7b12a2d2eedc
children 7eba8f83129b
line wrap: on
line diff
--- a/mercurial/pycompat.py	Thu Jul 05 09:53:00 2018 +0530
+++ b/mercurial/pycompat.py	Sun Jun 10 17:07:29 2018 +0900
@@ -47,6 +47,39 @@
 def identity(a):
     return a
 
+def _rapply(f, xs):
+    if xs is None:
+        # assume None means non-value of optional data
+        return xs
+    if isinstance(xs, (list, set, tuple)):
+        return type(xs)(_rapply(f, x) for x in xs)
+    if isinstance(xs, dict):
+        return type(xs)((_rapply(f, k), _rapply(f, v)) for k, v in xs.items())
+    return f(xs)
+
+def rapply(f, xs):
+    """Apply function recursively to every item preserving the data structure
+
+    >>> def f(x):
+    ...     return 'f(%s)' % x
+    >>> rapply(f, None) is None
+    True
+    >>> rapply(f, 'a')
+    'f(a)'
+    >>> rapply(f, {'a'}) == {'f(a)'}
+    True
+    >>> rapply(f, ['a', 'b', None, {'c': 'd'}, []])
+    ['f(a)', 'f(b)', None, {'f(c)': 'f(d)'}, []]
+
+    >>> xs = [object()]
+    >>> rapply(identity, xs) is xs
+    True
+    """
+    if f is identity:
+        # fast path mainly for py2
+        return xs
+    return _rapply(f, xs)
+
 if ispy3:
     import builtins
     import functools