Patchwork [1,of,6] mercurial: implement a source transforming module loader on Python 3

login
register
mail settings
Submitter Gregory Szorc
Date June 1, 2016, 5:52 a.m.
Message ID <867ebaa1ca956c760226.1464760378@ubuntu-vm-main>
Download mbox | patch
Permalink /patch/15318/
State Accepted
Headers show

Comments

Gregory Szorc - June 1, 2016, 5:52 a.m.
# HG changeset patch
# User Gregory Szorc <gregory.szorc@gmail.com>
# Date 1464759986 25200
#      Tue May 31 22:46:26 2016 -0700
# Node ID 867ebaa1ca956c76022655eb1f7a6f39da42b5a4
# Parent  48b38b16a8f83ea98ebdf0b370f59fd90dc17935
mercurial: implement a source transforming module loader on Python 3

The most painful part of ensuring Python code runs on both Python 2
and 3 is string encoding. Making this difficult is that string
literals in Python 2 are bytes and string literals in Python 3 are
unicode. So, to ensure consistent types are used, you have to
use "from __future__ import unicode_literals" and/or prefix literals
with their type (e.g. b'foo' or u'foo').

Nearly every string in Mercurial is bytes. So, to use the same source
code on both Python 2 and 3 would require prefixing nearly every
string literal with "b" to make it a byte literal. This is ugly and
not something mpm is willing to do.

This patch implements a custom module loader on Python 3 that performs
source transformation to convert string literals (unicode in Python 3)
to byte literals. In effect, it changes Python 3's string literals to
behave like Python 2's.

The module loader is only used on mercurial.* and hgext.* modules.

The loader works by tokenizing the loaded source and replacing
"string" tokens if necessary. The modified token stream is
untokenized back to source and loaded like normal. This does add some
overhead. However, this all occurs before caching: .pyc files will
cache the transformed version. This means the transformation penalty
is only paid on first load.

As the extensive inline comments explain, the presence of a custom
source transformer invalidates assumptions made by Python's built-in
bytecode caching mechanism. So, we have to wrap bytecode loading and
writing and add an additional header to bytecode files to facilitate
additional cache validation when the source transformations
change in the future.

There are still a few things this code doesn't handle well, namely
support for zip files as module sources and for extensions. Since
Mercurial doesn't officially support Python 3 yet, I'm inclined to
leave these as to-do items: getting a basic module loading mechanism
in place to unblock further Python 3 porting effort is more important
than comprehensive module importing support.

check-py3-compat.py has been updated to ignore frames. This is
necessary because CPython has built-in code to strip frames from the
built-in importer. When our custom code is present, this doesn't work
and the frames get all messed up. The new code is not perfect. It
works for now. But once you start chasing import failures you find
some edge cases where the files aren't being printed properly. This
only burdens people doing future Python 3 porting work so I'm inclined
to punt on the issue: the most important thing if for the source
transforming module loader to land.

