Home | History | Annotate | Download | only in coverage
      1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
      2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
      3 
      4 """Add things to old Pythons so I can pretend they are newer."""
      5 
      6 # This file does lots of tricky stuff, so disable a bunch of pylint warnings.
      7 # pylint: disable=redefined-builtin
      8 # pylint: disable=unused-import
      9 # pylint: disable=no-name-in-module
     10 
     11 import sys
     12 
     13 from coverage import env
     14 
     15 
     16 # Pythons 2 and 3 differ on where to get StringIO.
     17 try:
     18     from cStringIO import StringIO
     19 except ImportError:
     20     from io import StringIO
     21 
     22 # In py3, ConfigParser was renamed to the more-standard configparser
     23 try:
     24     import configparser
     25 except ImportError:
     26     import ConfigParser as configparser
     27 
     28 # What's a string called?
     29 try:
     30     string_class = basestring
     31 except NameError:
     32     string_class = str
     33 
     34 # What's a Unicode string called?
     35 try:
     36     unicode_class = unicode
     37 except NameError:
     38     unicode_class = str
     39 
     40 # Where do pickles come from?
     41 try:
     42     import cPickle as pickle
     43 except ImportError:
     44     import pickle
     45 
     46 # range or xrange?
     47 try:
     48     range = xrange
     49 except NameError:
     50     range = range
     51 
     52 # shlex.quote is new, but there's an undocumented implementation in "pipes",
     53 # who knew!?
     54 try:
     55     from shlex import quote as shlex_quote
     56 except ImportError:
     57     # Useful function, available under a different (undocumented) name
     58     # in Python versions earlier than 3.3.
     59     from pipes import quote as shlex_quote
     60 
     61 # A function to iterate listlessly over a dict's items.
     62 try:
     63     {}.iteritems
     64 except AttributeError:
     65     def iitems(d):
     66         """Produce the items from dict `d`."""
     67         return d.items()
     68 else:
     69     def iitems(d):
     70         """Produce the items from dict `d`."""
     71         return d.iteritems()
     72 
     73 # Getting the `next` function from an iterator is different in 2 and 3.
     74 try:
     75     iter([]).next
     76 except AttributeError:
     77     def iternext(seq):
     78         """Get the `next` function for iterating over `seq`."""
     79         return iter(seq).__next__
     80 else:
     81     def iternext(seq):
     82         """Get the `next` function for iterating over `seq`."""
     83         return iter(seq).next
     84 
     85 # Python 3.x is picky about bytes and strings, so provide methods to
     86 # get them right, and make them no-ops in 2.x
     87 if env.PY3:
     88     def to_bytes(s):
     89         """Convert string `s` to bytes."""
     90         return s.encode('utf8')
     91 
     92     def binary_bytes(byte_values):
     93         """Produce a byte string with the ints from `byte_values`."""
     94         return bytes(byte_values)
     95 
     96     def byte_to_int(byte_value):
     97         """Turn an element of a bytes object into an int."""
     98         return byte_value
     99 
    100     def bytes_to_ints(bytes_value):
    101         """Turn a bytes object into a sequence of ints."""
    102         # In Python 3, iterating bytes gives ints.
    103         return bytes_value
    104 
    105 else:
    106     def to_bytes(s):
    107         """Convert string `s` to bytes (no-op in 2.x)."""
    108         return s
    109 
    110     def binary_bytes(byte_values):
    111         """Produce a byte string with the ints from `byte_values`."""
    112         return "".join(chr(b) for b in byte_values)
    113 
    114     def byte_to_int(byte_value):
    115         """Turn an element of a bytes object into an int."""
    116         return ord(byte_value)
    117 
    118     def bytes_to_ints(bytes_value):
    119         """Turn a bytes object into a sequence of ints."""
    120         for byte in bytes_value:
    121             yield ord(byte)
    122 
    123 
    124 try:
    125     # In Python 2.x, the builtins were in __builtin__
    126     BUILTINS = sys.modules['__builtin__']
    127 except KeyError:
    128     # In Python 3.x, they're in builtins
    129     BUILTINS = sys.modules['builtins']
    130 
    131 
    132 # imp was deprecated in Python 3.3
    133 try:
    134     import importlib
    135     import importlib.util
    136     imp = None
    137 except ImportError:
    138     importlib = None
    139 
    140 # We only want to use importlib if it has everything we need.
    141 try:
    142     importlib_util_find_spec = importlib.util.find_spec
    143 except Exception:
    144     import imp
    145     importlib_util_find_spec = None
    146 
    147 # What is the .pyc magic number for this version of Python?
    148 try:
    149     PYC_MAGIC_NUMBER = importlib.util.MAGIC_NUMBER
    150 except AttributeError:
    151     PYC_MAGIC_NUMBER = imp.get_magic()
    152 
    153 
    154 def import_local_file(modname, modfile=None):
    155     """Import a local file as a module.
    156 
    157     Opens a file in the current directory named `modname`.py, imports it
    158     as `modname`, and returns the module object.  `modfile` is the file to
    159     import if it isn't in the current directory.
    160 
    161     """
    162     try:
    163         from importlib.machinery import SourceFileLoader
    164     except ImportError:
    165         SourceFileLoader = None
    166 
    167     if modfile is None:
    168         modfile = modname + '.py'
    169     if SourceFileLoader:
    170         mod = SourceFileLoader(modname, modfile).load_module()
    171     else:
    172         for suff in imp.get_suffixes():                 # pragma: part covered
    173             if suff[0] == '.py':
    174                 break
    175 
    176         with open(modfile, 'r') as f:
    177             # pylint: disable=undefined-loop-variable
    178             mod = imp.load_module(modname, f, modfile, suff)
    179 
    180     return mod
    181