D7015: py3: finish porting iteritems() to pycompat and remove source transformer

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Mon Oct 7 16:19:00 EDT 2019


indygreg created this revision.
Herald added subscribers: mercurial-devel, mjpieters.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  This commit finishes porting .iteritems() to pycompat.iteritems()
  for the mercurial package.
  
  The translation of .iteritems() to .items() was the last conversion
  performed by the source transformer. With the porting to pycompat
  complete, we no longer have a need for the source transformer. So
  the source transformer has been removed. Good riddance! The code
  base is now compatible with Python 2 and Python 3.
  
  For the record, as the person who introduced the source transformer,
  it brings me joy to delete it. It accomplished its goal to facilitate
  a port to Python 3 without overly burdening people on some painful
  low-level differences between Python 2 and 3. It is unfortunate we
  still have to wallpaper over many differences with the pycompat
  shim. But it is what it is.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D7015

AFFECTED FILES
  mercurial/__init__.py
  mercurial/archival.py
  mercurial/bookmarks.py
  mercurial/branchmap.py
  mercurial/changegroup.py
  mercurial/chgserver.py
  mercurial/cmdutil.py
  mercurial/commands.py
  mercurial/config.py
  mercurial/context.py
  mercurial/copies.py
  mercurial/debugcommands.py
  mercurial/dirstate.py
  mercurial/discovery.py
  mercurial/dispatch.py
  mercurial/exchange.py
  mercurial/exchangev2.py
  mercurial/extensions.py
  mercurial/exthelper.py
  mercurial/filemerge.py
  mercurial/fileset.py
  mercurial/formatter.py
  mercurial/help.py
  mercurial/hgweb/hgweb_mod.py
  mercurial/hgweb/hgwebdir_mod.py
  mercurial/hgweb/request.py
  mercurial/hgweb/webcommands.py
  mercurial/hgweb/webutil.py
  mercurial/hgweb/wsgicgi.py
  mercurial/hook.py
  mercurial/httpconnection.py
  mercurial/keepalive.py
  mercurial/localrepo.py
  mercurial/logcmdutil.py
  mercurial/logexchange.py
  mercurial/lsprof.py
  mercurial/manifest.py
  mercurial/match.py
  mercurial/merge.py
  mercurial/namespaces.py
  mercurial/obsolete.py
  mercurial/obsutil.py
  mercurial/patch.py
  mercurial/phases.py
  mercurial/pure/parsers.py
  mercurial/pycompat.py
  mercurial/revlog.py
  mercurial/revset.py
  mercurial/revsetlang.py
  mercurial/scmutil.py
  mercurial/similar.py
  mercurial/sparse.py
  mercurial/sshpeer.py
  mercurial/statprof.py
  mercurial/store.py
  mercurial/subrepo.py
  mercurial/subrepoutil.py
  mercurial/tags.py
  mercurial/templatefilters.py
  mercurial/templatefuncs.py
  mercurial/templatekw.py
  mercurial/templater.py
  mercurial/templateutil.py
  mercurial/transaction.py
  mercurial/ui.py
  mercurial/url.py
  mercurial/util.py
  mercurial/utils/cborutil.py
  mercurial/utils/procutil.py
  mercurial/verify.py
  mercurial/wireprotoframing.py
  mercurial/wireprotov1peer.py
  mercurial/wireprotov1server.py
  mercurial/wireprotov2server.py

CHANGE DETAILS

diff --git a/mercurial/wireprotov2server.py b/mercurial/wireprotov2server.py
--- a/mercurial/wireprotov2server.py
+++ b/mercurial/wireprotov2server.py
@@ -965,7 +965,7 @@
 
 @wireprotocommand(b'branchmap', permission=b'pull')
 def branchmapv2(repo, proto):
-    yield {encoding.fromlocal(k): v for k, v in repo.branchmap().iteritems()}
+    yield {encoding.fromlocal(k): v for k, v in pycompat.iteritems(repo.branchmap())}
 
 
 @wireprotocommand(b'capabilities', permission=b'pull')
@@ -1061,7 +1061,7 @@
     # If requested, send bookmarks from nodes that didn't have revision
     # data sent so receiver is aware of any bookmark updates.
     if b'bookmarks' in fields:
-        for node, marks in sorted(nodebookmarks.iteritems()):
+        for node, marks in sorted(pycompat.iteritems(nodebookmarks)):
             yield {
                 b'node': node,
                 b'bookmarks': sorted(marks),
@@ -1379,7 +1379,7 @@
     keys = repo.listkeys(encoding.tolocal(namespace))
     keys = {
         encoding.fromlocal(k): encoding.fromlocal(v)
-        for k, v in keys.iteritems()
+        for k, v in pycompat.iteritems(keys)
     }
 
     yield keys
diff --git a/mercurial/wireprotov1server.py b/mercurial/wireprotov1server.py
--- a/mercurial/wireprotov1server.py
+++ b/mercurial/wireprotov1server.py
@@ -243,7 +243,7 @@
 def branchmap(repo, proto):
     branchmap = repo.branchmap()
     heads = []
-    for branch, nodes in branchmap.iteritems():
+    for branch, nodes in pycompat.iteritems(branchmap):
         branchname = urlreq.quote(encoding.fromlocal(branch))
         branchnodes = wireprototypes.encodelist(nodes)
         heads.append(b'%s %s' % (branchname, branchnodes))
@@ -440,7 +440,7 @@
     opts = options(
         b'getbundle', wireprototypes.GETBUNDLE_ARGUMENTS.keys(), others
     )
-    for k, v in opts.iteritems():
+    for k, v in pycompat.iteritems(opts):
         keytype = wireprototypes.GETBUNDLE_ARGUMENTS[k]
         if keytype == b'nodes':
             opts[k] = wireprototypes.decodelist(v)
diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py
--- a/mercurial/wireprotov1peer.py
+++ b/mercurial/wireprotov1peer.py
@@ -95,7 +95,7 @@
 
         args = b','.join(
             b'%s=%s' % (escapearg(k), escapearg(v))
-            for k, v in argsdict.iteritems()
+            for k, v in pycompat.iteritems(argsdict)
         )
         cmds.append(b'%s %s' % (op, args))
 
@@ -448,7 +448,7 @@
         self.requirecap(b'getbundle', _(b'look up remote changes'))
         opts = {}
         bundlecaps = kwargs.get(b'bundlecaps') or set()
-        for key, value in kwargs.iteritems():
+        for key, value in pycompat.iteritems(kwargs):
             if value is None:
                 continue
             keytype = wireprototypes.GETBUNDLE_ARGUMENTS.get(key)
diff --git a/mercurial/wireprotoframing.py b/mercurial/wireprotoframing.py
--- a/mercurial/wireprotoframing.py
+++ b/mercurial/wireprotoframing.py
@@ -123,7 +123,7 @@
 
 def humanflags(mapping, value):
     """Convert a numeric flags value to a human value, using a mapping table."""
-    namemap = {v: k for k, v in mapping.iteritems()}
+    namemap = {v: k for k, v in pycompat.iteritems(mapping)}
     flags = []
     val = 1
     while value >= val:
@@ -160,7 +160,7 @@
     @encoding.strmethod
     def __repr__(self):
         typename = b'<unknown 0x%02x>' % self.typeid
-        for name, value in FRAME_TYPES.iteritems():
+        for name, value in pycompat.iteritems(FRAME_TYPES):
             if value == self.typeid:
                 typename = name
                 break
diff --git a/mercurial/verify.py b/mercurial/verify.py
--- a/mercurial/verify.py
+++ b/mercurial/verify.py
@@ -423,11 +423,11 @@
                 _(b'checking'), unit=_(b'manifests'), total=len(subdirs)
             )
 
-        for subdir, linkrevs in subdirnodes.iteritems():
+        for subdir, linkrevs in pycompat.iteritems(subdirnodes):
             subdirfilenodes = self._verifymanifest(
                 linkrevs, subdir, storefiles, subdirprogress
             )
-            for f, onefilenodes in subdirfilenodes.iteritems():
+            for f, onefilenodes in pycompat.iteritems(subdirfilenodes):
                 filenodes.setdefault(f, {}).update(onefilenodes)
 
         if not dir and subdirnodes:
@@ -608,7 +608,7 @@
 
             # cross-check
             if f in filenodes:
-                fns = [(v, k) for k, v in filenodes[f].iteritems()]
+                fns = [(v, k) for k, v in pycompat.iteritems(filenodes[f])]
                 for lr, node in sorted(fns):
                     self._err(
                         lr,
diff --git a/mercurial/utils/procutil.py b/mercurial/utils/procutil.py
--- a/mercurial/utils/procutil.py
+++ b/mercurial/utils/procutil.py
@@ -247,7 +247,7 @@
 
 def filter(s, cmd):
     b"filter a string through a command that transforms its input to its output"
-    for name, fn in _filtertable.iteritems():
+    for name, fn in pycompat.iteritems(_filtertable):
         if cmd.startswith(name):
             return fn(s, cmd[len(name) :].lstrip())
     return pipefilter(s, cmd)
@@ -369,7 +369,7 @@
 
     env = dict(encoding.environ)
     if environ:
-        env.update((k, py2shell(v)) for k, v in environ.iteritems())
+        env.update((k, py2shell(v)) for k, v in pycompat.iteritems(environ))
     env[b'HG'] = hgexecutable()
     return env
 
diff --git a/mercurial/utils/cborutil.py b/mercurial/utils/cborutil.py
--- a/mercurial/utils/cborutil.py
+++ b/mercurial/utils/cborutil.py
@@ -176,7 +176,7 @@
     yield encodelength(MAJOR_TYPE_MAP, len(d))
 
     for key, value in sorted(
-        d.iteritems(), key=lambda x: _mixedtypesortkey(x[0])
+        pycompat.iteritems(d), key=lambda x: _mixedtypesortkey(x[0])
     ):
         for chunk in streamencode(key):
             yield chunk
diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -1265,7 +1265,7 @@
         # __setitem__() isn't called as of PyPy 5.8.0
         def update(self, src):
             if isinstance(src, dict):
-                src = src.iteritems()
+                src = pycompat.iteritems(src)
             for k, v in src:
                 self[k] = v
 
@@ -3501,7 +3501,7 @@
         self._dirs = {}
         addpath = self.addpath
         if isinstance(map, dict) and skip is not None:
-            for f, s in map.iteritems():
+            for f, s in pycompat.iteritems(map):
                 if s[0] != skip:
                     addpath(f)
         elif skip is not None:
diff --git a/mercurial/url.py b/mercurial/url.py
--- a/mercurial/url.py
+++ b/mercurial/url.py
@@ -232,7 +232,7 @@
         ]
     )
     self.send(b'CONNECT %s HTTP/1.0\r\n' % self.realhostport)
-    for header in proxyheaders.iteritems():
+    for header in pycompat.iteritems(proxyheaders):
         self.send(b'%s: %s\r\n' % header)
     self.send(b'\r\n')
 
diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -2220,7 +2220,7 @@
         # Now process the sub-options. If a sub-option is registered, its
         # attribute will always be present. The value will be None if there
         # was no valid sub-option.