There was a bit of churn in test-check-py3-compat.t because we now
trip up on str/unicode/bytes failures as a result of source
transformation. This is unfortunate. But what are you going to do?
Martijn Pieters - June 6, 2016, 3:44 p.m.
On 31 May 2016 at 22:52, Gregory Szorc <gregory.szorc@gmail.com> wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc@gmail.com>
> # Date 1464759986 25200
> #      Tue May 31 22:46:26 2016 -0700
> # Node ID 867ebaa1ca956c76022655eb1f7a6f39da42b5a4
> # Parent  48b38b16a8f83ea98ebdf0b370f59fd90dc17935
> mercurial: implement a source transforming module loader on Python 3
>
> The most painful part of ensuring Python code runs on both Python 2
> and 3 is string encoding. Making this difficult is that string
> literals in Python 2 are bytes and string literals in Python 3 are
> unicode. So, to ensure consistent types are used, you have to
> use "from __future__ import unicode_literals" and/or prefix literals
> with their type (e.g. b'foo' or u'foo').
>
> Nearly every string in Mercurial is bytes. So, to use the same source
> code on both Python 2 and 3 would require prefixing nearly every
> string literal with "b" to make it a byte literal. This is ugly and
> not something mpm is willing to do.
>
> This patch implements a custom module loader on Python 3 that performs
> source transformation to convert string literals (unicode in Python 3)
> to byte literals. In effect, it changes Python 3's string literals to
> behave like Python 2's.
>
> The module loader is only used on mercurial.* and hgext.* modules.
>
> The loader works by tokenizing the loaded source and replacing
> "string" tokens if necessary. The modified token stream is
> untokenized back to source and loaded like normal. This does add some
> overhead. However, this all occurs before caching: .pyc files will
> cache the transformed version. This means the transformation penalty
> is only paid on first load.
>
> As the extensive inline comments explain, the presence of a custom
> source transformer invalidates assumptions made by Python's built-in
> bytecode caching mechanism. So, we have to wrap bytecode loading and
> writing and add an additional header to bytecode files to facilitate
> additional cache validation when the source transformations
> change in the future.
>
> There are still a few things this code doesn't handle well, namely
> support for zip files as module sources and for extensions. Since
> Mercurial doesn't officially support Python 3 yet, I'm inclined to
> leave these as to-do items: getting a basic module loading mechanism
> in place to unblock further Python 3 porting effort is more important
> than comprehensive module importing support.
>
> check-py3-compat.py has been updated to ignore frames. This is
> necessary because CPython has built-in code to strip frames from the
> built-in importer. When our custom code is present, this doesn't work
> and the frames get all messed up. The new code is not perfect. It
> works for now. But once you start chasing import failures you find
> some edge cases where the files aren't being printed properly. This
> only burdens people doing future Python 3 porting work so I'm inclined
> to punt on the issue: the most important thing if for the source
> transforming module loader to land.
>
> There was a bit of churn in test-check-py3-compat.t because we now
> trip up on str/unicode/bytes failures as a result of source
> transformation. This is unfortunate. But what are you going to do?
>
> diff --git a/contrib/check-py3-compat.py b/contrib/check-py3-compat.py
> --- a/contrib/check-py3-compat.py
> +++ b/contrib/check-py3-compat.py
> @@ -56,17 +56,30 @@ def check_compat_py3(f):
>      if f.startswith(('hgext/', 'mercurial/')) and not f.endswith('__init__.py'):
>          assert f.endswith('.py')
>          name = f.replace('/', '.')[:-3]
>          with open(f, 'r') as fh:
>              try:
>                  imp.load_module(name, fh, '', ('py', 'r', imp.PY_SOURCE))
>              except Exception as e:
>                  exc_type, exc_value, tb = sys.exc_info()
> -                frame = traceback.extract_tb(tb)[-1]
> +                # We walk the stack and ignore frames from our custom importer,
> +                # import mechanisms, and stdlib modules. This kinda/sorta
> +                # emulates CPython behavior in import.c while also attempting
> +                # to pin blame on a Mercurial file.
> +                for frame in reversed(traceback.extract_tb(tb)):
> +                    if frame.name == '_call_with_frames_removed':
> +                        continue
> +                    if 'importlib' in frame.filename:
> +                        continue
> +                    if 'mercurial/__init__.py' in frame.filename:
> +                        continue
> +                    if frame.filename.startswith(sys.prefix):
> +                        continue
> +                    break
>
>                  if frame.filename:
>                      filename = os.path.basename(frame.filename)
>                      print('%s: error importing: <%s> %s (error at %s:%d)' % (
>                            f, type(e).__name__, e, filename, frame.lineno))
>                  else:
>                      print('%s: error importing module: <%s> %s (line %d)' % (
>                            f, type(e).__name__, e, frame.lineno))
> diff --git a/mercurial/__init__.py b/mercurial/__init__.py
> --- a/mercurial/__init__.py
> +++ b/mercurial/__init__.py
> @@ -116,14 +116,168 @@ class hgimporter(object):
>              if not modinfo:
>                  raise ImportError('could not find mercurial module %s' %
>                                    name)
>
>          mod = imp.load_module(name, *modinfo)
>          sys.modules[name] = mod
>          return mod
>
> +# 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:
> +    from . import pure
> +    import importlib
> +    import io
> +    import token
> +    import tokenize
> +
> +    class hgpathentryfinder(importlib.abc.PathEntryFinder):
> +        """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.', 'hgext.')):
> +                return None
> +
> +            # This assumes Python 3 doesn't support loading C modules.
> +            if fullname in _dualmodules:
> +                stem = fullname.split('.')[-1]
> +                fullname = 'mercurial.pure.%s' % stem
> +                target = pure
> +                assert len(path) == 1
> +                path = [os.path.join(path[0], 'pure')]
> +
> +            # Try to find the module using other registered finders.
> +            spec = None
> +            for finder in sys.meta_path:
> +                if finder == self:
> +                    continue
> +
> +                spec = finder.find_spec(fullname, path, target=target)
> +                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
> +
> +            if fullname.startswith('mercurial.pure.'):
> +                spec.name = spec.name.replace('.pure.', '.')
> +
> +            # TODO need to support loaders from alternate specs, like zip
> +            # loaders.
> +            spec.loader = hgloader(spec.name, spec.origin)
> +            return spec
> +
> +    def replacetoken(t):
> +        """Transform a source token from raw to Python 3.
> +
> +        This function is called for every lexical token found from
> +        ``tokenize.tokenize()``. It allows the module loader to rewrite
> +        tokens between source decoding and compilation.
> +
> +        REMEMBER TO BUMP ``BYTECODEHEADER`` WHEN CHANGING THIS FUNCTION.
> +        """
> +        # Convert most string literals to byte literals. String literals
> +        # in Python 2 are bytes. String literals in Python 3 are unicode.
> +        # Most strings in Mercurial are bytes and unicode strings are rare.
> +        # Rather than rewrite all string literals to use ``b''`` to indicate
> +        # byte strings, we apply this token transformer to insert the ``b``
> +        # prefix nearly everywhere.
> +        if t.type == token.STRING:
> +            s = t.string
> +
> +            # If a docstring, keep it as a string literal.
> +            if s[0:3] in ("'''", '"""'):
> +                return t
> +
> +            if s[0] not in ("'", '"'):
> +                return t
> +
> +            # String literal. Prefix to make a b'' string.
> +            return tokenize.TokenInfo(t.type, 'b%s' % s, t.start, t.end, t.line)
> +
> +        return 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\x01'
> +
> +    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.
> +            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(replacetoken(t) for t in tokens)
> +            # 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, hgimporter) for x in sys.meta_path):
> +if sys.version_info[0] >= 3:
> +    _importercls = hgpathentryfinder
> +else:
> +    _importercls = hgimporter
> +if not any(isinstance(x, _importercls) for x in sys.meta_path):
>      # meta_path is used before any implicit finders and before sys.path.
> -    sys.meta_path.insert(0, hgimporter())
> +    sys.meta_path.insert(0, _importercls())
> diff --git a/tests/test-check-py3-compat.t b/tests/test-check-py3-compat.t
> --- a/tests/test-check-py3-compat.t
> +++ b/tests/test-check-py3-compat.t
> @@ -30,133 +30,164 @@
>    tests/md5sum.py not using absolute_import
>    tests/readlink.py not using absolute_import
>    tests/run-tests.py not using absolute_import
>    tests/test-demandimport.py not using absolute_import
>
>  #if py3exe
>    $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs $PYTHON3 contrib/check-py3-compat.py
>    doc/hgmanpage.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
> -  hgext/automv.py: error importing module: <SyntaxError> invalid syntax (commands.py, line *) (line *) (glob)
> -  hgext/blackbox.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/bugzilla.py: error importing module: <ImportError> No module named 'urlparse' (line *) (glob)
> -  hgext/censor.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/chgserver.py: error importing module: <ImportError> No module named 'SocketServer' (line *) (glob)
> -  hgext/children.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/churn.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/clonebundles.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> +  hgext/acl.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/automv.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/blackbox.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/bugzilla.py: error importing module: <ImportError> No module named 'urlparse' (line 284)
> +  hgext/censor.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/chgserver.py: error importing module: <ImportError> No module named 'SocketServer' (line 43)
> +  hgext/children.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/churn.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/clonebundles.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
>    hgext/color.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
> -  hgext/convert/bzr.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
> -  hgext/convert/common.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
> -  hgext/convert/convcmd.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> -  hgext/convert/cvs.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
> -  hgext/convert/cvsps.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
> -  hgext/convert/darcs.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
> -  hgext/convert/filemap.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
> -  hgext/convert/git.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
> -  hgext/convert/gnuarch.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
> -  hgext/convert/hg.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/convert/monotone.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
> -  hgext/convert/p*.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
> -  hgext/convert/subversion.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
> -  hgext/convert/transport.py: error importing module: <ImportError> No module named 'svn.client' (line *) (glob)
> -  hgext/eol.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/extdiff.py: error importing module: <SyntaxError> invalid syntax (archival.py, line *) (line *) (glob)
> -  hgext/factotum.py: error importing: <ImportError> No module named 'rfc822' (error at __init__.py:*) (glob)
> -  hgext/fetch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/fsmonitor/watchmanclient.py: error importing module: <SystemError> Parent module 'hgext.fsmonitor' not loaded, cannot perform relative import (line *) (glob)
> -  hgext/gpg.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/graphlog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/hgk.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/histedit.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
> -  hgext/keyword.py: error importing: <ImportError> No module named 'BaseHTTPServer' (error at common.py:*) (glob)
> -  hgext/largefiles/basestore.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> -  hgext/largefiles/lfcommands.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> -  hgext/largefiles/lfutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/largefiles/localstore.py: error importing module: <ImportError> No module named 'lfutil' (line *) (glob)
> -  hgext/largefiles/overrides.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> +  hgext/convert/bzr.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/common.py: error importing module: <ImportError> No module named 'cPickle' (line 10)
> +  hgext/convert/convcmd.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/cvs.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/cvsps.py: error importing module: <ImportError> No module named 'cPickle' (line 9)
> +  hgext/convert/darcs.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/filemap.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/git.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/gnuarch.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/hg.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/monotone.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/p4.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/subversion.py: error importing module: <ImportError> No module named 'cPickle' (line 6)
> +  hgext/convert/transport.py: error importing module: <ImportError> No module named 'svn.client' (line 21)
> +  hgext/eol.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/extdiff.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/factotum.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/fetch.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/fsmonitor/state.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/fsmonitor/watchmanclient.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/gpg.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/graphlog.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/hgk.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/highlight/highlight.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/histedit.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/keyword.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/basestore.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/lfcommands.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/lfutil.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/localstore.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/overrides.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
>    hgext/largefiles/proto.py: error importing: <ImportError> No module named 'httplib' (error at httppeer.py:*) (glob)
> -  hgext/largefiles/remotestore.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at wireproto.py:*) (glob)
> -  hgext/largefiles/reposetup.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> +  hgext/largefiles/remotestore.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/reposetup.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
>    hgext/largefiles/uisetup.py: error importing module: <SyntaxError> invalid syntax (archival.py, line *) (line *) (glob)
> -  hgext/largefiles/wirestore.py: error importing module: <ImportError> No module named 'lfutil' (line *) (glob)
> -  hgext/mq.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/notify.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/pager.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/patchbomb.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/purge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/rebase.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/record.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/relink.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/schemes.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/share.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/shelve.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
> -  hgext/strip.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/transplant.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> +  hgext/largefiles/wirestore.py: error importing module: <ImportError> No module named 'lfutil' (line 8)
> +  hgext/mq.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/notify.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/pager.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/patchbomb.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/purge.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/rebase.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/record.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/relink.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/schemes.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/share.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/shelve.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/strip.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/transplant.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/win32mbcs.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/win32text.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
>    mercurial/archival.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
> -  mercurial/branchmap.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> +  mercurial/bookmarks.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/branchmap.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
>    mercurial/bundle*.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
> -  mercurial/bundlerepo.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
> -  mercurial/changegroup.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/changelog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/cmdutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> +  mercurial/bundlerepo.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/byterange.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/changegroup.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/changelog.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/cmdutil.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
>    mercurial/commands.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
> -  mercurial/commandserver.py: error importing module: <ImportError> No module named 'SocketServer' (line *) (glob)
> -  mercurial/context.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/copies.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/crecord.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/dirstate.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/discovery.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/dispatch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/exchange.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
> -  mercurial/extensions.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/filelog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/filemerge.py: error importing: <ImportError> No module named 'cPickle' (error at formatter.py:*) (glob)
> -  mercurial/fileset.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/formatter.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
> -  mercurial/graphmod.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/help.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/hg.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> -  mercurial/hgweb/common.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line *) (glob)
> -  mercurial/hgweb/hgweb_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
> -  mercurial/hgweb/hgwebdir_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
> -  mercurial/hgweb/protocol.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
> -  mercurial/hgweb/request.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
> -  mercurial/hgweb/server.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line *) (glob)
> -  mercurial/hgweb/webcommands.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
> -  mercurial/hgweb/webutil.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
> -  mercurial/hgweb/wsgicgi.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
> -  mercurial/hook.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/httpconnection.py: error importing: <ImportError> No module named 'rfc822' (error at __init__.py:*) (glob)
> -  mercurial/httppeer.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
> -  mercurial/keepalive.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
> -  mercurial/localrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/mail.py: error importing module: <AttributeError> module 'email' has no attribute 'Header' (line *) (glob)
> -  mercurial/manifest.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/merge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/namespaces.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/patch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/pure/mpatch.py: error importing module: <ImportError> cannot import name 'pycompat' (line *) (glob)
> -  mercurial/pure/parsers.py: error importing module: <ImportError> No module named 'mercurial.pure.node' (line *) (glob)
> +  mercurial/commandserver.py: error importing module: <ImportError> No module named 'SocketServer' (line 10)
> +  mercurial/config.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/context.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/copies.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/crecord.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/dagparser.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/dagutil.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/destutil.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/dirstate.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/discovery.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/dispatch.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/exchange.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/extensions.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/fancyopts.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/filelog.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/filemerge.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/fileset.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/formatter.py: error importing module: <ImportError> No module named 'cPickle' (line 10)
> +  mercurial/graphmod.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/hbisect.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/help.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/hg.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/hgweb/common.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line 11)
> +  mercurial/hgweb/hgweb_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 14)
> +  mercurial/hgweb/hgwebdir_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 15)
> +  mercurial/hgweb/protocol.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 13)
> +  mercurial/hgweb/request.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 15)
> +  mercurial/hgweb/server.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line 11)
> +  mercurial/hgweb/webcommands.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 16)
> +  mercurial/hgweb/webutil.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 16)
> +  mercurial/hgweb/wsgicgi.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 16)
> +  mercurial/hook.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/httpconnection.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/httppeer.py: error importing module: <ImportError> No module named 'httplib' (line 12)
> +  mercurial/keepalive.py: error importing module: <ImportError> No module named 'httplib' (line 113)
> +  mercurial/localrepo.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/lock.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/mail.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/manifest.py: error importing: <TypeError> getattr(): attribute name must be string (error at pycompat.py:*) (glob)
> +  mercurial/match.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/mdiff.py: error importing: <TypeError> getattr(): attribute name must be string (error at pycompat.py:*) (glob)
> +  mercurial/merge.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/minirst.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/namespaces.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/obsolete.py: error importing: <TypeError> getattr(): attribute name must be string (error at pycompat.py:*) (glob)
> +  mercurial/patch.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/pathutil.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/peer.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/pure/mpatch.py: error importing module: <ImportError> cannot import name 'pycompat' (line 12)
> +  mercurial/pure/parsers.py: error importing module: <ImportError> No module named 'mercurial.pure.node' (line 13)
> +  mercurial/pushkey.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/pvec.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/registrar.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
>    mercurial/repair.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
> -  mercurial/revlog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/revset.py: error importing module: <AttributeError> 'dict' object has no attribute 'iteritems' (line *) (glob)
> -  mercurial/scmutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/scmwindows.py: error importing module: <ImportError> No module named '_winreg' (line *) (glob)
> -  mercurial/simplemerge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/sshpeer.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at wireproto.py:*) (glob)
> -  mercurial/sshserver.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/statichttprepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/store.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/streamclone.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/subrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/templatefilters.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/templatekw.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/templater.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/ui.py: error importing: <ImportError> No module named 'cPickle' (error at formatter.py:*) (glob)
> -  mercurial/unionrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/url.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
> -  mercurial/verify.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/win*.py: error importing module: <ImportError> No module named 'msvcrt' (line *) (glob)
> -  mercurial/windows.py: error importing module: <ImportError> No module named '_winreg' (line *) (glob)
> +  mercurial/repoview.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/revlog.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/revset.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/scmposix.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/scmutil.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/scmwindows.py: error importing module: <ImportError> No module named '_winreg' (line 3)
> +  mercurial/similar.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/simplemerge.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/sshpeer.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/sshserver.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/sslutil.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/statichttprepo.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/store.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/streamclone.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/subrepo.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/tagmerge.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/tags.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/templatefilters.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/templatekw.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/templater.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/transaction.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/ui.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/unionrepo.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/url.py: error importing module: <ImportError> No module named 'httplib' (line 13)
> +  mercurial/util.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/verify.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/win32.py: error importing module: <ImportError> No module named 'msvcrt' (line 12)
> +  mercurial/windows.py: error importing module: <ImportError> No module named '_winreg' (line 10)
>    mercurial/wireproto.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
>
>  #endif
>
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

