pycompat: move rapply() from util
authorYuya Nishihara <yuya@tcha.org>
Sun, 10 Jun 2018 17:07:29 +0900
changeset 46860 152f4822d21068b4b4343de67a46e56e2742b58b
parent 46859 f442c9494ec70e25583386e89c4b981b5ca4680c
child 46861 a3130208db1cff69cdd9133780963595fc6c5a9e
push id826
push usergszorc@mozilla.com
push dateSun, 08 Jul 2018 00:11:10 +0000
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.
mercurial/cmdutil.py
mercurial/pycompat.py
mercurial/revset.py
mercurial/scmutil.py
mercurial/smartset.py
mercurial/ui.py
mercurial/util.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1675,17 +1675,17 @@ def showmarker(fm, marker, index=None):
     fm.write('flag', '%X ', marker.flags())
     parents = marker.parentnodes()
     if parents is not None:
         fm.write('parentnodes', '{%s} ',
                  fm.formatlist(map(hex, parents), name='node', sep=', '))
     fm.write('date', '(%s) ', fm.formatdate(marker.date()))
     meta = marker.metadata().copy()
     meta.pop('date', None)
-    smeta = util.rapply(pycompat.maybebytestr, meta)
+    smeta = pycompat.rapply(pycompat.maybebytestr, meta)
     fm.write('metadata', '{%s}', fm.formatdict(smeta, fmt='%r: %r', sep=', '))
     fm.plain('\n')
 
 def finddate(ui, repo, date):
     """Find the tipmost changeset that matches the given date spec"""
 
     df = dateutil.matchdate(date)
     m = scmutil.matchall(repo)
--- a/mercurial/pycompat.py
+++ b/mercurial/pycompat.py
@@ -42,16 +42,49 @@ else:
     import xmlrpc.client as xmlrpclib
 
     def future_set_exception_info(f, exc_info):
         f.set_exception(exc_info[0])
 
 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
     import io
     import struct
 
     fsencode = os.fsencode
     fsdecode = os.fsdecode
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -107,17 +107,17 @@ def _getrevsource(repo, r):
         if label in extra:
             try:
                 return repo[extra[label]].rev()
             except error.RepoLookupError:
                 pass
     return None
 
 def _sortedb(xs):
-    return sorted(util.rapply(pycompat.maybebytestr, xs))
+    return sorted(pycompat.rapply(pycompat.maybebytestr, xs))
 
 # operator methods
 
 def stringset(repo, subset, x, order):
     if not x:
         raise error.ParseError(_("empty string is not a valid revision"))
     x = scmutil.intrev(scmutil.revsymbol(repo, x))
     if (x in subset
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -860,17 +860,17 @@ def cleanupnodes(repo, replacements, ope
         bmarks = repo._bookmarks
         bmarkchanges = []
         for oldnode, newnode in moves.items():
             oldbmarks = repo.nodebookmarks(oldnode)
             if not oldbmarks:
                 continue
             from . import bookmarks # avoid import cycle
             repo.ui.debug('moving bookmarks %r from %s to %s\n' %
-                          (util.rapply(pycompat.maybebytestr, oldbmarks),
+                          (pycompat.rapply(pycompat.maybebytestr, oldbmarks),
                            hex(oldnode), hex(newnode)))
             # Delete divergent bookmarks being parents of related newnodes
             deleterevs = repo.revs('parents(roots(%ln & (::%n))) - parents(%n)',
                                    allnewnodes, newnode, oldnode)
             deletenodes = _containsnode(repo, deleterevs)
             for name in oldbmarks:
                 bmarkchanges.append((name, newnode))
                 for b in bookmarks.divergent2delete(repo, deletenodes, name):
--- a/mercurial/smartset.py
+++ b/mercurial/smartset.py
@@ -24,17 +24,17 @@ def _formatsetrepr(r):
     bytes     '<branch closed>'
     callable  lambda: '<branch %r>' % sorted(b)
     object    other
     ========  =================================
     """
     if r is None:
         return ''
     elif isinstance(r, tuple):
-        return r[0] % util.rapply(pycompat.maybebytestr, r[1:])
+        return r[0] % pycompat.rapply(pycompat.maybebytestr, r[1:])
     elif isinstance(r, bytes):
         return r
     elif callable(r):
         return r()
     else:
         return pycompat.byterepr(r)
 
 def _typename(o):
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -151,20 +151,20 @@ b"""# example system-wide hg config (see
 # (see 'hg help extensions' for more info)
 #
 # blackbox =
 # churn =
 """,
 }
 
 def _maybestrurl(maybebytes):
-    return util.rapply(pycompat.strurl, maybebytes)
+    return pycompat.rapply(pycompat.strurl, maybebytes)
 
 def _maybebytesurl(maybestr):
-    return util.rapply(pycompat.bytesurl, maybestr)
+    return pycompat.rapply(pycompat.bytesurl, maybestr)
 
 class httppasswordmgrdbproxy(object):
     """Delays loading urllib2 until it's needed."""
     def __init__(self):
         self._mgr = None
 
     def _get_mgr(self):
         if self._mgr is None:
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -126,49 +126,16 @@ try:
     recvfds = osutil.recvfds
 except AttributeError:
     pass
 
 # Python compatibility
 
 _notset = object()
 
-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(pycompat.identity, xs) is xs
-    True
-    """
-    if f is pycompat.identity:
-        # fast path mainly for py2
-        return xs
-    return _rapply(f, xs)
-
 def bitsfrom(container):
     bits = 0
     for bit in container:
         bits |= bit
     return bits
 
 # python 2.6 still have deprecation warning enabled by default. We do not want
 # to display anything to standard user so detect if we are running test and