[PATCH 1 of 6] mercurial: implement a source transforming module loader on Python 3
Gregory Szorc
gregory.szorc at gmail.com
Mon Jun 6 15:29:25 EDT 2016
On Tue, May 31, 2016 at 10:52 PM, Gregory Szorc <gregory.szorc at gmail.com>
wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc at 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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.mercurial-scm.org/pipermail/mercurial-devel/attachments/20160606/96226eeb/attachment.html>
More information about the Mercurial-devel
mailing list