From a Python 3 tech perspective, this looks sound to me. I like
hijacking the importer machinery for this over using a custom codec,
nice!
Gregory Szorc - June 6, 2016, 7:29 p.m.
On Tue, May 31, 2016 at 10:52 PM, Gregory Szorc <gregory.szorc@gmail.com>
wrote:

> # HG changeset patch
> # User Gregory Szorc <gregory.szorc@gmail.com>
> # Date 1464759986 25200
> #      Tue May 31 22:46:26 2016 -0700
> # Node ID 867ebaa1ca956c76022655eb1f7a6f39da42b5a4
> # Parent  48b38b16a8f83ea98ebdf0b370f59fd90dc17935
> mercurial: implement a source transforming module loader on Python 3
>
> The most painful part of ensuring Python code runs on both Python 2
> and 3 is string encoding. Making this difficult is that string
> literals in Python 2 are bytes and string literals in Python 3 are
> unicode. So, to ensure consistent types are used, you have to
> use "from __future__ import unicode_literals" and/or prefix literals
> with their type (e.g. b'foo' or u'foo').
>
> Nearly every string in Mercurial is bytes. So, to use the same source
> code on both Python 2 and 3 would require prefixing nearly every
> string literal with "b" to make it a byte literal. This is ugly and
> not something mpm is willing to do.
>
> This patch implements a custom module loader on Python 3 that performs
> source transformation to convert string literals (unicode in Python 3)
> to byte literals. In effect, it changes Python 3's string literals to
> behave like Python 2's.
>
> The module loader is only used on mercurial.* and hgext.* modules.
>
> The loader works by tokenizing the loaded source and replacing
> "string" tokens if necessary. The modified token stream is
> untokenized back to source and loaded like normal. This does add some
> overhead. However, this all occurs before caching: .pyc files will
> cache the transformed version. This means the transformation penalty
> is only paid on first load.
>
> As the extensive inline comments explain, the presence of a custom
> source transformer invalidates assumptions made by Python's built-in
> bytecode caching mechanism. So, we have to wrap bytecode loading and
> writing and add an additional header to bytecode files to facilitate
> additional cache validation when the source transformations
> change in the future.
>
> There are still a few things this code doesn't handle well, namely
> support for zip files as module sources and for extensions. Since
> Mercurial doesn't officially support Python 3 yet, I'm inclined to
> leave these as to-do items: getting a basic module loading mechanism
> in place to unblock further Python 3 porting effort is more important
> than comprehensive module importing support.
>
> check-py3-compat.py has been updated to ignore frames. This is
> necessary because CPython has built-in code to strip frames from the
> built-in importer. When our custom code is present, this doesn't work
> and the frames get all messed up. The new code is not perfect. It
> works for now. But once you start chasing import failures you find
> some edge cases where the files aren't being printed properly. This
> only burdens people doing future Python 3 porting work so I'm inclined
> to punt on the issue: the most important thing if for the source
> transforming module loader to land.
>
> There was a bit of churn in test-check-py3-compat.t because we now
> trip up on str/unicode/bytes failures as a result of source
> transformation. This is unfortunate. But what are you going to do?
>

I should probably add this to the commit message, but I chose this approach
over a custom codec because it feels more robust and cleaner to me. With a
custom codec:

* You need to declare the codec in the header of every .py file
* When the transformation semantics change, we'd likely need to bump the
codec name/version otherwise the cached .pyc will get used. This means
updating every .py file whenever we change transformation logic. Yuck.