-        for suboption, (attr, func) in _pathsuboptions.iteritems():
+        for suboption, (attr, func) in pycompat.iteritems(_pathsuboptions):
             if suboption not in suboptions:
                 setattr(self, attr, None)
                 continue
@@ -2246,7 +2246,7 @@
         This is intended to be used for presentation purposes.
         """
         d = {}
-        for subopt, (attr, _func) in _pathsuboptions.iteritems():
+        for subopt, (attr, _func) in pycompat.iteritems(_pathsuboptions):
             value = getattr(self, attr)
             if value is not None:
                 d[subopt] = value
diff --git a/mercurial/transaction.py b/mercurial/transaction.py
--- a/mercurial/transaction.py
+++ b/mercurial/transaction.py
@@ -355,7 +355,7 @@
     def _generatefiles(self, suffix=b'', group=gengroupall):
         # write files registered for generation
         any = False
-        for id, entry in sorted(self._filegenerators.iteritems()):
+        for id, entry in sorted(pycompat.iteritems(self._filegenerators)):
             any = True
             order, filenames, genfunc, location = entry
 
diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py
--- a/mercurial/templateutil.py
+++ b/mercurial/templateutil.py
@@ -308,7 +308,7 @@
         if util.safehasattr(self._values, b'get'):
             values = {
                 k: v
-                for k, v in self._values.iteritems()
+                for k, v in pycompat.iteritems(self._values)
                 if select(self._wrapvalue(k, v))
             }
         else:
@@ -341,7 +341,7 @@
         xs = self._values
         if util.safehasattr(xs, b'get'):
             return {
-                k: unwrapvalue(context, mapping, v) for k, v in xs.iteritems()
+                k: unwrapvalue(context, mapping, v) for k, v in pycompat.iteritems(xs)
             }
         return [unwrapvalue(context, mapping, x) for x in xs]
 
@@ -461,7 +461,7 @@
             items.append(
                 {
                     k: unwrapvalue(context, lm, v)
-                    for k, v in nm.iteritems()
+                    for k, v in pycompat.iteritems(nm)
                     if k not in knownres
                 }
             )
@@ -639,7 +639,7 @@
     This exists for backward compatibility with the old-style template. Use
     hybriddict() for new template keywords.
     """
-    c = [{key: k, value: v} for k, v in data.iteritems()]
+    c = [{key: k, value: v} for k, v in pycompat.iteritems(data)]
     f = _showcompatlist(context, mapping, name, c, plural, separator)
     return hybriddict(data, key=key, value=value, fmt=fmt, gen=f)
 
diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -503,7 +503,7 @@
 
     def compiledict(xs):
         return util.sortdict(
-            (k, compileexp(x, context, curmethods)) for k, x in xs.iteritems()
+            (k, compileexp(x, context, curmethods)) for k, x in pycompat.iteritems(xs)
         )
 
     def compilelist(xs):
@@ -680,7 +680,7 @@
         newres = self._resources.availablekeys(newmapping)
         mapping = {
             k: v
-            for k, v in origmapping.iteritems()
+            for k, v in pycompat.iteritems(origmapping)
             if (
                 k in knownres  # not a symbol per self.symbol()
                 or newres.isdisjoint(self._defaultrequires(k))
diff --git a/mercurial/templatekw.py b/mercurial/templatekw.py
--- a/mercurial/templatekw.py
+++ b/mercurial/templatekw.py
@@ -568,7 +568,7 @@
         # 'name' for iterating over namespaces, templatename for local reference
         return lambda v: {b'name': v, ns.templatename: v}
 
-    for k, ns in repo.names.iteritems():
+    for k, ns in pycompat.iteritems(repo.names):
         names = ns.names(repo, ctx.node())
         f = _showcompatlist(context, mapping, b'name', names)
         namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
@@ -630,12 +630,12 @@
     repo = context.resource(mapping, b'repo')
     # see commands.paths() for naming of dictionary keys
     paths = repo.ui.paths
-    urls = util.sortdict((k, p.rawloc) for k, p in sorted(paths.iteritems()))
+    urls = util.sortdict((k, p.rawloc) for k, p in sorted(pycompat.iteritems(paths)))
 
     def makemap(k):
         p = paths[k]
         d = {b'name': k, b'url': p.rawloc}
-        d.update((o, v) for o, v in sorted(p.suboptions.iteritems()))
+        d.update((o, v) for o, v in sorted(pycompat.iteritems(p.suboptions)))
         return d
 
     return _hybrid(None, urls, makemap, lambda k: b'%s=%s' % (k, urls[k]))
@@ -982,7 +982,7 @@
 def loadkeyword(ui, extname, registrarobj):
     """Load template keyword from specified registrarobj
     """
-    for name, func in registrarobj._table.iteritems():
+    for name, func in pycompat.iteritems(registrarobj._table):
         keywords[name] = func
 
 
diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py
--- a/mercurial/templatefuncs.py
+++ b/mercurial/templatefuncs.py
@@ -91,7 +91,7 @@
 
     data.update(
         (k, evalfuncarg(context, mapping, v))
-        for k, v in args[b'kwargs'].iteritems()
+        for k, v in pycompat.iteritems(args[b'kwargs'])
     )
     return templateutil.hybriddict(data)
 
@@ -874,7 +874,7 @@
 def loadfunction(ui, extname, registrarobj):
     """Load template function from specified registrarobj
     """
-    for name, func in registrarobj._table.iteritems():
+    for name, func in pycompat.iteritems(registrarobj._table):
         funcs[name] = func
 
 
diff --git a/mercurial/templatefilters.py b/mercurial/templatefilters.py
--- a/mercurial/templatefilters.py
+++ b/mercurial/templatefilters.py
@@ -341,7 +341,7 @@
         out = [
             b'"%s": %s'
             % (encoding.jsonescape(k, paranoid=paranoid), json(v, paranoid))
-            for k, v in sorted(obj.iteritems())
+            for k, v in sorted(pycompat.iteritems(obj))
         ]
         return b'{' + b', '.join(out) + b'}'
     elif util.safehasattr(obj, b'__iter__'):
@@ -542,7 +542,7 @@
 def loadfilter(ui, extname, registrarobj):
     """Load template filter from specified registrarobj
     """
-    for name, func in registrarobj._table.iteritems():
+    for name, func in pycompat.iteritems(registrarobj._table):
         filters[name] = func
 
 
diff --git a/mercurial/tags.py b/mercurial/tags.py
--- a/mercurial/tags.py
+++ b/mercurial/tags.py
@@ -27,6 +27,7 @@
     encoding,
     error,
     match as matchmod,
+    pycompat,
     scmutil,
     util,
 )
@@ -355,7 +356,7 @@
     if tagtype is None:
         assert tagtypes is None
 
-    for name, nodehist in filetags.iteritems():
+    for name, nodehist in pycompat.iteritems(filetags):
         if name not in alltags:
             alltags[name] = nodehist
             if tagtype is not None:
@@ -536,7 +537,7 @@
     # we keep them in UTF-8 throughout this module.  If we converted
     # them local encoding on input, we would lose info writing them to
     # the cache.
-    for (name, (node, hist)) in sorted(cachetags.iteritems()):
+    for (name, (node, hist)) in sorted(pycompat.iteritems(cachetags)):
         for n in hist:
             cachefile.write(b"%s %s\n" % (hex(n), name))
         cachefile.write(b"%s %s\n" % (hex(node), name))
diff --git a/mercurial/subrepoutil.py b/mercurial/subrepoutil.py
--- a/mercurial/subrepoutil.py
+++ b/mercurial/subrepoutil.py
@@ -20,6 +20,7 @@
     filemerge,
     pathutil,
     phases,
+    pycompat,
     util,
 )
 from .utils import stringutil
@@ -162,7 +163,7 @@
         repo.ui.debug(b"  subrepo %s: %s %s\n" % (s, msg, r))
 
     promptssrc = filemerge.partextras(labels)
-    for s, l in sorted(s1.iteritems()):
+    for s, l in sorted(pycompat.iteritems(s1)):
         a = sa.get(s, nullstate)
         ld = l  # local state with possible dirty flag for compares
         if wctx.sub(s).dirty():
diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py
--- a/mercurial/subrepo.py
+++ b/mercurial/subrepo.py
@@ -1740,7 +1740,7 @@
             for b in rev2branch[self._state[1]]:
                 if b.startswith(b'refs/remotes/origin/'):
                     return True
-        for b, revision in branch2rev.iteritems():
+        for b, revision in pycompat.iteritems(branch2rev):
             if b.startswith(b'refs/remotes/origin/'):
                 if self._gitisancestor(self._state[1], revision):
                     return True
diff --git a/mercurial/store.py b/mercurial/store.py
--- a/mercurial/store.py
+++ b/mercurial/store.py
@@ -144,7 +144,7 @@
         cmap[xchr(x)] = e + xchr(x).lower()
 
     dmap = {}
-    for k, v in cmap.iteritems():
+    for k, v in pycompat.iteritems(cmap):
         dmap[v] = k
 
     def decode(s):
diff --git a/mercurial/statprof.py b/mercurial/statprof.py
--- a/mercurial/statprof.py
+++ b/mercurial/statprof.py
@@ -574,7 +574,7 @@
 
     # compute sums for each function
     functiondata = []
-    for fname, sitestats in grouped.iteritems():
+    for fname, sitestats in pycompat.iteritems(grouped):
         total_cum_sec = 0
         total_self_sec = 0
         total_percent = 0
@@ -653,7 +653,7 @@
                 else:
                     children[site] = 1
 
-    parents = [(parent, count) for parent, count in parents.iteritems()]
+    parents = [(parent, count) for parent, count in pycompat.iteritems(parents)]
     parents.sort(reverse=True, key=lambda x: x[1])
     for parent, count in parents:
         fp.write(
@@ -697,7 +697,7 @@
         )
     )
 
-    children = [(child, count) for child, count in children.iteritems()]
+    children = [(child, count) for child, count in pycompat.iteritems(children)]
     children.sort(reverse=True, key=lambda x: x[1])
     for child, count in children:
         fp.write(
@@ -819,7 +819,7 @@
     fd, path = pycompat.mkstemp()
 
     with open(path, b"w+") as file:
-        for line, count in lines.iteritems():
+        for line, count in pycompat.iteritems(lines):
             file.write(b"%s %d\n" % (line, count))
 
     if outputfile is None:
diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -479,10 +479,10 @@
             else:
                 wireargs[k] = args[k]
                 del args[k]
-        for k, v in sorted(wireargs.iteritems()):
+        for k, v in sorted(pycompat.iteritems(wireargs)):
             self._pipeo.write(b"%s %d\n" % (k, len(v)))
             if isinstance(v, dict):
-                for dk, dv in v.iteritems():
+                for dk, dv in pycompat.iteritems(v):
                     self._pipeo.write(b"%s %d\n" % (dk, len(dv)))
                     self._pipeo.write(dv)
             else:
diff --git a/mercurial/sparse.py b/mercurial/sparse.py
--- a/mercurial/sparse.py
+++ b/mercurial/sparse.py
@@ -389,7 +389,7 @@
         sparsematch = matcher(repo, [mctx.rev()])
 
     temporaryfiles = []
-    for file, action in actions.iteritems():
+    for file, action in pycompat.iteritems(actions):
         type, args, msg = action
         files.add(file)
         if sparsematch(file):
@@ -532,7 +532,7 @@
         )
 
     # Check for files that were only in the dirstate.
