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

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Tue Oct 8 14:30:52 EDT 2019


Closed by commit rHGd783f945a701: py3: finish porting iteritems() to pycompat and remove source transformer (authored by indygreg).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs Review".

CHANGED PRIOR TO COMMIT
  https://phab.mercurial-scm.org/D7015?vs=16938&id=16966#toc

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D7015?vs=16938&id=16966

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D7015/new/

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,10 @@
 
 @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 +1064,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 +1382,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
@@ -246,7 +246,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)
@@ -368,7 +368,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,8 @@
         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 +462,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 +640,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
@@ -514,7 +514,8 @@
 
     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):
@@ -691,7 +692,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,14 @@
     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 +984,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__'):
@@ -544,7 +544,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(
@@ -821,7 +821,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,11 @@
     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 +2071,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,9 @@
             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 +1143,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
@@ -2626,7 +2626,9 @@
         # 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,9 @@
 
     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 +830,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 +912,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 +1054,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 +1085,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 +1202,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 +1244,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 +1261,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 +1312,9 @@
         """
         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 +1343,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 +1366,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 +2148,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':
@@ -802,7 +802,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,8 @@
                     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,9 @@
 
 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,9 @@
         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 +393,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,9 @@
     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 +684,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 +865,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 +878,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 +1113,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(
-            match, subrepos, listunknown, listignored, full=full
-        ).iteritems():
+        for fn, st in pycompat.iteritems(
+            self.walk(match, subrepos, listunknown, listignored, full=full)
+        ):
             if not dcontains(fn):
                 if (listignored or mexact(fn)) and dirignore(fn):
                     if listignored:
@@ -1324,7 +1326,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 +1414,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 +1437,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:
@@ -2039,7 +2039,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(
@@ -2268,7 +2268,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)
@@ -2454,7 +2454,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))
             )
@@ -3608,7 +3608,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,9 @@
                 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 +5148,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 +6961,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