>
> diff --git a/contrib/check-py3-compat.py b/contrib/check-py3-compat.py
> --- a/contrib/check-py3-compat.py
> +++ b/contrib/check-py3-compat.py
> @@ -56,17 +56,30 @@ def check_compat_py3(f):
>      if f.startswith(('hgext/', 'mercurial/')) and not
> f.endswith('__init__.py'):
>          assert f.endswith('.py')
>          name = f.replace('/', '.')[:-3]
>          with open(f, 'r') as fh:
>              try:
>                  imp.load_module(name, fh, '', ('py', 'r', imp.PY_SOURCE))
>              except Exception as e:
>                  exc_type, exc_value, tb = sys.exc_info()
> -                frame = traceback.extract_tb(tb)[-1]
> +                # We walk the stack and ignore frames from our custom
> importer,
> +                # import mechanisms, and stdlib modules. This kinda/sorta
> +                # emulates CPython behavior in import.c while also
> attempting
> +                # to pin blame on a Mercurial file.
> +                for frame in reversed(traceback.extract_tb(tb)):
> +                    if frame.name == '_call_with_frames_removed':
> +                        continue
> +                    if 'importlib' in frame.filename:
> +                        continue
> +                    if 'mercurial/__init__.py' in frame.filename:
> +                        continue
> +                    if frame.filename.startswith(sys.prefix):
> +                        continue
> +                    break
>
>                  if frame.filename:
>                      filename = os.path.basename(frame.filename)
>                      print('%s: error importing: <%s> %s (error at %s:%d)'
> % (
>                            f, type(e).__name__, e, filename, frame.lineno))
>                  else:
>                      print('%s: error importing module: <%s> %s (line %d)'
> % (
>                            f, type(e).__name__, e, frame.lineno))
> diff --git a/mercurial/__init__.py b/mercurial/__init__.py
> --- a/mercurial/__init__.py
> +++ b/mercurial/__init__.py
> @@ -116,14 +116,168 @@ class hgimporter(object):
>              if not modinfo:
>                  raise ImportError('could not find mercurial module %s' %
>                                    name)
>
>          mod = imp.load_module(name, *modinfo)
>          sys.modules[name] = mod
>          return mod
>
> +# 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:
> +    from . import pure
> +    import importlib
> +    import io
> +    import token
> +    import tokenize
> +
> +    class hgpathentryfinder(importlib.abc.PathEntryFinder):
> +        """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.', 'hgext.')):
> +                return None
> +
> +            # This assumes Python 3 doesn't support loading C modules.
> +            if fullname in _dualmodules:
> +                stem = fullname.split('.')[-1]
> +                fullname = 'mercurial.pure.%s' % stem
> +                target = pure
> +                assert len(path) == 1
> +                path = [os.path.join(path[0], 'pure')]
> +
> +            # Try to find the module using other registered finders.
> +            spec = None
> +            for finder in sys.meta_path:
> +                if finder == self:
> +                    continue
> +
> +                spec = finder.find_spec(fullname, path, target=target)
> +                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
> +
> +            if fullname.startswith('mercurial.pure.'):
> +                spec.name = spec.name.replace('.pure.', '.')
> +
> +            # TODO need to support loaders from alternate specs, like zip
> +            # loaders.
> +            spec.loader = hgloader(spec.name, spec.origin)
> +            return spec
> +
> +    def replacetoken(t):
> +        """Transform a source token from raw to Python 3.
> +
> +        This function is called for every lexical token found from
> +        ``tokenize.tokenize()``. It allows the module loader to rewrite
> +        tokens between source decoding and compilation.
> +
> +        REMEMBER TO BUMP ``BYTECODEHEADER`` WHEN CHANGING THIS FUNCTION.
> +        """
> +        # Convert most string literals to byte literals. String literals
> +        # in Python 2 are bytes. String literals in Python 3 are unicode.
> +        # Most strings in Mercurial are bytes and unicode strings are
> rare.
> +        # Rather than rewrite all string literals to use ``b''`` to
> indicate
> +        # byte strings, we apply this token transformer to insert the
> ``b``
> +        # prefix nearly everywhere.
> +        if t.type == token.STRING:
> +            s = t.string
> +
> +            # If a docstring, keep it as a string literal.
> +            if s[0:3] in ("'''", '"""'):
> +                return t
> +
> +            if s[0] not in ("'", '"'):
> +                return t
> +
> +            # String literal. Prefix to make a b'' string.
> +            return tokenize.TokenInfo(t.type, 'b%s' % s, t.start, t.end,
> t.line)
> +
> +        return 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\x01'
> +
> +    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.
> +            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(replacetoken(t) for t in tokens)
> +            # 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, hgimporter) for x in sys.meta_path):
> +if sys.version_info[0] >= 3:
> +    _importercls = hgpathentryfinder
> +else:
> +    _importercls = hgimporter
> +if not any(isinstance(x, _importercls) for x in sys.meta_path):
>      # meta_path is used before any implicit finders and before sys.path.
> -    sys.meta_path.insert(0, hgimporter())
> +    sys.meta_path.insert(0, _importercls())
> diff --git a/tests/test-check-py3-compat.t b/tests/test-check-py3-compat.t
> --- a/tests/test-check-py3-compat.t
> +++ b/tests/test-check-py3-compat.t
> @@ -30,133 +30,164 @@
>    tests/md5sum.py not using absolute_import
>    tests/readlink.py not using absolute_import
>    tests/run-tests.py not using absolute_import
>    tests/test-demandimport.py not using absolute_import
>
>  #if py3exe
>    $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs $PYTHON3
> contrib/check-py3-compat.py
>    doc/hgmanpage.py: invalid syntax: invalid syntax (<unknown>, line *)
> (glob)
> -  hgext/automv.py: error importing module: <SyntaxError> invalid syntax
> (commands.py, line *) (line *) (glob)
> -  hgext/blackbox.py: error importing: <AttributeError> 'dict' object has
> no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/bugzilla.py: error importing module: <ImportError> No module
> named 'urlparse' (line *) (glob)
> -  hgext/censor.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/chgserver.py: error importing module: <ImportError> No module
> named 'SocketServer' (line *) (glob)
> -  hgext/children.py: error importing: <AttributeError> 'dict' object has
> no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/churn.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/clonebundles.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> +  hgext/acl.py: error importing: <TypeError> encode() argument 1 must be
> str, not bytes (error at encoding.py:*) (glob)
> +  hgext/automv.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/blackbox.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/bugzilla.py: error importing module: <ImportError> No module
> named 'urlparse' (line 284)
> +  hgext/censor.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/chgserver.py: error importing module: <ImportError> No module
> named 'SocketServer' (line 43)
> +  hgext/children.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/churn.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/clonebundles.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
>    hgext/color.py: invalid syntax: invalid syntax (<unknown>, line *)
> (glob)
> -  hgext/convert/bzr.py: error importing module: <SystemError> Parent
> module 'hgext.convert' not loaded, cannot perform relative import (line *)
> (glob)
> -  hgext/convert/common.py: error importing module: <ImportError> No
> module named 'cPickle' (line *) (glob)
> -  hgext/convert/convcmd.py: error importing: <SyntaxError> invalid syntax
> (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> -  hgext/convert/cvs.py: error importing module: <SystemError> Parent
> module 'hgext.convert' not loaded, cannot perform relative import (line *)
> (glob)
> -  hgext/convert/cvsps.py: error importing module: <ImportError> No module
> named 'cPickle' (line *) (glob)
> -  hgext/convert/darcs.py: error importing module: <SystemError> Parent
> module 'hgext.convert' not loaded, cannot perform relative import (line *)
> (glob)
> -  hgext/convert/filemap.py: error importing module: <SystemError> Parent
> module 'hgext.convert' not loaded, cannot perform relative import (line *)
> (glob)
> -  hgext/convert/git.py: error importing module: <SystemError> Parent
> module 'hgext.convert' not loaded, cannot perform relative import (line *)
> (glob)
> -  hgext/convert/gnuarch.py: error importing module: <SystemError> Parent
> module 'hgext.convert' not loaded, cannot perform relative import (line *)
> (glob)
> -  hgext/convert/hg.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/convert/monotone.py: error importing module: <SystemError> Parent
> module 'hgext.convert' not loaded, cannot perform relative import (line *)
> (glob)
> -  hgext/convert/p*.py: error importing module: <SystemError> Parent
> module 'hgext.convert' not loaded, cannot perform relative import (line *)
> (glob)
> -  hgext/convert/subversion.py: error importing module: <ImportError> No
> module named 'cPickle' (line *) (glob)
> -  hgext/convert/transport.py: error importing module: <ImportError> No
> module named 'svn.client' (line *) (glob)
> -  hgext/eol.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/extdiff.py: error importing module: <SyntaxError> invalid syntax
> (archival.py, line *) (line *) (glob)
> -  hgext/factotum.py: error importing: <ImportError> No module named
> 'rfc822' (error at __init__.py:*) (glob)
> -  hgext/fetch.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/fsmonitor/watchmanclient.py: error importing module:
> <SystemError> Parent module 'hgext.fsmonitor' not loaded, cannot perform
> relative import (line *) (glob)
> -  hgext/gpg.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/graphlog.py: error importing: <AttributeError> 'dict' object has
> no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/hgk.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/histedit.py: error importing module: <SyntaxError> invalid syntax
> (bundle*.py, line *) (line *) (glob)
> -  hgext/keyword.py: error importing: <ImportError> No module named
> 'BaseHTTPServer' (error at common.py:*) (glob)
> -  hgext/largefiles/basestore.py: error importing: <SyntaxError> invalid
> syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> -  hgext/largefiles/lfcommands.py: error importing: <SyntaxError> invalid
> syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> -  hgext/largefiles/lfutil.py: error importing: <AttributeError> 'dict'
> object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/largefiles/localstore.py: error importing module: <ImportError>
> No module named 'lfutil' (line *) (glob)
> -  hgext/largefiles/overrides.py: error importing: <SyntaxError> invalid
> syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> +  hgext/convert/bzr.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/common.py: error importing module: <ImportError> No
> module named 'cPickle' (line 10)
> +  hgext/convert/convcmd.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/cvs.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/cvsps.py: error importing module: <ImportError> No module
> named 'cPickle' (line 9)
> +  hgext/convert/darcs.py: error importing: <TypeError> encode() argument
> 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/filemap.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/git.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/gnuarch.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/hg.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/monotone.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/p4.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/convert/subversion.py: error importing module: <ImportError> No
> module named 'cPickle' (line 6)
> +  hgext/convert/transport.py: error importing module: <ImportError> No
> module named 'svn.client' (line 21)
> +  hgext/eol.py: error importing: <TypeError> encode() argument 1 must be
> str, not bytes (error at encoding.py:*) (glob)
> +  hgext/extdiff.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/factotum.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/fetch.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/fsmonitor/state.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/fsmonitor/watchmanclient.py: error importing: <TypeError>
> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/gpg.py: error importing: <TypeError> encode() argument 1 must be
> str, not bytes (error at encoding.py:*) (glob)
> +  hgext/graphlog.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/hgk.py: error importing: <TypeError> encode() argument 1 must be
> str, not bytes (error at encoding.py:*) (glob)
> +  hgext/highlight/highlight.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/histedit.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/keyword.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/basestore.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/lfcommands.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/lfutil.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/localstore.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/overrides.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
>    hgext/largefiles/proto.py: error importing: <ImportError> No module
> named 'httplib' (error at httppeer.py:*) (glob)
> -  hgext/largefiles/remotestore.py: error importing: <SyntaxError> invalid
> syntax (bundle*.py, line *) (error at wireproto.py:*) (glob)
> -  hgext/largefiles/reposetup.py: error importing: <AttributeError> 'dict'
> object has no attribute 'iteritems' (error at revset.py:*) (glob)
> +  hgext/largefiles/remotestore.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/largefiles/reposetup.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
>    hgext/largefiles/uisetup.py: error importing module: <SyntaxError>
> invalid syntax (archival.py, line *) (line *) (glob)
> -  hgext/largefiles/wirestore.py: error importing module: <ImportError> No
> module named 'lfutil' (line *) (glob)
> -  hgext/mq.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/notify.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/pager.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/patchbomb.py: error importing: <AttributeError> 'dict' object has
> no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/purge.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/rebase.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/record.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/relink.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/schemes.py: error importing: <AttributeError> 'dict' object has
> no attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/share.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/shelve.py: error importing module: <SyntaxError> invalid syntax
> (bundle*.py, line *) (line *) (glob)
> -  hgext/strip.py: error importing: <AttributeError> 'dict' object has no
> attribute 'iteritems' (error at revset.py:*) (glob)
> -  hgext/transplant.py: error importing: <SyntaxError> invalid syntax
> (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> +  hgext/largefiles/wirestore.py: error importing module: <ImportError> No
> module named 'lfutil' (line 8)
> +  hgext/mq.py: error importing: <TypeError> encode() argument 1 must be
> str, not bytes (error at encoding.py:*) (glob)
> +  hgext/notify.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/pager.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/patchbomb.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/purge.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/rebase.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/record.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/relink.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/schemes.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/share.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/shelve.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/strip.py: error importing: <TypeError> encode() argument 1 must
> be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/transplant.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/win32mbcs.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  hgext/win32text.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
>    mercurial/archival.py: invalid syntax: invalid syntax (<unknown>, line
> *) (glob)
> -  mercurial/branchmap.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> +  mercurial/bookmarks.py: error importing: <TypeError> encode() argument
> 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/branchmap.py: error importing: <TypeError> encode() argument
> 1 must be str, not bytes (error at encoding.py:*) (glob)
>    mercurial/bundle*.py: invalid syntax: invalid syntax (<unknown>, line
> *) (glob)
> -  mercurial/bundlerepo.py: error importing module: <SyntaxError> invalid
> syntax (bundle*.py, line *) (line *) (glob)
> -  mercurial/changegroup.py: error importing: <AttributeError> 'dict'
> object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/changelog.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/cmdutil.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> +  mercurial/bundlerepo.py: error importing: <TypeError> encode() argument
> 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/byterange.py: error importing: <TypeError> encode() argument
> 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/changegroup.py: error importing: <TypeError> encode()
> argument 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/changelog.py: error importing: <TypeError> encode() argument
> 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/cmdutil.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
>    mercurial/commands.py: invalid syntax: invalid syntax (<unknown>, line
> *) (glob)
> -  mercurial/commandserver.py: error importing module: <ImportError> No
> module named 'SocketServer' (line *) (glob)
> -  mercurial/context.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/copies.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/crecord.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/dirstate.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/discovery.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/dispatch.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/exchange.py: error importing module: <SyntaxError> invalid
> syntax (bundle*.py, line *) (line *) (glob)
> -  mercurial/extensions.py: error importing: <AttributeError> 'dict'
> object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/filelog.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/filemerge.py: error importing: <ImportError> No module named
> 'cPickle' (error at formatter.py:*) (glob)
> -  mercurial/fileset.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/formatter.py: error importing module: <ImportError> No module
> named 'cPickle' (line *) (glob)
> -  mercurial/graphmod.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/help.py: error importing: <AttributeError> 'dict' object has
> no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/hg.py: error importing: <SyntaxError> invalid syntax
> (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
> -  mercurial/hgweb/common.py: error importing module: <ImportError> No
> module named 'BaseHTTPServer' (line *) (glob)
> -  mercurial/hgweb/hgweb_mod.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line *) (glob)
> -  mercurial/hgweb/hgwebdir_mod.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line *) (glob)
> -  mercurial/hgweb/protocol.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line *) (glob)
> -  mercurial/hgweb/request.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line *) (glob)
> -  mercurial/hgweb/server.py: error importing module: <ImportError> No
> module named 'BaseHTTPServer' (line *) (glob)
> -  mercurial/hgweb/webcommands.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line *) (glob)
> -  mercurial/hgweb/webutil.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line *) (glob)
> -  mercurial/hgweb/wsgicgi.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line *) (glob)
> -  mercurial/hook.py: error importing: <AttributeError> 'dict' object has
> no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/httpconnection.py: error importing: <ImportError> No module
> named 'rfc822' (error at __init__.py:*) (glob)
> -  mercurial/httppeer.py: error importing module: <ImportError> No module
> named 'httplib' (line *) (glob)
> -  mercurial/keepalive.py: error importing module: <ImportError> No module
> named 'httplib' (line *) (glob)
> -  mercurial/localrepo.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/mail.py: error importing module: <AttributeError> module
> 'email' has no attribute 'Header' (line *) (glob)
> -  mercurial/manifest.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/merge.py: error importing: <AttributeError> 'dict' object has
> no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/namespaces.py: error importing: <AttributeError> 'dict'
> object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/patch.py: error importing: <AttributeError> 'dict' object has
> no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/pure/mpatch.py: error importing module: <ImportError> cannot
> import name 'pycompat' (line *) (glob)
> -  mercurial/pure/parsers.py: error importing module: <ImportError> No
> module named 'mercurial.pure.node' (line *) (glob)
> +  mercurial/commandserver.py: error importing module: <ImportError> No
> module named 'SocketServer' (line 10)
> +  mercurial/config.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/context.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/copies.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/crecord.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/dagparser.py: error importing: <TypeError> encode() argument
> 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/dagutil.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/destutil.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/dirstate.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/discovery.py: error importing: <TypeError> encode() argument
> 1 must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/dispatch.py: error importing: <TypeError> encode() argument 1
> must be str, not bytes (error at encoding.py:*) (glob)
> +  mercurial/exchange.py: error importing: <TypeError> getattr():
> attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/extensions.py: error importing: <TypeError> getattr():
> attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/fancyopts.py: error importing: <TypeError> getattr():
> attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/filelog.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at i18n.py:*) (glob)
> +  mercurial/filemerge.py: error importing: <TypeError> getattr():
> attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/fileset.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at i18n.py:*) (glob)
> +  mercurial/formatter.py: error importing module: <ImportError> No module
> named 'cPickle' (line 10)
> +  mercurial/graphmod.py: error importing: <TypeError> getattr():
> attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/hbisect.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at i18n.py:*) (glob)
> +  mercurial/help.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at i18n.py:*) (glob)
> +  mercurial/hg.py: error importing: <TypeError> getattr(): attribute name
> must be string (error at i18n.py:*) (glob)
> +  mercurial/hgweb/common.py: error importing module: <ImportError> No
> module named 'BaseHTTPServer' (line 11)
> +  mercurial/hgweb/hgweb_mod.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line 14)
> +  mercurial/hgweb/hgwebdir_mod.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line 15)
> +  mercurial/hgweb/protocol.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line 13)
> +  mercurial/hgweb/request.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line 15)
> +  mercurial/hgweb/server.py: error importing module: <ImportError> No
> module named 'BaseHTTPServer' (line 11)
> +  mercurial/hgweb/webcommands.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line 16)
> +  mercurial/hgweb/webutil.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line 16)
> +  mercurial/hgweb/wsgicgi.py: error importing module: <SystemError>
> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import
> (line 16)
> +  mercurial/hook.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at i18n.py:*) (glob)
> +  mercurial/httpconnection.py: error importing: <TypeError> getattr():
> attribute name must be string (error at i18n.py:*) (glob)
> +  mercurial/httppeer.py: error importing module: <ImportError> No module
> named 'httplib' (line 12)
> +  mercurial/keepalive.py: error importing module: <ImportError> No module
> named 'httplib' (line 113)
> +  mercurial/localrepo.py: error importing: <TypeError> '_fields_' must be
> a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/lock.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/mail.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/manifest.py: error importing: <TypeError> getattr():
> attribute name must be string (error at pycompat.py:*) (glob)
> +  mercurial/match.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/mdiff.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at pycompat.py:*) (glob)
> +  mercurial/merge.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/minirst.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/namespaces.py: error importing: <TypeError> '_fields_' must
> be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/obsolete.py: error importing: <TypeError> getattr():
> attribute name must be string (error at pycompat.py:*) (glob)
> +  mercurial/patch.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/pathutil.py: error importing: <TypeError> '_fields_' must be
> a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/peer.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/pure/mpatch.py: error importing module: <ImportError> cannot
> import name 'pycompat' (line 12)
> +  mercurial/pure/parsers.py: error importing module: <ImportError> No
> module named 'mercurial.pure.node' (line 13)
> +  mercurial/pushkey.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/pvec.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/registrar.py: error importing: <TypeError> '_fields_' must be
> a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
>    mercurial/repair.py: error importing module: <SyntaxError> invalid
> syntax (bundle*.py, line *) (line *) (glob)
> -  mercurial/revlog.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/revset.py: error importing module: <AttributeError> 'dict'
> object has no attribute 'iteritems' (line *) (glob)
> -  mercurial/scmutil.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/scmwindows.py: error importing module: <ImportError> No
> module named '_winreg' (line *) (glob)
> -  mercurial/simplemerge.py: error importing: <AttributeError> 'dict'
> object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/sshpeer.py: error importing: <SyntaxError> invalid syntax
> (bundle*.py, line *) (error at wireproto.py:*) (glob)
> -  mercurial/sshserver.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/statichttprepo.py: error importing: <AttributeError> 'dict'
> object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/store.py: error importing: <AttributeError> 'dict' object has
> no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/streamclone.py: error importing: <AttributeError> 'dict'
> object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/subrepo.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/templatefilters.py: error importing: <AttributeError> 'dict'
> object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/templatekw.py: error importing: <AttributeError> 'dict'
> object has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/templater.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/ui.py: error importing: <ImportError> No module named
> 'cPickle' (error at formatter.py:*) (glob)
> -  mercurial/unionrepo.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/url.py: error importing module: <ImportError> No module named
> 'httplib' (line *) (glob)
> -  mercurial/verify.py: error importing: <AttributeError> 'dict' object
> has no attribute 'iteritems' (error at revset.py:*) (glob)
> -  mercurial/win*.py: error importing module: <ImportError> No module
> named 'msvcrt' (line *) (glob)
> -  mercurial/windows.py: error importing module: <ImportError> No module
> named '_winreg' (line *) (glob)
> +  mercurial/repoview.py: error importing: <TypeError> '_fields_' must be
> a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/revlog.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/revset.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/scmposix.py: error importing: <TypeError> '_fields_' must be
> a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/scmutil.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/scmwindows.py: error importing module: <ImportError> No
> module named '_winreg' (line 3)
> +  mercurial/similar.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/simplemerge.py: error importing: <TypeError> '_fields_' must
> be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/sshpeer.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/sshserver.py: error importing: <TypeError> '_fields_' must be
> a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/sslutil.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/statichttprepo.py: error importing: <TypeError> '_fields_'
> must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/store.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/streamclone.py: error importing: <TypeError> '_fields_' must
> be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/subrepo.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/tagmerge.py: error importing: <TypeError> '_fields_' must be
> a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/tags.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/templatefilters.py: error importing: <TypeError> '_fields_'
> must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/templatekw.py: error importing: <TypeError> '_fields_' must
> be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/templater.py: error importing: <TypeError> '_fields_' must be
> a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/transaction.py: error importing: <TypeError> '_fields_' must
> be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/ui.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/unionrepo.py: error importing: <TypeError> '_fields_' must be
> a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/url.py: error importing module: <ImportError> No module named
> 'httplib' (line 13)
> +  mercurial/util.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/verify.py: error importing: <TypeError> '_fields_' must be a
> sequence of (name, C type) pairs (error at osutil.py:*) (glob)
> +  mercurial/win32.py: error importing module: <ImportError> No module
> named 'msvcrt' (line 12)
> +  mercurial/windows.py: error importing module: <ImportError> No module
> named '_winreg' (line 10)
>    mercurial/wireproto.py: error importing module: <SyntaxError> invalid
> syntax (bundle*.py, line *) (line *) (glob)
>
>  #endif
>
Jun Wu - June 6, 2016, 8:45 p.m.
Right. I actually like this better than other solutions.

