--- a/DebugClients/Python3/coverage/backward.py Sun Oct 04 13:35:09 2015 +0200 +++ b/DebugClients/Python3/coverage/backward.py Sun Oct 04 22:37:56 2015 +0200 @@ -1,60 +1,29 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt + """Add things to old Pythons so I can pretend they are newer.""" -# This file does lots of tricky stuff, so disable a bunch of lintisms. -# pylint: disable=F0401,W0611,W0622 -# F0401: Unable to import blah -# W0611: Unused import blah -# W0622: Redefining built-in blah - -import os, re, sys - -# Python 2.3 doesn't have `set` -try: - set = set # new in 2.4 -except NameError: - from sets import Set as set - -# Python 2.3 doesn't have `sorted`. -try: - sorted = sorted -except NameError: - def sorted(iterable): - """A 2.3-compatible implementation of `sorted`.""" - lst = list(iterable) - lst.sort() - return lst +# This file does lots of tricky stuff, so disable a bunch of pylint warnings. +# pylint: disable=redefined-builtin +# pylint: disable=unused-import +# pylint: disable=no-name-in-module -# Python 2.3 doesn't have `reversed`. -try: - reversed = reversed -except NameError: - def reversed(iterable): - """A 2.3-compatible implementation of `reversed`.""" - lst = list(iterable) - return lst[::-1] +import sys -# rpartition is new in 2.5 -try: - "".rpartition -except AttributeError: - def rpartition(s, sep): - """Implement s.rpartition(sep) for old Pythons.""" - i = s.rfind(sep) - if i == -1: - return ('', '', s) - else: - return (s[:i], sep, s[i+len(sep):]) -else: - def rpartition(s, sep): - """A common interface for new Pythons.""" - return s.rpartition(sep) +from coverage import env -# Pythons 2 and 3 differ on where to get StringIO + +# Pythons 2 and 3 differ on where to get StringIO. try: from cStringIO import StringIO - BytesIO = StringIO except ImportError: - from io import StringIO, BytesIO + from io import StringIO + +# In py3, ConfigParser was renamed to the more-standard configparser +try: + import configparser +except ImportError: + import ConfigParser as configparser # What's a string called? try: @@ -62,6 +31,12 @@ except NameError: string_class = str +# What's a Unicode string called? +try: + unicode_class = unicode +except NameError: + unicode_class = str + # Where do pickles come from? try: import cPickle as pickle @@ -86,60 +61,25 @@ """Produce the items from dict `d`.""" return d.iteritems() -# Exec is a statement in Py2, a function in Py3 -if sys.version_info >= (3, 0): - def exec_code_object(code, global_map): - """A wrapper around exec().""" - exec(code, global_map) +# Getting the `next` function from an iterator is different in 2 and 3. +try: + iter([]).next +except AttributeError: + def iternext(seq): + """Get the `next` function for iterating over `seq`.""" + return iter(seq).__next__ else: - # OK, this is pretty gross. In Py2, exec was a statement, but that will - # be a syntax error if we try to put it in a Py3 file, even if it is never - # executed. So hide it inside an evaluated string literal instead. - eval( - compile( - "def exec_code_object(code, global_map):\n" - " exec code in global_map\n", - "<exec_function>", "exec" - ) - ) - -# Reading Python source and interpreting the coding comment is a big deal. -if sys.version_info >= (3, 0): - # Python 3.2 provides `tokenize.open`, the best way to open source files. - import tokenize - try: - open_source = tokenize.open # pylint: disable=E1101 - except AttributeError: - from io import TextIOWrapper - detect_encoding = tokenize.detect_encoding # pylint: disable=E1101 - # Copied from the 3.2 stdlib: - def open_source(fname): - """Open a file in read only mode using the encoding detected by - detect_encoding(). - """ - buffer = open(fname, 'rb') - encoding, _ = detect_encoding(buffer.readline) - buffer.seek(0) - text = TextIOWrapper(buffer, encoding, line_buffering=True) - text.mode = 'r' - return text -else: - def open_source(fname): - """Open a source file the best way.""" - return open(fname, "rU") - + def iternext(seq): + """Get the `next` function for iterating over `seq`.""" + return iter(seq).next # Python 3.x is picky about bytes and strings, so provide methods to # get them right, and make them no-ops in 2.x -if sys.version_info >= (3, 0): +if env.PY3: def to_bytes(s): """Convert string `s` to bytes.""" return s.encode('utf8') - def to_string(b): - """Convert bytes `b` to a string.""" - return b.decode('utf8') - def binary_bytes(byte_values): """Produce a byte string with the ints from `byte_values`.""" return bytes(byte_values) @@ -150,7 +90,7 @@ def bytes_to_ints(bytes_value): """Turn a bytes object into a sequence of ints.""" - # In Py3, iterating bytes gives ints. + # In Python 3, iterating bytes gives ints. return bytes_value else: @@ -158,13 +98,9 @@ """Convert string `s` to bytes (no-op in 2.x).""" return s - def to_string(b): - """Convert bytes `b` to a string (no-op in 2.x).""" - return b - def binary_bytes(byte_values): """Produce a byte string with the ints from `byte_values`.""" - return "".join([chr(b) for b in byte_values]) + return "".join(chr(b) for b in byte_values) def byte_to_int(byte_value): """Turn an element of a bytes object into an int.""" @@ -175,10 +111,59 @@ for byte in bytes_value: yield ord(byte) -# Md5 is available in different places. + +try: + # In Python 2.x, the builtins were in __builtin__ + BUILTINS = sys.modules['__builtin__'] +except KeyError: + # In Python 3.x, they're in builtins + BUILTINS = sys.modules['builtins'] + + +# imp was deprecated in Python 3.3 +try: + import importlib + import importlib.util + imp = None +except ImportError: + importlib = None + +# We only want to use importlib if it has everything we need. +try: + importlib_util_find_spec = importlib.util.find_spec +except Exception: + import imp + importlib_util_find_spec = None + +# What is the .pyc magic number for this version of Python? try: - import hashlib - md5 = hashlib.md5 -except ImportError: - import md5 - md5 = md5.new + PYC_MAGIC_NUMBER = importlib.util.MAGIC_NUMBER +except AttributeError: + PYC_MAGIC_NUMBER = imp.get_magic() + + +def import_local_file(modname): + """Import a local file as a module. + + Opens a file in the current directory named `modname`.py, imports it + as `modname`, and returns the module object. + + """ + try: + from importlib.machinery import SourceFileLoader + except ImportError: + SourceFileLoader = None + + modfile = modname + '.py' + if SourceFileLoader: + mod = SourceFileLoader(modname, modfile).load_module() + else: + for suff in imp.get_suffixes(): # pragma: part covered + if suff[0] == '.py': + break + + with open(modfile, 'r') as f: + # pylint: disable=undefined-loop-variable + mod = imp.load_module(modname, f, modfile, suff) + + return mod