-    for file, state in dirstate.iteritems():
+    for file, state in pycompat.iteritems(dirstate):
         if not file in files:
             old = origsparsematch(file)
             new = sparsematch(file)
@@ -541,7 +541,7 @@
 
     # Apply changes to disk
     typeactions = mergemod.emptyactions()
-    for f, (m, args, msg) in actions.iteritems():
+    for f, (m, args, msg) in pycompat.iteritems(actions):
         typeactions[m].append((f, args, msg))
 
     mergemod.applyupdates(
diff --git a/mercurial/similar.py b/mercurial/similar.py
--- a/mercurial/similar.py
+++ b/mercurial/similar.py
@@ -8,7 +8,10 @@
 from __future__ import absolute_import
 
 from .i18n import _
-from . import mdiff
+from . import (
+    mdiff,
+    pycompat,
+)
 
 
 def _findexactmatches(repo, added, removed):
@@ -95,7 +98,7 @@
                 copies[a] = (r, myscore)
     progress.complete()
 
-    for dest, v in copies.iteritems():
+    for dest, v in pycompat.iteritems(copies):
         source, bscore = v
         yield source, dest, bscore
 
diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -135,7 +135,7 @@
             del subpaths[subpath]
             missing.add(subpath)
 
-    for subpath, ctx in sorted(subpaths.iteritems()):
+    for subpath, ctx in sorted(pycompat.iteritems(subpaths)):
         yield subpath, ctx.sub(subpath)
 
     # Yield an empty subrepo based on ctx1 for anything only in ctx2.  That way,
@@ -1298,7 +1298,7 @@
         ignored=False,
         full=False,
     )
-    for abs, st in walkresults.iteritems():
+    for abs, st in pycompat.iteritems(walkresults):
         dstate = dirstate[abs]
         if dstate == b'?' and audit_path.check(abs):
             unknown.append(abs)
@@ -1345,7 +1345,7 @@
     with repo.wlock():
         wctx.forget(deleted)
         wctx.add(unknown)
-        for new, old in renames.iteritems():
+        for new, old in pycompat.iteritems(renames):
             wctx.copy(old, new)
 
 
@@ -1481,10 +1481,10 @@
     oldcopies = copiesmod.pathcopies(newctx, oldctx, match)
     oldcopies.update(copies)
     copies = dict(
-        (dst, oldcopies.get(src, src)) for dst, src in oldcopies.iteritems()
+        (dst, oldcopies.get(src, src)) for dst, src in pycompat.iteritems(oldcopies)
     )
     # Adjust the dirstate copies
-    for dst, src in copies.iteritems():
+    for dst, src in pycompat.iteritems(copies):
         if src not in newctx or dst in newctx or ds[dst] != b'a':
             src = None
         ds.copy(src, dst)
@@ -2070,7 +2070,7 @@
                 return
             published = [
                 rev
-                for rev, (old, new) in phasetracking.iteritems()
+                for rev, (old, new) in pycompat.iteritems(phasetracking)
                 if new == phases.public and rev < origrepolen
             ]
             if not published:
diff --git a/mercurial/revsetlang.py b/mercurial/revsetlang.py
--- a/mercurial/revsetlang.py
+++ b/mercurial/revsetlang.py
@@ -605,7 +605,7 @@
     tree = _aliasrules.expand(aliases, tree)
     # warn about problematic (but not referred) aliases
     if warn is not None:
-        for name, alias in sorted(aliases.iteritems()):
+        for name, alias in sorted(pycompat.iteritems(aliases)):
             if alias.error and not alias.warned:
                 warn(_(b'warning: %s\n') % (alias.error))
                 alias.warned = True
diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -577,7 +577,7 @@
             bms.add(repo[bmrev].rev())
         else:
             matchrevs = set()
-            for name, bmrev in repo._bookmarks.iteritems():
+            for name, bmrev in pycompat.iteritems(repo._bookmarks):
                 if matcher(name):
                     matchrevs.add(bmrev)
             for bmrev in matchrevs:
@@ -1612,7 +1612,7 @@
             )
         namespaces.add(repo.names[pattern])
     else:
-        for name, ns in repo.names.iteritems():
+        for name, ns in pycompat.iteritems(repo.names):
             if matcher(name):
                 namespaces.add(ns)
 
@@ -2681,7 +2681,7 @@
 def loadpredicate(ui, extname, registrarobj):
     """Load revset predicates from specified registrarobj
     """
-    for name, func in registrarobj._table.iteritems():
+    for name, func in pycompat.iteritems(registrarobj._table):
         symbols[name] = func
         if func._safe:
             safesymbols.add(name)
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -444,7 +444,7 @@
             self._flagprocessors[REVIDX_ELLIPSIS] = ellipsisprocessor
 
         # revlog v0 doesn't have flag processors
-        for flag, processor in opts.get(b'flagprocessors', {}).iteritems():
+        for flag, processor in pycompat.iteritems(opts.get(b'flagprocessors', {})):
             flagutil.insertflagprocessor(flag, processor, self._flagprocessors)
 
         if self._chunkcachesize <= 0:
@@ -1141,7 +1141,7 @@
                     # But, obviously its parents aren't.
                     for p in self.parents(n):
                         heads.pop(p, None)
-        heads = [head for head, flag in heads.iteritems() if flag]
+        heads = [head for head, flag in pycompat.iteritems(heads) if flag]
         roots = list(roots)
         assert orderedout
         assert roots
diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py
--- a/mercurial/pycompat.py
+++ b/mercurial/pycompat.py
@@ -316,7 +316,7 @@
         they can be passed as keyword arguments as dictonaries with bytes keys
         can't be passed as keyword arguments to functions on Python 3.
         """
-        dic = dict((k.decode('latin-1'), v) for k, v in dic.iteritems())
+        dic = dict((k.decode('latin-1'), v) for k, v in dic.items())
         return dic
 
     def byteskwargs(dic):
@@ -324,7 +324,7 @@
         Converts keys of python dictonaries to bytes as they were converted to
         str to pass that dictonary as a keyword argument on Python 3.
         """
-        dic = dict((k.encode('latin-1'), v) for k, v in dic.iteritems())
+        dic = dict((k.encode('latin-1'), v) for k, v in dic.items())
         return dic
 
     # TODO: handle shlex.shlex().
diff --git a/mercurial/pure/parsers.py b/mercurial/pure/parsers.py
--- a/mercurial/pure/parsers.py
+++ b/mercurial/pure/parsers.py
@@ -166,7 +166,7 @@
     cs = stringio()
     write = cs.write
     write(b"".join(pl))
-    for f, e in dmap.iteritems():
+    for f, e in pycompat.iteritems(dmap):
         if e[0] == b'n' and e[3] == now:
             # The file was last modified "simultaneously" with the current
             # write to dirstate (i.e. within the same second for file-
diff --git a/mercurial/phases.py b/mercurial/phases.py
--- a/mercurial/phases.py
+++ b/mercurial/phases.py
@@ -673,7 +673,7 @@
     # build list from dictionary
     draftroots = []
     nodemap = repo.changelog.nodemap  # to filter unknown nodes
-    for nhex, phase in roots.iteritems():
+    for nhex, phase in pycompat.iteritems(roots):
         if nhex == b'publishing':  # ignore data related to publish option
             continue
         node = bin(nhex)
diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -2617,7 +2617,7 @@
         # filter out copies where source side isn't inside the matcher
         # (copies.pathcopies() already filtered out the destination)
         copy = {
-            dst: src for dst, src in copy.iteritems() if copysourcematch(src)
+            dst: src for dst, src in pycompat.iteritems(copy) if copysourcematch(src)
         }
 
     modifiedset = set(modified)
diff --git a/mercurial/obsutil.py b/mercurial/obsutil.py
--- a/mercurial/obsutil.py
+++ b/mercurial/obsutil.py
@@ -15,6 +15,7 @@
     encoding,
     node as nodemod,
     phases,
+    pycompat,
     util,
 )
 from .utils import dateutil
@@ -983,7 +984,7 @@
             base[tuple(nsuccset)] = n
     return [
         {b'divergentnodes': divset, b'commonpredecessor': b}
-        for divset, b in base.iteritems()
+        for divset, b in pycompat.iteritems(base)
     ]
 
 
diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
--- a/mercurial/obsolete.py
+++ b/mercurial/obsolete.py
@@ -243,7 +243,7 @@
                 # if content cannot be translated to nodeid drop the data.
                 parents = None
 
-        metadata = tuple(sorted(metadata.iteritems()))
+        metadata = tuple(sorted(pycompat.iteritems(metadata)))
 
         yield (pre, sucs, flags, metadata, date, parents)
 
@@ -273,7 +273,7 @@
     """Return encoded metadata string to string mapping.
 
     Assume no ':' in key and no '\0' in both key and value."""
-    for key, value in meta.iteritems():
+    for key, value in pycompat.iteritems(meta):
         if b':' in key or b'\0' in key:
             raise ValueError(b"':' and '\0' are forbidden in metadata key'")
         if b'\0' in value:
@@ -644,7 +644,7 @@
                 r'in-marker cycle with %s' % pycompat.sysstr(node.hex(prec))
             )
 
-        metadata = tuple(sorted(metadata.iteritems()))
+        metadata = tuple(sorted(pycompat.iteritems(metadata)))
         for k, v in metadata:
             try:
                 # might be better to reject non-ASCII keys