I mentioned the codec hack at the time I'm not aware of or fully understand
the module loader approach.

Excerpts from Gregory Szorc's message of 2016-06-06 12:29:25 -0700:
> I should probably add this to the commit message, but I chose this approach
> over a custom codec because it feels more robust and cleaner to me. With a
> custom codec:
> 
> * You need to declare the codec in the header of every .py file
> * When the transformation semantics change, we'd likely need to bump the
> codec name/version otherwise the cached .pyc will get used. This means
> updating every .py file whenever we change transformation logic. Yuck.
Yuya Nishihara - June 9, 2016, 2:49 p.m.
On Tue, 31 May 2016 22:52:58 -0700, Gregory Szorc wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc@gmail.com>
> # Date 1464759986 25200
> #      Tue May 31 22:46:26 2016 -0700
> # Node ID 867ebaa1ca956c76022655eb1f7a6f39da42b5a4
> # Parent  48b38b16a8f83ea98ebdf0b370f59fd90dc17935
> mercurial: implement a source transforming module loader on Python 3

I agree this approach will be less hurt, and it seems good choice to process
the code transformation at token level than AST level for simplicity.

> +    class hgpathentryfinder(importlib.abc.PathEntryFinder):
> +        """A sys.meta_path finder that uses a custom module loader."""

