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