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 @@ -61,7 +61,20 @@ def check_compat_py3(f): 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) diff --git a/mercurial/__init__.py b/mercurial/__init__.py --- a/mercurial/__init__.py +++ b/mercurial/__init__.py @@ -121,9 +121,238 @@ class hgimporter(object): 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.MetaPathFinder): + """A sys.meta_path finder that uses a custom module loader.""" + def find_spec(self, fullname, path, target=None): + # Only handle Mercurial-related modules. + if not fullname.startswith(('mercurial.', 'hgext.', 'hgext3rd.')): + 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 replacetokens(tokens): + """Transform a stream of tokens from raw to Python 3. + + It is called by the custom module loading machinery to rewrite + source/tokens between source decoding and compilation. + + Returns a generator of possibly rewritten tokens. + + The input token list may be mutated as part of processing. However, + its changes do not necessarily match the output token stream. + + REMEMBER TO CHANGE ``BYTECODEHEADER`` WHEN CHANGING THIS FUNCTION + OR CACHED FILES WON'T GET INVALIDATED PROPERLY. + """ + for i, t in enumerate(tokens): + # 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 + + # Preserve docstrings as string literals. This is inconsistent + # with regular unprefixed strings. However, the + # "from __future__" parsing (which allows a module docstring to + # exist before it) doesn't properly handle the docstring if it + # is b''' prefixed, leading to a SyntaxError. We leave all + # docstrings as unprefixed to avoid this. This means Mercurial + # components touching docstrings need to handle unicode, + # unfortunately. + if s[0:3] in ("'''", '"""'): + yield t + continue + + # If the first character isn't a quote, it is likely a string + # prefixing character (such as 'b', 'u', or 'r'. Ignore. + if s[0] not in ("'", '"'): + yield t + continue + + # String literal. Prefix to make a b'' string. + yield tokenize.TokenInfo(t.type, 'b%s' % s, t.start, t.end, + t.line) + continue + + try: + nexttoken = tokens[i + 1] + except IndexError: + nexttoken = None + + try: + prevtoken = tokens[i - 1] + except IndexError: + prevtoken = None + + # This looks like a function call. + if (t.type == token.NAME and nexttoken and + nexttoken.type == token.OP and nexttoken.string == '('): + fn = t.string + + # *attr() builtins don't accept byte strings to 2nd argument. + # Rewrite the token to include the unicode literal prefix so + # the string transformer above doesn't add the byte prefix. + if fn in ('getattr', 'setattr', 'hasattr', 'safehasattr'): + try: + # (NAME, 'getattr') + # (OP, '(') + # (NAME, 'foo') + # (OP, ',') + # (NAME|STRING, foo) + st = tokens[i + 4] + if (st.type == token.STRING and + st.string[0] in ("'", '"')): + rt = tokenize.TokenInfo(st.type, 'u%s' % st.string, + st.start, st.end, st.line) + tokens[i + 4] = rt + except IndexError: + pass + + # .encode() and .decode() on str/bytes/unicode don't accept + # byte strings on Python 3. Rewrite the token to include the + # unicode literal prefix so the string transformer above doesn't + # add the byte prefix. + if (fn in ('encode', 'decode') and + prevtoken.type == token.OP and prevtoken.string == '.'): + # (OP, '.') + # (NAME, 'encode') + # (OP, '(') + # (STRING, 'utf-8') + # (OP, ')') + try: + st = tokens[i + 2] + if (st.type == token.STRING and + st.string[0] in ("'", '"')): + rt = tokenize.TokenInfo(st.type, 'u%s' % st.string, + st.start, st.end, st.line) + tokens[i + 2] = rt + except IndexError: + pass + + # Emit unmodified token. + yield t + + # Header to add to bytecode files. This MUST be changed when + # ``replacetoken`` or any mechanism that changes semantics of module + # loading is changed. Otherwise cached bytecode may get loaded without + # the new transformation mechanisms applied. + BYTECODEHEADER = b'HG\x00\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``. That is a literal + ``HG`` with 2 binary bytes indicating the transformation version. + """ + def get_data(self, path): + data = super(hgloader, self).get_data(path) + + if not path.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)): + return data + + # There should be a header indicating the Mercurial transformation + # version. If it doesn't exist or doesn't match the current version, + # we raise an OSError because that is what + # ``SourceFileLoader.get_code()`` expects when loading bytecode + # paths to indicate the cached file is "bad." + if data[0:2] != b'HG': + raise OSError('no hg header') + if data[0:4] != BYTECODEHEADER: + raise OSError('hg header version mismatch') + + return data[4:] + + def set_data(self, path, data, *args, **kwargs): + if path.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)): + data = BYTECODEHEADER + data + + return super(hgloader, self).set_data(path, data, *args, **kwargs) + + def source_to_code(self, data, path): + """Perform token transformation before compilation.""" + buf = io.BytesIO(data) + tokens = tokenize.tokenize(buf.readline) + data = tokenize.untokenize(replacetokens(list(tokens))) + # 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 @@ -15,85 +15,101 @@ #if py3exe $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs $PYTHON3 contrib/check-py3-compat.py doc/hgmanpage.py: invalid syntax: invalid syntax (, line *) (glob) - hgext/automv.py: error importing module: invalid syntax (commands.py, line *) (line *) (glob) - hgext/blackbox.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/bugzilla.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/censor.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/chgserver.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/children.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/churn.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/clonebundles.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) + hgext/acl.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/automv.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/blackbox.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/bugzilla.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/censor.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/chgserver.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/children.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/churn.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/clonebundles.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) hgext/color.py: invalid syntax: invalid syntax (, line *) (glob) - hgext/convert/bzr.py: error importing module: Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob) - hgext/convert/convcmd.py: error importing: invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob) - hgext/convert/cvs.py: error importing module: Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob) - hgext/convert/cvsps.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/convert/darcs.py: error importing module: Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob) - hgext/convert/filemap.py: error importing module: Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob) - hgext/convert/git.py: error importing module: Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob) - hgext/convert/gnuarch.py: error importing module: Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob) - hgext/convert/hg.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/convert/monotone.py: error importing module: Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob) - hgext/convert/p*.py: error importing module: Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob) - hgext/convert/subversion.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) + hgext/convert/bzr.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/common.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/convcmd.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/cvs.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/cvsps.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/darcs.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/filemap.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/git.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/gnuarch.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/hg.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/monotone.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/p4.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/convert/subversion.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) hgext/convert/transport.py: error importing module: No module named 'svn.client' (line *) (glob) - hgext/eol.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/extdiff.py: error importing module: invalid syntax (archival.py, line *) (line *) (glob) - hgext/factotum.py: error importing: No module named 'rfc822' (error at __init__.py:*) (glob) - hgext/fetch.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/fsmonitor/watchmanclient.py: error importing module: Parent module 'hgext.fsmonitor' not loaded, cannot perform relative import (line *) (glob) - hgext/gpg.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/graphlog.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/hgk.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/histedit.py: error importing module: invalid syntax (bundle*.py, line *) (line *) (glob) - hgext/keyword.py: error importing: No module named 'BaseHTTPServer' (error at common.py:*) (glob) - hgext/largefiles/basestore.py: error importing module: Parent module 'hgext.largefiles' not loaded, cannot perform relative import (line *) (glob) - hgext/largefiles/lfcommands.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/largefiles/lfutil.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/largefiles/localstore.py: error importing module: Parent module 'hgext.largefiles' not loaded, cannot perform relative import (line *) (glob) - hgext/largefiles/overrides.py: error importing module: invalid syntax (archival.py, line *) (line *) (glob) - hgext/largefiles/proto.py: error importing: invalid syntax (bundle2.py, line *) (error at httppeer.py:*) (glob) - hgext/largefiles/remotestore.py: error importing: invalid syntax (bundle*.py, line *) (error at wireproto.py:*) (glob) - hgext/largefiles/reposetup.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/largefiles/storefactory.py: error importing: invalid syntax (bundle2.py, line *) (error at bundlerepo.py:*) (glob) - hgext/largefiles/uisetup.py: error importing: No module named 'BaseHTTPServer' (error at common.py:*) (glob) + hgext/eol.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/extdiff.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/factotum.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/fetch.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/fsmonitor/state.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/fsmonitor/watchmanclient.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/gpg.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/graphlog.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/hgk.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/highlight/highlight.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/histedit.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/journal.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/keyword.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/largefiles/basestore.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/largefiles/lfcommands.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/largefiles/lfutil.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/largefiles/localstore.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/largefiles/overrides.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/largefiles/proto.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/largefiles/remotestore.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/largefiles/reposetup.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/largefiles/storefactory.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/largefiles/uisetup.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) hgext/largefiles/wirestore.py: error importing module: Parent module 'hgext.largefiles' not loaded, cannot perform relative import (line *) (glob) - hgext/mq.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/notify.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/pager.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/patchbomb.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/purge.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/rebase.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/record.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/relink.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/schemes.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/share.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/shelve.py: error importing module: invalid syntax (bundle*.py, line *) (line *) (glob) - hgext/strip.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - hgext/transplant.py: error importing: invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob) + hgext/mq.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/notify.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/pager.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/patchbomb.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/purge.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/rebase.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/record.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/relink.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/schemes.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/share.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/shelve.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/strip.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/transplant.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/win32mbcs.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + hgext/win32text.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) mercurial/archival.py: invalid syntax: invalid syntax (, line *) (glob) - mercurial/branchmap.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/bundle*.py: invalid syntax: invalid syntax (, line *) (glob) - mercurial/bundlerepo.py: error importing module: invalid syntax (bundle*.py, line *) (line *) (glob) - mercurial/changegroup.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/changelog.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/cmdutil.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) + mercurial/bookmarks.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/branchmap.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/bundle2.py: invalid syntax: invalid syntax (, line *) (glob) + mercurial/bundlerepo.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/byterange.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/changegroup.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/changelog.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/cmdutil.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) mercurial/commands.py: invalid syntax: invalid syntax (, line *) (glob) - mercurial/context.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/copies.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/crecord.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/dirstate.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/discovery.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/dispatch.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/exchange.py: error importing module: invalid syntax (bundle*.py, line *) (line *) (glob) - mercurial/extensions.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/filelog.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/filemerge.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/fileset.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/formatter.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/graphmod.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/help.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/hg.py: error importing: invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob) + mercurial/commandserver.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/config.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/context.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/copies.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/crecord.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/dagparser.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/dagutil.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/destutil.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/dirstate.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/discovery.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/dispatch.py: error importing: str expected, not bytes (error at encoding.py:*) (glob) + mercurial/exchange.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/extensions.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/fancyopts.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/filelog.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/filemerge.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/fileset.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/formatter.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/graphmod.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/hbisect.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/help.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/hg.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) mercurial/hgweb/common.py: error importing module: No module named 'BaseHTTPServer' (line *) (glob) mercurial/hgweb/hgweb_mod.py: error importing module: Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob) mercurial/hgweb/hgwebdir_mod.py: error importing module: Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob) @@ -103,39 +119,57 @@ mercurial/hgweb/webcommands.py: error importing module: Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob) mercurial/hgweb/webutil.py: error importing module: Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob) mercurial/hgweb/wsgicgi.py: error importing module: Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob) - mercurial/hook.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/httpconnection.py: error importing: No module named 'rfc822' (error at __init__.py:*) (glob) - mercurial/httppeer.py: error importing module: invalid syntax (bundle2.py, line *) (line *) (glob) - mercurial/keepalive.py: error importing module: No module named 'thread' (line *) (glob) - mercurial/localrepo.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/mail.py: error importing module: module 'email' has no attribute 'Header' (line *) (glob) - mercurial/manifest.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/merge.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/namespaces.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/patch.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) + mercurial/hook.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/httpconnection.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/httppeer.py: error importing: str expected, not bytes (error at i18n.py:*) (glob) + mercurial/keepalive.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/localrepo.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/lock.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/mail.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/manifest.py: error importing: getattr(): attribute name must be string (error at pycompat.py:*) (glob) + mercurial/match.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/mdiff.py: error importing: getattr(): attribute name must be string (error at pycompat.py:*) (glob) + mercurial/merge.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/minirst.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/namespaces.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/obsolete.py: error importing: getattr(): attribute name must be string (error at pycompat.py:*) (glob) + mercurial/patch.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/pathutil.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/peer.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) mercurial/pure/mpatch.py: error importing module: cannot import name 'pycompat' (line *) (glob) mercurial/pure/parsers.py: error importing module: No module named 'mercurial.pure.node' (line *) (glob) - mercurial/repair.py: error importing module: invalid syntax (bundle*.py, line *) (line *) (glob) - mercurial/revlog.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/revset.py: error importing module: 'dict' object has no attribute 'iteritems' (line *) (glob) - mercurial/scmutil.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) + mercurial/pushkey.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/pvec.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/registrar.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/repair.py: error importing module: invalid syntax (bundle2.py, line *) (line *) (glob) + mercurial/repoview.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/revlog.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/revset.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/scmposix.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/scmutil.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) mercurial/scmwindows.py: error importing module: No module named '_winreg' (line *) (glob) - mercurial/simplemerge.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/sshpeer.py: error importing: invalid syntax (bundle*.py, line *) (error at wireproto.py:*) (glob) - mercurial/sshserver.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/statichttprepo.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/store.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/streamclone.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/subrepo.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/templatefilters.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/templatekw.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/templater.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/ui.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/unionrepo.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/url.py: error importing: No module named 'rfc822' (error at __init__.py:*) (glob) - mercurial/verify.py: error importing: 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob) - mercurial/win*.py: error importing module: No module named 'msvcrt' (line *) (glob) + mercurial/similar.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/simplemerge.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/sshpeer.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/sshserver.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/sslutil.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/statichttprepo.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/store.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/streamclone.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/subrepo.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/tagmerge.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/tags.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/templatefilters.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/templatekw.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/templater.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/transaction.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/ui.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/unionrepo.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/url.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/util.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/verify.py: error importing: '_fields_' must be a sequence of (name, C type) pairs (error at osutil.py:*) (glob) + mercurial/win32.py: error importing module: No module named 'msvcrt' (line *) (glob) mercurial/windows.py: error importing module: No module named '_winreg' (line *) (glob) - mercurial/wireproto.py: error importing module: invalid syntax (bundle*.py, line *) (line *) (glob) + mercurial/wireproto.py: error importing module: invalid syntax (bundle2.py, line *) (line *) (glob) #endif