I'm not sure if this should be PathEntryFinder or MetaPathFinder. Python doc
says "meta path finder is a finder returned by a search of sys.meta_path,"
and we're using sys.meta_path.

https://docs.python.org/3/library/importlib.html#importlib.abc.MetaPathFinder
Augie Fackler - June 10, 2016, 3:53 a.m.
On Mon, Jun 06, 2016 at 08:44:18AM -0700, Martijn Pieters wrote:
> On 31 May 2016 at 22:52, Gregory Szorc <gregory.szorc@gmail.com> wrote:
> > # HG changeset patch
> > # User Gregory Szorc <gregory.szorc@gmail.com>
> > # Date 1464759986 25200
> > #      Tue May 31 22:46:26 2016 -0700
> > # Node ID 867ebaa1ca956c76022655eb1f7a6f39da42b5a4
> > # Parent  48b38b16a8f83ea98ebdf0b370f59fd90dc17935
> > mercurial: implement a source transforming module loader on Python 3

[snip]

> From a Python 3 tech perspective, this looks sound to me. I like
> hijacking the importer machinery for this over using a custom codec,
> nice!

Yeah, after a lot (really) of reflection, this seems like the least
awful thing, barring some sort of flag to annotate that allows
skipping revisions in a revset (so the invasive b'' prefixing required
could then be elided from annotate results.)

(I still think such a flag is a good idea, but am willing to not let
the perfect be the enemy of the not-awful.)

What's the status of this series? It looks like I expect a new version
to cope with some docstring encoding issues?

>
> --
> Martijn Pieters
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Pierre-Yves David - June 17, 2016, 4:56 p.m.
On 06/10/2016 05:53 AM, Augie Fackler wrote:
> On Mon, Jun 06, 2016 at 08:44:18AM -0700, Martijn Pieters wrote:
>> On 31 May 2016 at 22:52, Gregory Szorc <gregory.szorc@gmail.com> wrote:
>>> # HG changeset patch
>>> # User Gregory Szorc <gregory.szorc@gmail.com>
>>> # Date 1464759986 25200
>>> #      Tue May 31 22:46:26 2016 -0700
>>> # Node ID 867ebaa1ca956c76022655eb1f7a6f39da42b5a4
>>> # Parent  48b38b16a8f83ea98ebdf0b370f59fd90dc17935
>>> mercurial: implement a source transforming module loader on Python 3
> 
> [snip]
> 
>> From a Python 3 tech perspective, this looks sound to me. I like
>> hijacking the importer machinery for this over using a custom codec,
>> nice!
> 
> Yeah, after a lot (really) of reflection, this seems like the least
> awful thing, barring some sort of flag to annotate that allows
> skipping revisions in a revset (so the invasive b'' prefixing required
> could then be elided from annotate results.)
> 
> (I still think such a flag is a good idea, but am willing to not let
> the perfect be the enemy of the not-awful.)
> 
> What's the status of this series? It looks like I expect a new version
> to cope with some docstring encoding issues?

Same question here, what is the status of this?
there seems to be a consensus that this is an awful hack that solve a
massive problem the best way we currently can easily do.