diff --git a/mercurial/namespaces.py b/mercurial/namespaces.py
--- a/mercurial/namespaces.py
+++ b/mercurial/namespaces.py
@@ -2,6 +2,7 @@
 
 from .i18n import _
 from . import (
+    pycompat,
     registrar,
     templatekw,
     util,
@@ -83,7 +84,7 @@
         return self._names.__iter__()
 
     def items(self):
-        return self._names.iteritems()
+        return pycompat.iteritems(self._names)
 
     iteritems = items
 
@@ -116,7 +117,7 @@
 
         Raises a KeyError if there is no such node.
         """
-        for ns, v in self._names.iteritems():
+        for ns, v in pycompat.iteritems(self._names):
             n = v.singlenode(repo, name)
             if n:
                 return n
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -436,7 +436,7 @@
         # the type of state that is stored, and capital-letter records are used
         # to prevent older versions of Mercurial that do not support the feature
         # from loading them.
-        for filename, v in self._state.iteritems():
+        for filename, v in pycompat.iteritems(self._state):
             if v[0] == MERGE_RECORD_DRIVER_RESOLVED:
                 # Driver-resolved merge. These are stored in 'D' records.
                 records.append(
@@ -462,9 +462,9 @@
             else:
                 # Normal files.  These are stored in 'F' records.
                 records.append((RECORD_MERGED, b'\0'.join([filename] + v)))
-        for filename, extras in sorted(self._stateextras.iteritems()):
+        for filename, extras in sorted(pycompat.iteritems(self._stateextras)):
             rawextras = b'\0'.join(
-                b'%s\0%s' % (k, v) for k, v in extras.iteritems()
+                b'%s\0%s' % (k, v) for k, v in pycompat.iteritems(extras)
             )
             records.append(
                 (RECORD_FILE_VALUES, b'%s\0%s' % (filename, rawextras))
@@ -571,7 +571,7 @@
     def unresolved(self):
         """Obtain the paths of unresolved files."""
 
-        for f, entry in self._state.iteritems():
+        for f, entry in pycompat.iteritems(self._state):
             if entry[0] in (
                 MERGE_RECORD_UNRESOLVED,
                 MERGE_RECORD_UNRESOLVED_PATH,
@@ -725,7 +725,7 @@
             ACTION_ADD_MODIFIED: [],
             ACTION_GET: [],
         }
-        for f, (r, action) in self._results.iteritems():
+        for f, (r, action) in pycompat.iteritems(self._results):
             if action is not None:
                 actions[action].append((f, None, b"merge result"))
         return actions
@@ -865,7 +865,7 @@
                 warnconflicts.update(conflicts)
 
         checkunknowndirs = _unknowndirschecker()
-        for f, (m, args, msg) in actions.iteritems():
+        for f, (m, args, msg) in pycompat.iteritems(actions):
             if m in (ACTION_CREATED, ACTION_DELETED_CHANGED):
                 if _checkunknownfile(repo, wctx, mctx, f):
                     fileconflicts.add(f)
@@ -883,7 +883,7 @@
         collectconflicts(ignoredconflicts, ignoredconfig)
         collectconflicts(unknownconflicts, unknownconfig)
     else:
-        for f, (m, args, msg) in actions.iteritems():
+        for f, (m, args, msg) in pycompat.iteritems(actions):
             if m == ACTION_CREATED_MERGE:
                 fl2, anc = args
                 different = _checkunknownfile(repo, wctx, mctx, f)
@@ -942,7 +942,7 @@
         else:
             repo.ui.warn(_(b"%s: replacing untracked files in directory\n") % f)
 
-    for f, (m, args, msg) in actions.iteritems():
+    for f, (m, args, msg) in pycompat.iteritems(actions):
         if m == ACTION_CREATED:
             backup = (
                 f in fileconflicts
@@ -995,7 +995,7 @@
         wmf = wmf.matches(narrowmatch)
         if actions:
             narrowactions = {}
-            for m, actionsfortype in actions.iteritems():
+            for m, actionsfortype in pycompat.iteritems(actions):
                 narrowactions[m] = []
                 for (f, args, msg) in actionsfortype:
                     if narrowmatch(f):
@@ -1298,7 +1298,7 @@
         relevantfiles = set(ma.diff(m2).keys())
 
         # For copied and moved files, we need to add the source file too.
-        for copykey, copyvalue in copy.iteritems():
+        for copykey, copyvalue in pycompat.iteritems(copy):
             if copyvalue in relevantfiles:
                 relevantfiles.add(copykey)
         for movedirkey in movewithdir:
@@ -1309,7 +1309,7 @@
     diff = m1.diff(m2, match=matcher)
 
     actions = {}
-    for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
+    for f, ((n1, fl1), (n2, fl2)) in pycompat.iteritems(diff):
         if n1 and n2:  # file exists on both local and remote side
             if f not in ma:
                 fa = copy.get(f, None)
@@ -1573,7 +1573,7 @@
             if renamedelete is None or len(renamedelete) < len(renamedelete1):
                 renamedelete = renamedelete1
 
-            for f, a in sorted(actions.iteritems()):
+            for f, a in sorted(pycompat.iteritems(actions)):
                 m, args, msg = a
                 repo.ui.debug(b' %s: %s -> %s\n' % (f, msg, m))
                 if f in fbids:
@@ -2058,7 +2058,7 @@
     extraactions = ms.actions()
     if extraactions:
         mfiles = set(a[0] for a in actions[ACTION_MERGE])
-        for k, acts in extraactions.iteritems():
+        for k, acts in pycompat.iteritems(extraactions):
             actions[k].extend(acts)
             if k == ACTION_GET and wantfiledata:
                 # no filedata until mergestate is updated to provide it
@@ -2401,7 +2401,7 @@
         )
 
         if updatecheck == UPDATECHECK_NO_CONFLICT:
-            for f, (m, args, msg) in actionbyfile.iteritems():
+            for f, (m, args, msg) in pycompat.iteritems(actionbyfile):
                 if m not in (
                     ACTION_GET,
                     ACTION_KEEP,
@@ -2465,7 +2465,7 @@
 
         # Convert to dictionary-of-lists format
         actions = emptyactions()
-        for f, (m, args, msg) in actionbyfile.iteritems():
+        for f, (m, args, msg) in pycompat.iteritems(actionbyfile):
             if m not in actions:
                 actions[m] = []
             actions[m].append((f, args, msg))
@@ -2480,7 +2480,7 @@
                 _checkcollision(repo, wc.manifest(), actions)
 
         # divergent renames
-        for f, fl in sorted(diverge.iteritems()):
+        for f, fl in sorted(pycompat.iteritems(diverge)):
             repo.ui.warn(
                 _(
                     b"note: possible conflict - %s was renamed "
@@ -2492,7 +2492,7 @@
                 repo.ui.warn(b" %s\n" % nf)
 
         # rename and delete
-        for f, fl in sorted(renamedelete.iteritems()):
+        for f, fl in sorted(pycompat.iteritems(renamedelete)):
             repo.ui.warn(
                 _(
                     b"note: possible conflict - %s was deleted "
diff --git a/mercurial/match.py b/mercurial/match.py
--- a/mercurial/match.py
+++ b/mercurial/match.py
@@ -1617,7 +1617,7 @@
             continue
 
         linesyntax = syntax
-        for s, rels in syntaxes.iteritems():
+        for s, rels in pycompat.iteritems(syntaxes):
             if line.startswith(rels):
                 linesyntax = rels
                 line = line[len(rels) :]
diff --git a/mercurial/manifest.py b/mercurial/manifest.py
--- a/mercurial/manifest.py
+++ b/mercurial/manifest.py
@@ -487,7 +487,7 @@
         diff = self.diff(m2)
         files = set(
             filepath
-            for filepath, hashflags in diff.iteritems()
+            for filepath, hashflags in pycompat.iteritems(diff)
             if hashflags[1][0] is None
         )
         return files
@@ -789,7 +789,7 @@
 
     def _loadalllazy(self):
         selfdirs = self._dirs
-        for d, (path, node, readsubtree, docopy) in self._lazydirs.iteritems():
+        for d, (path, node, readsubtree, docopy) in pycompat.iteritems(self._lazydirs):
             if docopy:
                 selfdirs[d] = readsubtree(path, node).copy()
             else:
@@ -828,11 +828,11 @@
           differs, load it in both
         """
         toloadlazy = []
-        for d, v1 in t1._lazydirs.iteritems():
+        for d, v1 in pycompat.iteritems(t1._lazydirs):
             v2 = t2._lazydirs.get(d)
             if not v2 or v2[1] != v1[1]:
                 toloadlazy.append(d)
-        for d, v1 in t2._lazydirs.iteritems():
+        for d, v1 in pycompat.iteritems(t2._lazydirs):
             if d not in t1._lazydirs:
                 toloadlazy.append(d)
 
@@ -910,7 +910,7 @@
             if p in self._files:
                 yield self._subpath(p), n
             else:
-                for f, sn in n.iteritems():
+                for f, sn in pycompat.iteritems(n):
                     yield f, sn
 
     iteritems = items
@@ -1052,10 +1052,10 @@
                 self._load()
                 s._lazydirs = {
                     d: (p, n, r, True)
-                    for d, (p, n, r, c) in self._lazydirs.iteritems()
+                    for d, (p, n, r, c) in pycompat.iteritems(self._lazydirs)
                 }
                 sdirs = s._dirs
-                for d, v in self._dirs.iteritems():
+                for d, v in pycompat.iteritems(self._dirs):
                     sdirs[d] = v.copy()
                 s._files = dict.copy(self._files)
                 s._flags = dict.copy(self._flags)
@@ -1083,7 +1083,7 @@
             t1._load()
             t2._load()
             self._loaddifflazy(t1, t2)
-            for d, m1 in t1._dirs.iteritems():
+            for d, m1 in pycompat.iteritems(t1._dirs):
                 if d in t2._dirs:
                     m2 = t2._dirs[d]
                     _filesnotin(m1, m2)
@@ -1200,7 +1200,7 @@
                 ret._flags[fn] = self._flags[fn]
 
         visit = self._loadchildrensetlazy(visit)
-        for dir, subm in self._dirs.iteritems():
+        for dir, subm in pycompat.iteritems(self._dirs):
             if visit and dir[:-1] not in visit:
                 continue
             m = subm._matches(match)
@@ -1242,15 +1242,15 @@
             t2._load()
             self._loaddifflazy(t1, t2)
 
-            for d, m1 in t1._dirs.iteritems():
+            for d, m1 in pycompat.iteritems(t1._dirs):
                 m2 = t2._dirs.get(d, emptytree)
                 stack.append((m1, m2))
 
-            for d, m2 in t2._dirs.iteritems():
+            for d, m2 in pycompat.iteritems(t2._dirs):
                 if d not in t1._dirs:
                     stack.append((emptytree, m2))
 
-            for fn, n1 in t1._files.iteritems():
+            for fn, n1 in pycompat.iteritems(t1._files):
                 fl1 = t1._flags.get(fn, b'')
                 n2 = t2._files.get(fn, None)
                 fl2 = t2._flags.get(fn, b'')
@@ -1259,7 +1259,7 @@
                 elif clean:
                     result[t1._subpath(fn)] = None
 
-            for fn, n2 in t2._files.iteritems():
+            for fn, n2 in pycompat.iteritems(t2._files):
                 if fn not in t1._files:
                     fl2 = t2._flags.get(fn, b'')
                     result[t2._subpath(fn)] = ((None, b''), (n2, fl2))
@@ -1310,7 +1310,7 @@
         """
         self._load()
         flags = self.flags
-        lazydirs = [(d[:-1], v[1], b't') for d, v in self._lazydirs.iteritems()]
+        lazydirs = [(d[:-1], v[1], b't') for d, v in pycompat.iteritems(self._lazydirs)]
         dirs = [(d[:-1], self._dirs[d]._node, b't') for d in self._dirs]
         files = [(f, self._files[f], flags(f)) for f in self._files]
         return _text(sorted(dirs + files + lazydirs))
@@ -1339,7 +1339,7 @@
         visit = self._loadchildrensetlazy(visit)
         if visit == b'this' or visit == b'all':
             visit = None
-        for d, subm in self._dirs.iteritems():
+        for d, subm in pycompat.iteritems(self._dirs):
             if visit and d[:-1] not in visit:
                 continue
             subp1 = getnode(m1, d)
@@ -1362,7 +1362,7 @@
         self._load()
         # OPT: use visitchildrenset to avoid loading everything.
         self._loadalllazy()
-        for d, subm in self._dirs.iteritems():
+        for d, subm in pycompat.iteritems(self._dirs):
             for subtree in subm.walksubtrees(matcher=matcher):
                 yield subtree
 
@@ -2144,7 +2144,7 @@
             m0 = self._manifestlog.get(self._dir, store.node(r0)).read()
             m1 = self.read()
             md = treemanifest(dir=self._dir)
-            for f, ((n0, fl0), (n1, fl1)) in m0.diff(m1).iteritems():
+            for f, ((n0, fl0), (n1, fl1)) in pycompat.iteritems(m0.diff(m1)):
                 if n1:
                     md[f] = n1
                     if fl1:
diff --git a/mercurial/lsprof.py b/mercurial/lsprof.py
--- a/mercurial/lsprof.py
+++ b/mercurial/lsprof.py
@@ -4,6 +4,7 @@
 import sys
 
 from .pycompat import getattr
+from . import pycompat
 
 Profiler = _lsprof.Profiler
 
@@ -125,7 +126,7 @@
     try:
         mname = _fn2mod[code.co_filename]
     except KeyError:
-        for k, v in list(sys.modules.iteritems()):
+        for k, v in list(pycompat.iteritems(sys.modules)):
             if v is None:
                 continue
             if not isinstance(getattr(v, '__file__', None), str):
diff --git a/mercurial/logexchange.py b/mercurial/logexchange.py
--- a/mercurial/logexchange.py
+++ b/mercurial/logexchange.py
@@ -11,6 +11,7 @@
 from .node import hex
 
 from . import (
+    pycompat,
     util,
     vfs as vfsmod,
 )
@@ -74,7 +75,7 @@
         if oldpath != remotepath:
             f.write(b'%s\0%s\0%s\n' % (node, oldpath, rname))
 
-    for name, node in sorted(names.iteritems()):
+    for name, node in sorted(pycompat.iteritems(names)):
         if nametype == b"branches":
             for n in node:
                 f.write(b'%s\0%s\0%s\n' % (n, remotepath, name))
@@ -153,7 +154,7 @@
     with remoterepo.commandexecutor() as e:
         branchmap = e.callcommand(b'branchmap', {}).result()
 
-    for branch, nodes in branchmap.iteritems():
+    for branch, nodes in pycompat.iteritems(branchmap):
         bmap[branch] = []
         for node in nodes:
             if node in repo and not repo[node].obsolete():
diff --git a/mercurial/logcmdutil.py b/mercurial/logcmdutil.py
--- a/mercurial/logcmdutil.py
+++ b/mercurial/logcmdutil.py
@@ -290,7 +290,7 @@
         if branch != b'default':
             self.ui.write(columns[b'branch'] % branch, label=b'log.branch')
 
-        for nsname, ns in self.repo.names.iteritems():
+        for nsname, ns in pycompat.iteritems(self.repo.names):
             # branches has special logic already handled above, so here we just
             # skip it
             if nsname == b'branches':
@@ -795,7 +795,7 @@
         opts[b'_patslog'] = list(pats)
 
     expr = []
-    for op, val in sorted(opts.iteritems()):
+    for op, val in sorted(pycompat.iteritems(opts)):
         if not val:
             continue
         if op not in _opt2logrevset:
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1689,7 +1689,7 @@
         else:
             tags = self._tagscache.tags
         rev = self.changelog.rev
-        for k, v in tags.iteritems():
+        for k, v in pycompat.iteritems(tags):
             try:
                 # ignore tags to unknown nodes
                 rev(v)
@@ -1724,14 +1724,14 @@
         # writing to the cache), but the rest of Mercurial wants them in
         # local encoding.
         tags = {}
-        for (name, (node, hist)) in alltags.iteritems():
+        for (name, (node, hist)) in pycompat.iteritems(alltags):
             if node != nullid:
                 tags[encoding.tolocal(name)] = node
         tags[b'tip'] = self.changelog.tip()
         tagtypes = dict(
             [
                 (encoding.tolocal(name), value)
-                for (name, value) in tagtypes.iteritems()
+                for (name, value) in pycompat.iteritems(tagtypes)
             ]
         )
         return (tags, tagtypes)
@@ -1751,7 +1751,7 @@
         '''return a list of tags ordered by revision'''
         if not self._tagscache.tagslist:
             l = []
-            for t, n in self.tags().iteritems():
+            for t, n in pycompat.iteritems(self.tags()):
                 l.append((self.changelog.rev(n), t, n))
             self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
 
@@ -1761,7 +1761,7 @@
         '''return the tags associated with a node'''
         if not self._tagscache.nodetagscache:
             nodetagscache = {}
-            for t, n in self._tagscache.tags.iteritems():
+            for t, n in pycompat.iteritems(self._tagscache.tags):
                 nodetagscache.setdefault(n, []).append(t)
             for tags in pycompat.itervalues(nodetagscache):
                 tags.sort()
@@ -1886,7 +1886,7 @@
                 mf = matchmod.match(self.root, b'', [pat])
                 fn = None
                 params = cmd
-                for name, filterfn in self._datafilters.iteritems():
+                for name, filterfn in pycompat.iteritems(self._datafilters):
                     if cmd.startswith(name):
                         fn = filterfn
                         params = cmd[len(name) :].lstrip()
diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py
--- a/mercurial/keepalive.py
+++ b/mercurial/keepalive.py
@@ -194,7 +194,7 @@
 
     def close_all(self):
         """close all open connections"""
-        for host, conns in self._cm.get_all().iteritems():
+        for host, conns in pycompat.iteritems(self._cm.get_all()):
             for h in conns:
                 self._cm.remove(h)
                 h.close()
diff --git a/mercurial/httpconnection.py b/mercurial/httpconnection.py
--- a/mercurial/httpconnection.py
+++ b/mercurial/httpconnection.py
@@ -87,7 +87,7 @@
     bestuser = None
     bestlen = 0
     bestauth = None
-    for group, auth in groups.iteritems():
+    for group, auth in pycompat.iteritems(groups):
         if user and user != auth.get(b'username', user):
             # If a username was set in the URI, the entry username
             # must either match it or be unset
diff --git a/mercurial/hook.py b/mercurial/hook.py
--- a/mercurial/hook.py
+++ b/mercurial/hook.py
@@ -155,7 +155,7 @@
     env[b'HG_HOOKTYPE'] = htype
     env[b'HG_HOOKNAME'] = name
 
-    for k, v in args.iteritems():
+    for k, v in pycompat.iteritems(args):
         if callable(v):
             v = v()
         if isinstance(v, (dict, list)):
diff --git a/mercurial/hgweb/wsgicgi.py b/mercurial/hgweb/wsgicgi.py
--- a/mercurial/hgweb/wsgicgi.py
+++ b/mercurial/hgweb/wsgicgi.py
@@ -24,7 +24,7 @@
     procutil.setbinary(procutil.stdin)
     procutil.setbinary(procutil.stdout)
 
-    environ = dict(os.environ.iteritems())  # re-exports
+    environ = dict(pycompat.iteritems(os.environ))  # re-exports
     environ.setdefault(r'PATH_INFO', b'')
     if environ.get(r'SERVER_SOFTWARE', r'').startswith(r'Microsoft-IIS'):
         # IIS includes script_name in PATH_INFO
diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py
--- a/mercurial/hgweb/webutil.py
+++ b/mercurial/hgweb/webutil.py
@@ -57,7 +57,7 @@
     allowed = ui.configlist(b'web', b'allow-archive', untrusted=True)
     archives = []
 
-    for typ, spec in archivespecs.iteritems():
+    for typ, spec in pycompat.iteritems(archivespecs):
         if typ in allowed or ui.configbool(
             b'web', b'allow' + typ, untrusted=True
         ):
@@ -852,7 +852,7 @@
 
     def itermaps(self, context):
         separator = self._start
-        for key, value in sorted(self._vars.iteritems()):
+        for key, value in sorted(pycompat.iteritems(self._vars)):
             yield {
                 b'name': key,
                 b'value': pycompat.bytestr(value),
diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -564,7 +564,7 @@
     l = len(path)
     abspath = b"/" + path
 
-    for full, n in mf.iteritems():
+    for full, n in pycompat.iteritems(mf):
         # the virtual path (working copy path) used for the full
         # (repository) path
         f = decodepath(full)
@@ -1525,7 +1525,7 @@
 
         early, other = [], []
         primary = lambda s: s.partition(b'|')[0]
-        for c, e in commands.table.iteritems():
+        for c, e in pycompat.iteritems(commands.table):
             doc = _getdoc(e)
             if b'DEPRECATED' in doc or c.startswith(b'debug'):
                 continue
diff --git a/mercurial/hgweb/request.py b/mercurial/hgweb/request.py
--- a/mercurial/hgweb/request.py
+++ b/mercurial/hgweb/request.py
@@ -74,7 +74,7 @@
         return vals[0]
 
     def asdictoflists(self):
-        return {k: list(v) for k, v in self._items.iteritems()}
+        return {k: list(v) for k, v in pycompat.iteritems(self._items)}
 
 
 @attr.s(frozen=True)
@@ -162,10 +162,10 @@
     # strings on Python 3 must be between \00000-\000FF. We deal with bytes
     # in Mercurial, so mass convert string keys and values to bytes.
     if pycompat.ispy3:
-        env = {k.encode('latin-1'): v for k, v in env.iteritems()}
+        env = {k.encode('latin-1'): v for k, v in pycompat.iteritems(env)}
         env = {
             k: v.encode('latin-1') if isinstance(v, str) else v
-            for k, v in env.iteritems()
+            for k, v in pycompat.iteritems(env)
         }
 
     # Some hosting solutions are emulating hgwebdir, and dispatching directly
@@ -300,7 +300,7 @@
     # perform case normalization for us. We just rewrite underscore to dash
     # so keys match what likely went over the wire.
     headers = []
-    for k, v in env.iteritems():
+    for k, v in pycompat.iteritems(env):
         if k.startswith(b'HTTP_'):
             headers.append((k[len(b'HTTP_') :].replace(b'_', b'-'), v))
 
diff --git a/mercurial/hgweb/hgwebdir_mod.py b/mercurial/hgweb/hgwebdir_mod.py
--- a/mercurial/hgweb/hgwebdir_mod.py
+++ b/mercurial/hgweb/hgwebdir_mod.py
@@ -447,7 +447,7 @@
                     uenv = req.rawenv
                     if pycompat.ispy3:
                         uenv = {
-                            k.decode('latin1'): v for k, v in uenv.iteritems()
+                            k.decode('latin1'): v for k, v in pycompat.iteritems(uenv)
                         }
                     req = requestmod.parserequestfromenv(
                         uenv,
diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -396,7 +396,7 @@
 
             if cmd == b'archive':
                 fn = req.qsparams[b'node']
-                for type_, spec in webutil.archivespecs.iteritems():
+                for type_, spec in pycompat.iteritems(webutil.archivespecs):
                     ext = spec[2]
                     if fn.endswith(ext):
                         req.qsparams[b'node'] = fn[: -len(ext)]
diff --git a/mercurial/help.py b/mercurial/help.py
--- a/mercurial/help.py
+++ b/mercurial/help.py
@@ -124,7 +124,7 @@
     '''return a text listing of the given extensions'''
     rst = []
     if exts:
-        for name, desc in sorted(exts.iteritems()):
+        for name, desc in sorted(pycompat.iteritems(exts)):
             if not showdeprecated and any(w in desc for w in _exclkeywords):
                 continue
             rst.append(b'%s:%s: %s\n' % (b' ' * indent, name, desc))
@@ -261,7 +261,7 @@
             name = names[0]
             if not filtertopic(ui, name):
                 results[b'topics'].append((names[0], header))
-    for cmd, entry in commands.table.iteritems():
+    for cmd, entry in pycompat.iteritems(commands.table):
         if len(entry) == 3:
             summary = entry[2]
         else:
@@ -278,7 +278,8 @@
                 continue
             results[b'commands'].append((cmdname, summary))
     for name, docs in itertools.chain(
-        extensions.enabled(False).iteritems(), extensions.disabled().iteritems()
+        pycompat.iteritems(extensions.enabled(False)),
+        pycompat.iteritems(extensions.disabled())
     ):
         if not docs:
             continue
@@ -291,7 +292,7 @@
         except ImportError:
             # debug message would be printed in extensions.load()
             continue
-        for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
+        for cmd, entry in pycompat.iteritems(getattr(mod, 'cmdtable', {})):
             if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
                 cmdname = cmdutil.parsealiases(cmd)[0]
                 func = entry[0]
@@ -738,7 +739,7 @@
         h = {}
         # Command -> string showing synonyms
         syns = {}
-        for c, e in commands.table.iteritems():
+        for c, e in pycompat.iteritems(commands.table):
             fs = cmdutil.parsealiases(c)
             f = fs[0]
             syns[f] = b', '.join(fs)
diff --git a/mercurial/formatter.py b/mercurial/formatter.py
--- a/mercurial/formatter.py
+++ b/mercurial/formatter.py
@@ -280,7 +280,7 @@
 def _iteritems(data):
     '''iterate key-value pairs in stable order'''
     if isinstance(data, dict):
-        return sorted(data.iteritems())
+        return sorted(pycompat.iteritems(data))
     return data
 
 
diff --git a/mercurial/fileset.py b/mercurial/fileset.py
--- a/mercurial/fileset.py
+++ b/mercurial/fileset.py
@@ -629,7 +629,7 @@
 def loadpredicate(ui, extname, registrarobj):
     """Load fileset predicates from specified registrarobj
     """
-    for name, func in registrarobj._table.iteritems():
+    for name, func in pycompat.iteritems(registrarobj._table):
         symbols[name] = func
 
 
diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py
--- a/mercurial/filemerge.py
+++ b/mercurial/filemerge.py
@@ -1231,7 +1231,7 @@
 def loadinternalmerge(ui, extname, registrarobj):
     """Load internal merge tool from specified registrarobj
     """
-    for name, func in registrarobj._table.iteritems():
+    for name, func in pycompat.iteritems(registrarobj._table):
         fullname = b':' + name
         internals[fullname] = func
         internals[b'internal:' + name] = func
diff --git a/mercurial/exthelper.py b/mercurial/exthelper.py
--- a/mercurial/exthelper.py
+++ b/mercurial/exthelper.py
@@ -106,7 +106,7 @@
         self._extcommandwrappers.extend(other._extcommandwrappers)
         self._functionwrappers.extend(other._functionwrappers)
         self.cmdtable.update(other.cmdtable)
-        for section, items in other.configtable.iteritems():
+        for section, items in pycompat.iteritems(other.configtable):
             if section in self.configtable:
                 self.configtable[section].update(items)
             else:
diff --git a/mercurial/extensions.py b/mercurial/extensions.py
--- a/mercurial/extensions.py
+++ b/mercurial/extensions.py
@@ -74,7 +74,7 @@
     try:
         mod = _extensions[name]
     except KeyError:
-        for k, v in _extensions.iteritems():
+        for k, v in pycompat.iteritems(_extensions):
             if k.endswith(b'.' + name) or k.endswith(b'/' + name):
                 mod = v
                 break
@@ -167,7 +167,7 @@
 
 def _validatecmdtable(ui, cmdtable):
     """Check if extension commands have required attributes"""
-    for c, e in cmdtable.iteritems():
+    for c, e in pycompat.iteritems(cmdtable):
         f = e[0]
         missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)]
         if not missing:
@@ -551,7 +551,7 @@
     '''
     assert callable(wrapper)
     aliases, entry = cmdutil.findcmd(command, table)
-    for alias, e in table.iteritems():
+    for alias, e in pycompat.iteritems(table):
         if e is entry:
             key = alias
             break
@@ -725,7 +725,7 @@
         if name in exts or name in _order or name == b'__init__':
             continue
         exts[name] = path
-    for name, path in _disabledextensions.iteritems():
+    for name, path in pycompat.iteritems(_disabledextensions):
         # If no path was provided for a disabled extension (e.g. "color=!"),
         # don't replace the path we already found by the scan above.
         if path:
@@ -787,7 +787,7 @@
 
         return dict(
             (name, gettext(desc))
-            for name, desc in __index__.docs.iteritems()
+            for name, desc in pycompat.iteritems(__index__.docs)
             if name not in _order
         )
     except (ImportError, AttributeError):
@@ -798,7 +798,7 @@
         return {}
 
     exts = {}
-    for name, path in paths.iteritems():
+    for name, path in pycompat.iteritems(paths):
         doc = _disabledhelp(path)
         if doc:
             exts[name] = doc.splitlines()[0]
@@ -897,7 +897,7 @@
         ext = _finddisabledcmd(ui, cmd, cmd, path, strict=strict)
     if not ext:
         # otherwise, interrogate each extension until there's a match
-        for name, path in paths.iteritems():
+        for name, path in pycompat.iteritems(paths):
             ext = _finddisabledcmd(ui, cmd, name, path, strict=strict)
             if ext:
                 break
@@ -921,7 +921,7 @@
 
 def notloaded():
     '''return short names of extensions that failed to load'''
-    return [name for name, mod in _extensions.iteritems() if mod is None]
+    return [name for name, mod in pycompat.iteritems(_extensions) if mod is None]
 
 
 def moduleversion(module):
diff --git a/mercurial/exchangev2.py b/mercurial/exchangev2.py
--- a/mercurial/exchangev2.py
+++ b/mercurial/exchangev2.py
@@ -429,7 +429,7 @@
     linkrevs = {}
     seen = set()
 
-    for clrev, node in sorted(manifestnodes.iteritems()):
+    for clrev, node in sorted(pycompat.iteritems(manifestnodes)):
         if node in seen:
             continue
 
@@ -641,7 +641,7 @@
 
                 locallinkrevs[path] = {
                     node: linkrevs[manifestnode]
-                    for node, manifestnode in nodes.iteritems()
+                    for node, manifestnode in pycompat.iteritems(nodes)
                 }
 
             for path, f in fs:
@@ -758,7 +758,7 @@
 
                 linkrevs = {
                     fnode: manlinkrevs[mnode]
-                    for fnode, mnode in fnodes[path].iteritems()
+                    for fnode, mnode in pycompat.iteritems(fnodes[path])
                 }
 
                 def getlinkrev(node):
diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -957,7 +957,7 @@
             bundler.newpart(b'check:heads', data=iter(pushop.remoteheads))
         else:
             affected = set()
-            for branch, heads in pushop.pushbranchmap.iteritems():
+            for branch, heads in pycompat.iteritems(pushop.pushbranchmap):
                 remoteheads, newheads, unsyncedheads, discardedheads = heads
                 if remoteheads is not None:
                     remote = set(remoteheads)
@@ -1260,7 +1260,7 @@
 
         part = bundler.newpart(b'pushvars')
 
-        for key, value in shellvars.iteritems():
+        for key, value in pycompat.iteritems(shellvars):
             part.addparam(key, value, mandatory=False)
 
 
diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -540,7 +540,7 @@
 
         try:
             aliases, entry = cmdutil.findcmd(self.name, cmdtable)
-            for alias, e in cmdtable.iteritems():
+            for alias, e in pycompat.iteritems(cmdtable):
                 if e is entry:
                     self.cmd = alias
                     break
diff --git a/mercurial/discovery.py b/mercurial/discovery.py
--- a/mercurial/discovery.py
+++ b/mercurial/discovery.py
@@ -21,6 +21,7 @@
     branchmap,
     error,
     phases,
+    pycompat,
     scmutil,
     setdiscovery,
     treediscovery,
@@ -226,7 +227,7 @@
 
     knownnode = cl.hasnode  # do not use nodemap until it is filtered
     # A. register remote heads of branches which are in outgoing set
-    for branch, heads in remotemap.iteritems():
+    for branch, heads in pycompat.iteritems(remotemap):
         # don't add head info about branches which we don't have locally
         if branch not in branches:
             continue
@@ -248,13 +249,13 @@
     # This will possibly add new heads and remove existing ones.
     newmap = branchmap.remotebranchcache(
         (branch, heads[1])
-        for branch, heads in headssum.iteritems()
+        for branch, heads in pycompat.iteritems(headssum)
         if heads[0] is not None
     )
     newmap.update(repo, (ctx.rev() for ctx in missingctx))
-    for branch, newheads in newmap.iteritems():
+    for branch, newheads in pycompat.iteritems(newmap):
         headssum[branch][1][:] = newheads
-    for branch, items in headssum.iteritems():
+    for branch, items in pycompat.iteritems(headssum):
         for l in items:
             if l is not None:
                 l.sort()
@@ -266,7 +267,7 @@
         futureheads = set(torev(h) for h in outgoing.missingheads)
         futureheads |= set(torev(h) for h in outgoing.commonheads)
         allfuturecommon = repo.changelog.ancestors(futureheads, inclusive=True)
-        for branch, heads in sorted(headssum.iteritems()):
+        for branch, heads in sorted(pycompat.iteritems(headssum)):
             remoteheads, newheads, unsyncedheads, placeholder = heads
             result = _postprocessobsolete(pushop, allfuturecommon, newheads)
             headssum[branch] = (
@@ -362,7 +363,7 @@
         headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
     pushop.pushbranchmap = headssum
     newbranches = [
-        branch for branch, heads in headssum.iteritems() if heads[0] is None
+        branch for branch, heads in pycompat.iteritems(headssum) if heads[0] is None
     ]
     # 1. Check for new branches on the remote.
     if newbranches and not newbranch:  # new branch requires --new-branch
@@ -390,7 +391,7 @@
     # If there are more heads after the push than before, a suitable
     # error message, depending on unsynced status, is displayed.
     errormsg = None
-    for branch, heads in sorted(headssum.iteritems()):
+    for branch, heads in sorted(pycompat.iteritems(headssum)):
         remoteheads, newheads, unsyncedheads, discardedheads = heads
         # add unsynced data
         if remoteheads is None:
diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -282,7 +282,7 @@
         return iter(sorted(self._map))
 
     def items(self):
-        return self._map.iteritems()
+        return pycompat.iteritems(self._map)
 
     iteritems = items
 
@@ -670,7 +670,7 @@
     def _writedirstate(self, st):
         # notify callbacks about parents change
         if self._origpl is not None and self._origpl != self._pl:
-            for c, callback in sorted(self._plchangecallbacks.iteritems()):
+            for c, callback in sorted(pycompat.iteritems(self._plchangecallbacks)):
                 callback(self, self._origpl, self._pl)
             self._origpl = None
         # use the modification time of the newly created temporary file as the
@@ -682,7 +682,7 @@
         delaywrite = self._ui.configint(b'debug', b'dirstate.delaywrite')
         if delaywrite > 0:
             # do we have any files to delay for?
-            items = self._map.iteritems()
+            items = pycompat.iteritems(self._map)
             for f, e in items:
                 if e[0] == b'n' and e[3] == now:
                     import time  # to avoid useless import
@@ -863,7 +863,7 @@
         if match.isexact() and self._checkcase:
             normed = {}
 
-            for f, st in results.iteritems():
+            for f, st in pycompat.iteritems(results):
                 if st is None:
                     continue
 
@@ -876,7 +876,7 @@
 
                 paths.add(f)
 
-            for norm, paths in normed.iteritems():
+            for norm, paths in pycompat.iteritems(normed):
                 if len(paths) > 1:
                     for path in paths:
                         folded = self._discoverpath(
@@ -1111,9 +1111,9 @@
         # - match.traversedir does something, because match.traversedir should
         #   be called for every dir in the working dir
         full = listclean or match.traversedir is not None
-        for fn, st in self.walk(
+        for fn, st in pycompat.iteritems(self.walk(
             match, subrepos, listunknown, listignored, full=full
-        ).iteritems():
+        )):
             if not dcontains(fn):
                 if (listignored or mexact(fn)) and dirignore(fn):
                     if listignored:
@@ -1324,7 +1324,7 @@
         util.clearcachedproperty(self, b"otherparentset")
 
     def items(self):
-        return self._map.iteritems()
+        return pycompat.iteritems(self._map)
 
     # forward for python2,3 compat
     iteritems = items
@@ -1412,7 +1412,7 @@
         except AttributeError:
             nonnorm = set()
             otherparent = set()
-            for fname, e in self._map.iteritems():
+            for fname, e in pycompat.iteritems(self._map):
                 if e[0] != b'n' or e[3] == -1:
                     nonnorm.add(fname)
                 if e[0] == b'n' and e[2] == -2:
@@ -1435,7 +1435,7 @@
 
         f = {}
         normcase = util.normcase
-        for name, s in self._map.iteritems():
+        for name, s in pycompat.iteritems(self._map):
             if s[0] != b'r':
                 f[normcase(name)] = name
         f[b'.'] = b'.'  # prevents useless util.fspath() invocation
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -448,7 +448,7 @@
     b2caps = bundle2.bundle2caps(peer)
     if b2caps:
         ui.writenoi18n(b'Bundle2 capabilities:\n')
-        for key, values in sorted(b2caps.iteritems()):
+        for key, values in sorted(pycompat.iteritems(b2caps)):
             ui.write(b'  %s\n' % key)
             for v in values:
                 ui.write(b'    %s\n' % v)
@@ -870,7 +870,7 @@
         keyfunc = lambda x: (x[1][3], x[0])  # sort by mtime, then by filename
     else:
         keyfunc = None  # sort by filename
-    for file_, ent in sorted(repo.dirstate.iteritems(), key=keyfunc):
+    for file_, ent in sorted(pycompat.iteritems(repo.dirstate), key=keyfunc):
         if ent[3] == -1:
             timestr = b'unset               '
         elif nodates:
@@ -2029,7 +2029,7 @@
     names = set()
     # since we previously only listed open branches, we will handle that
     # specially (after this for loop)
-    for name, ns in repo.names.iteritems():
+    for name, ns in pycompat.iteritems(repo.names):
         if name != b'branches':
             names.update(ns.listnames(repo))
     names.update(
@@ -2258,7 +2258,7 @@
         fullpaths = opts[r'full']
         files, dirs = set(), set()
         adddir, addfile = dirs.add, files.add
-        for f, st in dirstate.iteritems():
+        for f, st in pycompat.iteritems(dirstate):
             if f.startswith(spec) and st[0] in acceptable:
                 if fixpaths:
                     f = f.replace(b'/', pycompat.ossep)
@@ -2444,7 +2444,7 @@
         ui.status(pycompat.bytestr(r) + b'\n')
         return not r
     else:
-        for k, v in sorted(target.listkeys(namespace).iteritems()):
+        for k, v in sorted(pycompat.iteritems(target.listkeys(namespace))):
             ui.write(
                 b"%s\t%s\n" % (stringutil.escapestr(k), stringutil.escapestr(v))
             )
@@ -3582,7 +3582,7 @@
     for opt in cmdutil.remoteopts:
         del opts[opt[1]]
     args = {}
-    for k, v in opts.iteritems():
+    for k, v in pycompat.iteritems(opts):
         if v:
             args[k] = v
     args = pycompat.strkwargs(args)
diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -17,6 +17,7 @@
     match as matchmod,
     node,
     pathutil,
+    pycompat,
     util,
 )
 from .utils import stringutil
@@ -144,7 +145,7 @@
 def _chain(a, b):
     """chain two sets of copies 'a' and 'b'"""
     t = a.copy()
-    for k, v in b.iteritems():
+    for k, v in pycompat.iteritems(b):
         if v in t:
             t[k] = t[v]
         else:
@@ -353,7 +354,7 @@
     # to filter the source instead.
     f = _forwardcopies(b, a)
     r = {}
-    for k, v in sorted(f.iteritems()):
+    for k, v in sorted(pycompat.iteritems(f)):
         if match and not match(v):
             continue
         # remove copies
@@ -632,7 +633,7 @@
 
     # examine each file copy for a potential directory move, which is
     # when all the files in a directory are moved to a new directory
-    for dst, src in fullcopy.iteritems():
+    for dst, src in pycompat.iteritems(fullcopy):
         dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
         if dsrc in invalid:
             # already seen to be uninteresting
@@ -658,7 +659,7 @@
     if not dirmove:
         return copy, {}, diverge, renamedelete, {}
 
-    dirmove = {k + b"/": v + b"/" for k, v in dirmove.iteritems()}
+    dirmove = {k + b"/": v + b"/" for k, v in pycompat.iteritems(dirmove)}
 
     for d in dirmove:
         repo.ui.debug(
@@ -736,7 +737,7 @@
         ctx = ctx.p1()
 
     cp = _forwardcopies(base, c2)
-    for dst, src in cp.iteritems():
+    for dst, src in pycompat.iteritems(cp):
         if src in m1:
             copies[dst] = src
 
@@ -845,7 +846,7 @@
         # of the function is much faster (and is required for carrying copy
         # metadata across the rebase anyway).
         exclude = pathcopies(repo[fromrev], repo[skiprev])
-    for dst, src in pathcopies(repo[fromrev], repo[rev]).iteritems():
+    for dst, src in pycompat.iteritems(pathcopies(repo[fromrev], repo[rev])):
         if dst in exclude:
             continue
         if dst in wctx:
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -126,7 +126,7 @@
         deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
         deletedset = set(deleted)
         d = mf1.diff(mf2, match=match, clean=listclean)
-        for fn, value in d.iteritems():
+        for fn, value in pycompat.iteritems(d):
             if fn in deletedset:
                 continue
             if value is None:
diff --git a/mercurial/config.py b/mercurial/config.py
--- a/mercurial/config.py
+++ b/mercurial/config.py
@@ -86,7 +86,7 @@
         return sorted(self._data.keys())
 
     def items(self, section):
-        return list(self._data.get(section, {}).iteritems())
+        return list(pycompat.iteritems(self._data.get(section, {})))
 
     def set(self, section, item, value, source=b""):
         if pycompat.ispy3:
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2355,7 +2355,7 @@
 )
 def debugcommands(ui, cmd=b'', *args):
     """list all available commands and options"""
-    for cmd, vals in sorted(table.iteritems()):
+    for cmd, vals in sorted(pycompat.iteritems(table)):
         cmd = cmd.split(b'|')[0]
         opts = b', '.join([i[1] for i in vals[1]])
         ui.write(b'%s: %s\n' % (cmd, opts))
@@ -3906,7 +3906,7 @@
                 hexremoterev = hex(remoterev)
                 bms = [
                     bm
-                    for bm, bmr in peer.listkeys(b'bookmarks').iteritems()
+                    for bm, bmr in pycompat.iteritems(peer.listkeys(b'bookmarks'))
                     if bmr == hexremoterev
                 ]
 
@@ -5146,11 +5146,11 @@
     if search:
         pathitems = [
             (name, path)
-            for name, path in ui.paths.iteritems()
+            for name, path in pycompat.iteritems(ui.paths)
             if name == search
         ]
     else:
-        pathitems = sorted(ui.paths.iteritems())
+        pathitems = sorted(pycompat.iteritems(ui.paths))
 
     fm = ui.formatter(b'paths', opts)
     if fm.isplain():
@@ -6959,7 +6959,7 @@
 
     c = repo.dirstate.copies()
     copied, renamed = [], []
-    for d, s in c.iteritems():
+    for d, s in pycompat.iteritems(c):
         if s in status.removed:
             status.removed.remove(s)
             renamed.append(d)
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -582,7 +582,7 @@
             # 5. finally restore backed-up files
             try:
                 dirstate = repo.dirstate
-                for realname, tmpname in backups.iteritems():
+                for realname, tmpname in pycompat.iteritems(backups):
                     ui.debug(b'restoring %r to %r\n' % (tmpname, realname))
 
                     if dirstate[realname] == b'n':
diff --git a/mercurial/chgserver.py b/mercurial/chgserver.py
--- a/mercurial/chgserver.py
+++ b/mercurial/chgserver.py
@@ -131,7 +131,7 @@
         ignored = set()
     envitems = [
         (k, v)
-        for k, v in encoding.environ.iteritems()
+        for k, v in pycompat.iteritems(encoding.environ)
         if _envre.match(k) and k not in ignored
     ]
     envhash = _hashlist(sorted(envitems))
@@ -317,7 +317,7 @@
 
     def __call__(self, cmd, environ, cwd=None, type=b'system', cmdtable=None):
         args = [type, procutil.quotecommand(cmd), os.path.abspath(cwd or b'.')]
-        args.extend(b'%s=%s' % (k, v) for k, v in environ.iteritems())
+        args.extend(b'%s=%s' % (k, v) for k, v in pycompat.iteritems(environ))
         data = b'\0'.join(args)
         self.out.write(struct.pack(b'>cI', self.channel, len(data)))
         self.out.write(data)
diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -353,7 +353,7 @@
                     mfnode = cl.changelogrevision(cset).manifest
                     mfest = ml[mfnode].readdelta()
                     # store file cgnodes we must see
-                    for f, n in mfest.iteritems():
+                    for f, n in pycompat.iteritems(mfest):
                         needfiles.setdefault(f, set()).add(n)
 
             # process the files
@@ -991,7 +991,7 @@
         if self._ellipses and self._isshallow:
             mfdicts = [
                 (self._repo.manifestlog[n].read(), lr)
-                for (n, lr) in manifests.iteritems()
+                for (n, lr) in pycompat.iteritems(manifests)
             ]
 
         manifests.clear()
@@ -1672,7 +1672,7 @@
                 del needfiles[f]
     progress.complete()
 
-    for f, needs in needfiles.iteritems():
+    for f, needs in pycompat.iteritems(needfiles):
         fl = repo.file(f)
         for n in needs:
             try:
diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py
--- a/mercurial/branchmap.py
+++ b/mercurial/branchmap.py
@@ -228,7 +228,7 @@
         return key in self._entries
 
     def iteritems(self):
-        for k, v in self._entries.iteritems():
+        for k, v in pycompat.iteritems(self._entries):
             self._verifybranch(k)
             yield k, v
 
@@ -344,7 +344,7 @@
         return heads
 
     def iterbranches(self):
-        for bn, heads in self.iteritems():
+        for bn, heads in pycompat.iteritems(self):
             yield (bn, heads) + self._branchtip(heads)
 
     def iterheads(self):
@@ -370,7 +370,7 @@
                 cachekey.append(hex(self.filteredhash))
             f.write(b" ".join(cachekey) + b'\n')
             nodecount = 0
-            for label, nodes in sorted(self._entries.iteritems()):
+            for label, nodes in sorted(pycompat.iteritems(self._entries)):
                 label = encoding.fromlocal(label)
                 for node in nodes:
                     nodecount += 1
@@ -420,7 +420,7 @@
         # if older branchheads are reachable from new ones, they aren't
         # really branchheads. Note checking parents is insufficient:
         # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
-        for branch, newheadrevs in newbranches.iteritems():
+        for branch, newheadrevs in pycompat.iteritems(newbranches):
             bheads = self._entries.setdefault(branch, [])
             bheadset = set(cl.rev(node) for node in bheads)
 
diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py
--- a/mercurial/bookmarks.py
+++ b/mercurial/bookmarks.py
@@ -137,7 +137,7 @@
         return iter(self._refmap)
 
     def iteritems(self):
-        return self._refmap.iteritems()
+        return pycompat.iteritems(self._refmap)
 
     def items(self):
         return self._refmap.items()
@@ -245,7 +245,7 @@
         self._aclean = True
 
     def _write(self, fp):
-        for name, node in sorted(self._refmap.iteritems()):
+        for name, node in sorted(pycompat.iteritems(self._refmap)):
             fp.write(b"%s %s\n" % (hex(node), encoding.fromlocal(name)))
         self._clean = True
         self._repo.invalidatevolatilesets()
@@ -413,7 +413,7 @@
         )
     name = repo._activebookmark.split(b'@', 1)[0]
     heads = []
-    for mark, n in repo._bookmarks.iteritems():
+    for mark, n in pycompat.iteritems(repo._bookmarks):
         if mark.split(b'@', 1)[0] == name:
             heads.append(n)
     return heads
@@ -467,7 +467,7 @@
     marks = getattr(repo, '_bookmarks', {})
 
     hasnode = repo.changelog.hasnode
-    for k, v in marks.iteritems():
+    for k, v in pycompat.iteritems(marks):
         # don't expose local divergent bookmarks
         if hasnode(v) and (b'@' not in k or k.endswith(b'@')):
             yield k, v
@@ -999,7 +999,7 @@
     hexfn = fm.hexfunc
     if len(bmarks) == 0 and fm.isplain():
         ui.status(_(b"no bookmarks set\n"))
-    for bmark, (n, prefix, label) in sorted(bmarks.iteritems()):
+    for bmark, (n, prefix, label) in sorted(pycompat.iteritems(bmarks)):
         fm.startitem()
         fm.context(repo=repo)
         if not ui.quiet:
diff --git a/mercurial/archival.py b/mercurial/archival.py
--- a/mercurial/archival.py
+++ b/mercurial/archival.py
@@ -74,7 +74,7 @@
 
 
 def guesskind(dest):
-    for kind, extensions in exts.iteritems():
+    for kind, extensions in pycompat.iteritems(exts):
         if any(dest.endswith(ext) for ext in extensions):
             return kind
     return None
diff --git a/mercurial/__init__.py b/mercurial/__init__.py
--- a/mercurial/__init__.py
+++ b/mercurial/__init__.py
@@ -7,199 +7,7 @@
 
 from __future__ import absolute_import
 
-import sys
-
 # Allow 'from mercurial import demandimport' to keep working.
 import hgdemandimport
 
 demandimport = hgdemandimport
-
-__all__ = []
-
-# Python 3 uses a custom module loader that transforms source code between
-# source file reading and compilation. This is done by registering a custom
-# finder that changes the spec for Mercurial modules to use a custom loader.
-if sys.version_info[0] >= 3:
-    import importlib
-    import importlib.abc
-    import io
-    import token
-    import tokenize
-
-    class hgpathentryfinder(importlib.abc.MetaPathFinder):
-        """A sys.meta_path finder that uses a custom module loader."""
-
-        def find_spec(self, fullname, path, target=None):
-            # Only handle Mercurial-related modules.
-            if not fullname.startswith('mercurial.'):
-                return None
-            # don't try to parse binary
-            if fullname.startswith('mercurial.cext.'):
-                return None
-            # third-party packages are expected to be dual-version clean
-            if fullname.startswith('mercurial.thirdparty'):
-                return None
-            # zstd is already dual-version clean, don't try and mangle it
-            if fullname.startswith('mercurial.zstd'):
-                return None
-            # rustext is built for the right python version,
-            # don't try and mangle it
-            if fullname.startswith('mercurial.rustext'):
-                return None
-
-            # Try to find the module using other registered finders.
-            spec = None
-            for finder in sys.meta_path:
-                if finder == self:
-                    continue
-
-                # Originally the API was a `find_module` method, but it was
-                # renamed to `find_spec` in python 3.4, with a new `target`
-                # argument.
-                find_spec_method = getattr(finder, 'find_spec', None)
-                if find_spec_method:
-                    spec = find_spec_method(fullname, path, target=target)
-                else:
-                    spec = finder.find_module(fullname)
-                    if spec is not None:
-                        spec = importlib.util.spec_from_loader(fullname, spec)
-                if spec:
-                    break
-
-            # This is a Mercurial-related module but we couldn't find it
-            # using the previously-registered finders. This likely means
-            # the module doesn't exist.
-            if not spec:
-                return None
-
-            # TODO need to support loaders from alternate specs, like zip
-            # loaders.
-            loader = hgloader(spec.name, spec.origin)
-            # Can't use util.safehasattr here because that would require
-            # importing util, and we're in import code.
-            if hasattr(spec.loader, 'loader'):  # hasattr-py3-only
-                # This is a nested loader (maybe a lazy loader?)
-                spec.loader.loader = loader
-            else:
-                spec.loader = loader
-            return spec
-
-    def replacetokens(tokens, fullname):
-        """Transform a stream of tokens from raw to Python 3.
-
-        It is called by the custom module loading machinery to rewrite
-        source/tokens between source decoding and compilation.
-
-        Returns a generator of possibly rewritten tokens.
-
-        The input token list may be mutated as part of processing. However,
-        its changes do not necessarily match the output token stream.
-
-        REMEMBER TO CHANGE ``BYTECODEHEADER`` WHEN CHANGING THIS FUNCTION
-        OR CACHED FILES WON'T GET INVALIDATED PROPERLY.
-        """
-        # The following utility functions access the tokens list and i index of
-        # the for i, t enumerate(tokens) loop below
-        def _isop(j, *o):
-            """Assert that tokens[j] is an OP with one of the given values"""
-            try:
-                return tokens[j].type == token.OP and tokens[j].string in o
-            except IndexError:
-                return False
-
-        for i, t in enumerate(tokens):
-            # This looks like a function call.
-            if t.type == token.NAME and _isop(i + 1, '('):
-                fn = t.string
-
-                # It changes iteritems/values to items/values as they are not
-                # present in Python 3 world.
-                if fn == 'iteritems' and not (
-                    tokens[i - 1].type == token.NAME
-                    and tokens[i - 1].string == 'def'
-                ):
-                    yield t._replace(string=fn[4:])
-                    continue
-
-            # Emit unmodified token.
-            yield t
-
-    # Header to add to bytecode files. This MUST be changed when
-    # ``replacetoken`` or any mechanism that changes semantics of module
-    # loading is changed. Otherwise cached bytecode may get loaded without
-    # the new transformation mechanisms applied.
-    BYTECODEHEADER = b'HG\x00\x16'
-
-    class hgloader(importlib.machinery.SourceFileLoader):
-        """Custom module loader that transforms source code.
-
-        When the source code is converted to a code object, we transform
-        certain patterns to be Python 3 compatible. This allows us to write code
-        that is natively Python 2 and compatible with Python 3 without
-        making the code excessively ugly.
-
-        We do this by transforming the token stream between parse and compile.
-
-        Implementing transformations invalidates caching assumptions made
-        by the built-in importer. The built-in importer stores a header on
-        saved bytecode files indicating the Python/bytecode version. If the
-        version changes, the cached bytecode is ignored. The Mercurial
-        transformations could change at any time. This means we need to check
-        that cached bytecode was generated with the current transformation
-        code or there could be a mismatch between cached bytecode and what
-        would be generated from this class.
-
-        We supplement the bytecode caching layer by wrapping ``get_data``
-        and ``set_data``. These functions are called when the
-        ``SourceFileLoader`` retrieves and saves bytecode cache files,
-        respectively. We simply add an additional header on the file. As
-        long as the version in this file is changed when semantics change,
-        cached bytecode should be invalidated when transformations change.
-
-        The added header has the form ``HG<VERSION>``. That is a literal
-        ``HG`` with 2 binary bytes indicating the transformation version.
-        """
-
-        def get_data(self, path):
-            data = super(hgloader, self).get_data(path)
-
-            if not path.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)):
-                return data
-
-            # There should be a header indicating the Mercurial transformation
-            # version. If it doesn't exist or doesn't match the current version,
-            # we raise an OSError because that is what
-            # ``SourceFileLoader.get_code()`` expects when loading bytecode
-            # paths to indicate the cached file is "bad."
-            if data[0:2] != b'HG':
-                raise OSError('no hg header')
-            if data[0:4] != BYTECODEHEADER:
-                raise OSError('hg header version mismatch')
-
-            return data[4:]
-
-        def set_data(self, path, data, *args, **kwargs):
-            if path.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)):
-                data = BYTECODEHEADER + data
-
-            return super(hgloader, self).set_data(path, data, *args, **kwargs)
-
-        def source_to_code(self, data, path):
-            """Perform token transformation before compilation."""
-            buf = io.BytesIO(data)
-            tokens = tokenize.tokenize(buf.readline)
-            data = tokenize.untokenize(replacetokens(list(tokens), self.name))
-            # Python's built-in importer strips frames from exceptions raised
-            # for this code. Unfortunately, that mechanism isn't extensible
-            # and our frame will be blamed for the import failure. There
-            # are extremely hacky ways to do frame stripping. We haven't
-            # implemented them because they are very ugly.
-            return super(hgloader, self).source_to_code(data, path)
-
-    # We automagically register our custom importer as a side-effect of
-    # loading. This is necessary to ensure that any entry points are able
-    # to import mercurial.* modules without having to perform this
-    # registration themselves.
-    if not any(isinstance(x, hgpathentryfinder) for x in sys.meta_path):
-        # meta_path is used before any implicit finders and before sys.path.
-        sys.meta_path.insert(0, hgpathentryfinder())



To: indygreg, #hg-reviewers
Cc: mjpieters, mercurial-devel


More information about the Mercurial-devel mailing list