As it seems like yuya spotted some issue, I'm dropping it from
patchwork, expecting a resend.

Cheers,
Gregory Szorc - June 25, 2016, 9:03 p.m.
On Fri, Jun 17, 2016 at 9:56 AM, Pierre-Yves David <
pierre-yves.david@ens-lyon.org> wrote:

> On 06/10/2016 05:53 AM, Augie Fackler wrote:
> > On Mon, Jun 06, 2016 at 08:44:18AM -0700, Martijn Pieters wrote:
> >> On 31 May 2016 at 22:52, Gregory Szorc <gregory.szorc@gmail.com> wrote:
> >>> # HG changeset patch
> >>> # User Gregory Szorc <gregory.szorc@gmail.com>
> >>> # Date 1464759986 25200
> >>> #      Tue May 31 22:46:26 2016 -0700
> >>> # Node ID 867ebaa1ca956c76022655eb1f7a6f39da42b5a4
> >>> # Parent  48b38b16a8f83ea98ebdf0b370f59fd90dc17935
> >>> mercurial: implement a source transforming module loader on Python 3
> >
> > [snip]
> >
> >> From a Python 3 tech perspective, this looks sound to me. I like
> >> hijacking the importer machinery for this over using a custom codec,
> >> nice!
> >
> > Yeah, after a lot (really) of reflection, this seems like the least
> > awful thing, barring some sort of flag to annotate that allows
> > skipping revisions in a revset (so the invasive b'' prefixing required
> > could then be elided from annotate results.)
> >
> > (I still think such a flag is a good idea, but am willing to not let
> > the perfect be the enemy of the not-awful.)
> >
> > What's the status of this series? It looks like I expect a new version
> > to cope with some docstring encoding issues?
>
> Same question here, what is the status of this?
>

My last 3 weeks have been really hectic and I haven't done much in the way
of coding. I'll patchbomb a V2 incorporating suggested improvements shortly.


> there seems to be a consensus that this is an awful hack that solve a
> massive problem the best way we currently can easily do.
>
> As it seems like yuya spotted some issue, I'm dropping it from
> patchwork, expecting a resend.
>
> Cheers,
>
> --
> Pierre-Yves David
>

Patch

diff --git a/contrib/check-py3-compat.py b/contrib/check-py3-compat.py
--- a/contrib/check-py3-compat.py
+++ b/contrib/check-py3-compat.py
@@ -56,17 +56,30 @@  def check_compat_py3(f):
     if f.startswith(('hgext/', 'mercurial/')) and not f.endswith('__init__.py'):
         assert f.endswith('.py')
         name = f.replace('/', '.')[:-3]
         with open(f, 'r') as fh:
             try:
                 imp.load_module(name, fh, '', ('py', 'r', imp.PY_SOURCE))
             except Exception as e:
                 exc_type, exc_value, tb = sys.exc_info()
-                frame = traceback.extract_tb(tb)[-1]
+                # We walk the stack and ignore frames from our custom importer,
+                # import mechanisms, and stdlib modules. This kinda/sorta
+                # emulates CPython behavior in import.c while also attempting
+                # to pin blame on a Mercurial file.
+                for frame in reversed(traceback.extract_tb(tb)):
+                    if frame.name == '_call_with_frames_removed':
+                        continue
+                    if 'importlib' in frame.filename:
+                        continue
+                    if 'mercurial/__init__.py' in frame.filename:
+                        continue
+                    if frame.filename.startswith(sys.prefix):
+                        continue
+                    break
 
                 if frame.filename:
                     filename = os.path.basename(frame.filename)
                     print('%s: error importing: <%s> %s (error at %s:%d)' % (
                           f, type(e).__name__, e, filename, frame.lineno))
                 else:
                     print('%s: error importing module: <%s> %s (line %d)' % (
                           f, type(e).__name__, e, frame.lineno))
diff --git a/mercurial/__init__.py b/mercurial/__init__.py
--- a/mercurial/__init__.py
+++ b/mercurial/__init__.py
@@ -116,14 +116,168 @@  class hgimporter(object):
             if not modinfo:
                 raise ImportError('could not find mercurial module %s' %
                                   name)
 
         mod = imp.load_module(name, *modinfo)
         sys.modules[name] = mod
         return mod
 
+# 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:
+    from . import pure
+    import importlib
+    import io
+    import token
+    import tokenize
+
+    class hgpathentryfinder(importlib.abc.PathEntryFinder):
+        """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.', 'hgext.')):
+                return None
+
+            # This assumes Python 3 doesn't support loading C modules.
+            if fullname in _dualmodules:
+                stem = fullname.split('.')[-1]
+                fullname = 'mercurial.pure.%s' % stem
+                target = pure
+                assert len(path) == 1
+                path = [os.path.join(path[0], 'pure')]
+
+            # Try to find the module using other registered finders.
+            spec = None
+            for finder in sys.meta_path:
+                if finder == self:
+                    continue
+
+                spec = finder.find_spec(fullname, path, target=target)
+                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
+
+            if fullname.startswith('mercurial.pure.'):
+                spec.name = spec.name.replace('.pure.', '.')
+
+            # TODO need to support loaders from alternate specs, like zip
+            # loaders.
+            spec.loader = hgloader(spec.name, spec.origin)
+            return spec
+
+    def replacetoken(t):
+        """Transform a source token from raw to Python 3.
+
+        This function is called for every lexical token found from
+        ``tokenize.tokenize()``. It allows the module loader to rewrite
+        tokens between source decoding and compilation.
+
+        REMEMBER TO BUMP ``BYTECODEHEADER`` WHEN CHANGING THIS FUNCTION.
+        """
+        # Convert most string literals to byte literals. String literals
+        # in Python 2 are bytes. String literals in Python 3 are unicode.
+        # Most strings in Mercurial are bytes and unicode strings are rare.
+        # Rather than rewrite all string literals to use ``b''`` to indicate
+        # byte strings, we apply this token transformer to insert the ``b``
+        # prefix nearly everywhere.
+        if t.type == token.STRING:
+            s = t.string
+
+            # If a docstring, keep it as a string literal.
+            if s[0:3] in ("'''", '"""'):
+                return t
+
+            if s[0] not in ("'", '"'):
+                return t
+
+            # String literal. Prefix to make a b'' string.
+            return tokenize.TokenInfo(t.type, 'b%s' % s, t.start, t.end, t.line)
+
+        return 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\x01'
+
+    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.
+            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(replacetoken(t) for t in tokens)
+            # 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, hgimporter) for x in sys.meta_path):
+if sys.version_info[0] >= 3:
+    _importercls = hgpathentryfinder
+else:
+    _importercls = hgimporter
+if not any(isinstance(x, _importercls) for x in sys.meta_path):
     # meta_path is used before any implicit finders and before sys.path.
-    sys.meta_path.insert(0, hgimporter())
+    sys.meta_path.insert(0, _importercls())
diff --git a/tests/test-check-py3-compat.t b/tests/test-check-py3-compat.t
--- a/tests/test-check-py3-compat.t
+++ b/tests/test-check-py3-compat.t
@@ -30,133 +30,164 @@ 
   tests/md5sum.py not using absolute_import
   tests/readlink.py not using absolute_import
   tests/run-tests.py not using absolute_import
   tests/test-demandimport.py not using absolute_import
 
 #if py3exe
   $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs $PYTHON3 contrib/check-py3-compat.py
   doc/hgmanpage.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
-  hgext/automv.py: error importing module: <SyntaxError> invalid syntax (commands.py, line *) (line *) (glob)
-  hgext/blackbox.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/bugzilla.py: error importing module: <ImportError> No module named 'urlparse' (line *) (glob)
-  hgext/censor.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/chgserver.py: error importing module: <ImportError> No module named 'SocketServer' (line *) (glob)
-  hgext/children.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/churn.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/clonebundles.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
+  hgext/acl.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/automv.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/blackbox.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/bugzilla.py: error importing module: <ImportError> No module named 'urlparse' (line 284)
+  hgext/censor.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/chgserver.py: error importing module: <ImportError> No module named 'SocketServer' (line 43)
+  hgext/children.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/churn.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/clonebundles.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
   hgext/color.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
-  hgext/convert/bzr.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
-  hgext/convert/common.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
-  hgext/convert/convcmd.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
-  hgext/convert/cvs.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
-  hgext/convert/cvsps.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
-  hgext/convert/darcs.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
-  hgext/convert/filemap.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
-  hgext/convert/git.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
-  hgext/convert/gnuarch.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
-  hgext/convert/hg.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/convert/monotone.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
-  hgext/convert/p*.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
-  hgext/convert/subversion.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
-  hgext/convert/transport.py: error importing module: <ImportError> No module named 'svn.client' (line *) (glob)
-  hgext/eol.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/extdiff.py: error importing module: <SyntaxError> invalid syntax (archival.py, line *) (line *) (glob)
-  hgext/factotum.py: error importing: <ImportError> No module named 'rfc822' (error at __init__.py:*) (glob)
-  hgext/fetch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/fsmonitor/watchmanclient.py: error importing module: <SystemError> Parent module 'hgext.fsmonitor' not loaded, cannot perform relative import (line *) (glob)
-  hgext/gpg.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/graphlog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/hgk.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/histedit.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
-  hgext/keyword.py: error importing: <ImportError> No module named 'BaseHTTPServer' (error at common.py:*) (glob)
-  hgext/largefiles/basestore.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
-  hgext/largefiles/lfcommands.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
-  hgext/largefiles/lfutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/largefiles/localstore.py: error importing module: <ImportError> No module named 'lfutil' (line *) (glob)
-  hgext/largefiles/overrides.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
+  hgext/convert/bzr.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/convert/common.py: error importing module: <ImportError> No module named 'cPickle' (line 10)
+  hgext/convert/convcmd.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/convert/cvs.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/convert/cvsps.py: error importing module: <ImportError> No module named 'cPickle' (line 9)
+  hgext/convert/darcs.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/convert/filemap.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/convert/git.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/convert/gnuarch.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/convert/hg.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/convert/monotone.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/convert/p4.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/convert/subversion.py: error importing module: <ImportError> No module named 'cPickle' (line 6)
+  hgext/convert/transport.py: error importing module: <ImportError> No module named 'svn.client' (line 21)
+  hgext/eol.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/extdiff.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/factotum.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/fetch.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/fsmonitor/state.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/fsmonitor/watchmanclient.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/gpg.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/graphlog.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/hgk.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/highlight/highlight.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/histedit.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/keyword.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/largefiles/basestore.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/largefiles/lfcommands.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/largefiles/lfutil.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/largefiles/localstore.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/largefiles/overrides.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
   hgext/largefiles/proto.py: error importing: <ImportError> No module named 'httplib' (error at httppeer.py:*) (glob)
-  hgext/largefiles/remotestore.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at wireproto.py:*) (glob)
-  hgext/largefiles/reposetup.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
+  hgext/largefiles/remotestore.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/largefiles/reposetup.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
   hgext/largefiles/uisetup.py: error importing module: <SyntaxError> invalid syntax (archival.py, line *) (line *) (glob)
-  hgext/largefiles/wirestore.py: error importing module: <ImportError> No module named 'lfutil' (line *) (glob)
-  hgext/mq.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/notify.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/pager.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/patchbomb.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/purge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/rebase.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/record.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/relink.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/schemes.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/share.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/shelve.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
-  hgext/strip.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  hgext/transplant.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
+  hgext/largefiles/wirestore.py: error importing module: <ImportError> No module named 'lfutil' (line 8)
+  hgext/mq.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/notify.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/pager.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/patchbomb.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/purge.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/rebase.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/record.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/relink.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/schemes.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/share.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/shelve.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/strip.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/transplant.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/win32mbcs.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  hgext/win32text.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
   mercurial/archival.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
-  mercurial/branchmap.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
+  mercurial/bookmarks.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/branchmap.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
   mercurial/bundle*.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
-  mercurial/bundlerepo.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
-  mercurial/changegroup.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/changelog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/cmdutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
+  mercurial/bundlerepo.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/byterange.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/changegroup.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/changelog.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/cmdutil.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
   mercurial/commands.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
-  mercurial/commandserver.py: error importing module: <ImportError> No module named 'SocketServer' (line *) (glob)
-  mercurial/context.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/copies.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/crecord.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/dirstate.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/discovery.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/dispatch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/exchange.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
-  mercurial/extensions.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/filelog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/filemerge.py: error importing: <ImportError> No module named 'cPickle' (error at formatter.py:*) (glob)
-  mercurial/fileset.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/formatter.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
-  mercurial/graphmod.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/help.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/hg.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
-  mercurial/hgweb/common.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line *) (glob)
-  mercurial/hgweb/hgweb_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
-  mercurial/hgweb/hgwebdir_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
-  mercurial/hgweb/protocol.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
-  mercurial/hgweb/request.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
-  mercurial/hgweb/server.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line *) (glob)
-  mercurial/hgweb/webcommands.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
-  mercurial/hgweb/webutil.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
-  mercurial/hgweb/wsgicgi.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
-  mercurial/hook.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/httpconnection.py: error importing: <ImportError> No module named 'rfc822' (error at __init__.py:*) (glob)
-  mercurial/httppeer.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
-  mercurial/keepalive.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
-  mercurial/localrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/mail.py: error importing module: <AttributeError> module 'email' has no attribute 'Header' (line *) (glob)
-  mercurial/manifest.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/merge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/namespaces.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/patch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/pure/mpatch.py: error importing module: <ImportError> cannot import name 'pycompat' (line *) (glob)
-  mercurial/pure/parsers.py: error importing module: <ImportError> No module named 'mercurial.pure.node' (line *) (glob)
+  mercurial/commandserver.py: error importing module: <ImportError> No module named 'SocketServer' (line 10)
+  mercurial/config.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/context.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/copies.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/crecord.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/dagparser.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/dagutil.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/destutil.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/dirstate.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/discovery.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/dispatch.py: error importing: <TypeError> encode() argument 1 must be str, not bytes (error at encoding.py:*) (glob)
+  mercurial/exchange.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/extensions.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/fancyopts.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/filelog.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/filemerge.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/fileset.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/formatter.py: error importing module: <ImportError> No module named 'cPickle' (line 10)
+  mercurial/graphmod.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/hbisect.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/help.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/hg.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/hgweb/common.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line 11)
+  mercurial/hgweb/hgweb_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 14)
+  mercurial/hgweb/hgwebdir_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 15)
+  mercurial/hgweb/protocol.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 13)
+  mercurial/hgweb/request.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 15)
+  mercurial/hgweb/server.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line 11)
+  mercurial/hgweb/webcommands.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 16)
+  mercurial/hgweb/webutil.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 16)
+  mercurial/hgweb/wsgicgi.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line 16)
+  mercurial/hook.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/httpconnection.py: error importing: <TypeError> getattr(): attribute name must be string (error at i18n.py:*) (glob)
+  mercurial/httppeer.py: error importing module: <ImportError> No module named 'httplib' (line 12)
+  mercurial/keepalive.py: error importing module: <ImportError> No module named 'httplib' (line 113)
+  mercurial/localrepo.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/lock.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/mail.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/manifest.py: error importing: <TypeError> getattr(): attribute name must be string (error at pycompat.py:*) (glob)
+  mercurial/match.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/mdiff.py: error importing: <TypeError> getattr(): attribute name must be string (error at pycompat.py:*) (glob)
+  mercurial/merge.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/minirst.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/namespaces.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/obsolete.py: error importing: <TypeError> getattr(): attribute name must be string (error at pycompat.py:*) (glob)
+  mercurial/patch.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/pathutil.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/peer.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/pure/mpatch.py: error importing module: <ImportError> cannot import name 'pycompat' (line 12)
+  mercurial/pure/parsers.py: error importing module: <ImportError> No module named 'mercurial.pure.node' (line 13)
+  mercurial/pushkey.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/pvec.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/registrar.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
   mercurial/repair.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
-  mercurial/revlog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/revset.py: error importing module: <AttributeError> 'dict' object has no attribute 'iteritems' (line *) (glob)
-  mercurial/scmutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/scmwindows.py: error importing module: <ImportError> No module named '_winreg' (line *) (glob)
-  mercurial/simplemerge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/sshpeer.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at wireproto.py:*) (glob)
-  mercurial/sshserver.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/statichttprepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/store.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/streamclone.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/subrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/templatefilters.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/templatekw.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/templater.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/ui.py: error importing: <ImportError> No module named 'cPickle' (error at formatter.py:*) (glob)
-  mercurial/unionrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/url.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
-  mercurial/verify.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
-  mercurial/win*.py: error importing module: <ImportError> No module named 'msvcrt' (line *) (glob)
-  mercurial/windows.py: error importing module: <ImportError> No module named '_winreg' (line *) (glob)
+  mercurial/repoview.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/revlog.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/revset.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/scmposix.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/scmutil.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/scmwindows.py: error importing module: <ImportError> No module named '_winreg' (line 3)
+  mercurial/similar.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/simplemerge.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/sshpeer.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/sshserver.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/sslutil.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/statichttprepo.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/store.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/streamclone.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/subrepo.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/tagmerge.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/tags.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/templatefilters.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/templatekw.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/templater.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/transaction.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/ui.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/unionrepo.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/url.py: error importing module: <ImportError> No module named 'httplib' (line 13)
+  mercurial/util.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/verify.py: error importing: <TypeError> '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob)
+  mercurial/win32.py: error importing module: <ImportError> No module named 'msvcrt' (line 12)
+  mercurial/windows.py: error importing module: <ImportError> No module named '_winreg' (line 10)
   mercurial/wireproto.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
 
 #endif