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# pxlint: disable=no-name-in-module 10 11import sys 12 13from coverage import env 14 15 16# Pythons 2 and 3 differ on where to get StringIO. 17try: 18 from cStringIO import StringIO 19except ImportError: 20 from io import StringIO 21 22# In py3, ConfigParser was renamed to the more-standard configparser 23try: 24 import configparser 25except ImportError: 26 import ConfigParser as configparser 27 28# What's a string called? 29try: 30 string_class = basestring 31except NameError: 32 string_class = str 33 34# What's a Unicode string called? 35try: 36 unicode_class = unicode 37except NameError: 38 unicode_class = str 39 40# Where do pickles come from? 41try: 42 import cPickle as pickle 43except ImportError: 44 import pickle 45 46# range or xrange? 47try: 48 range = xrange 49except NameError: 50 range = range # pylint: disable=redefined-variable-type 51 52# shlex.quote is new, but there's an undocumented implementation in "pipes", 53# who knew!? 54try: 55 from shlex import quote as shlex_quote 56except 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. 62try: 63 {}.iteritems 64except AttributeError: 65 def iitems(d): 66 """Produce the items from dict `d`.""" 67 return d.items() 68else: 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. 74try: 75 iter([]).next 76except AttributeError: 77 def iternext(seq): 78 """Get the `next` function for iterating over `seq`.""" 79 return iter(seq).__next__ 80else: 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 87if 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 bytes_to_ints(bytes_value): 97 """Turn a bytes object into a sequence of ints.""" 98 # In Python 3, iterating bytes gives ints. 99 return bytes_value 100 101else: 102 def to_bytes(s): 103 """Convert string `s` to bytes (no-op in 2.x).""" 104 return s 105 106 def binary_bytes(byte_values): 107 """Produce a byte string with the ints from `byte_values`.""" 108 return "".join(chr(b) for b in byte_values) 109 110 def bytes_to_ints(bytes_value): 111 """Turn a bytes object into a sequence of ints.""" 112 for byte in bytes_value: 113 yield ord(byte) 114 115 116try: 117 # In Python 2.x, the builtins were in __builtin__ 118 BUILTINS = sys.modules['__builtin__'] 119except KeyError: 120 # In Python 3.x, they're in builtins 121 BUILTINS = sys.modules['builtins'] 122 123 124# imp was deprecated in Python 3.3 125try: 126 import importlib 127 import importlib.util 128 imp = None 129except ImportError: 130 importlib = None 131 132# We only want to use importlib if it has everything we need. 133try: 134 importlib_util_find_spec = importlib.util.find_spec 135except Exception: 136 import imp 137 importlib_util_find_spec = None 138 139# What is the .pyc magic number for this version of Python? 140try: 141 PYC_MAGIC_NUMBER = importlib.util.MAGIC_NUMBER 142except AttributeError: 143 PYC_MAGIC_NUMBER = imp.get_magic() 144 145 146def import_local_file(modname, modfile=None): 147 """Import a local file as a module. 148 149 Opens a file in the current directory named `modname`.py, imports it 150 as `modname`, and returns the module object. `modfile` is the file to 151 import if it isn't in the current directory. 152 153 """ 154 try: 155 from importlib.machinery import SourceFileLoader 156 except ImportError: 157 SourceFileLoader = None 158 159 if modfile is None: 160 modfile = modname + '.py' 161 if SourceFileLoader: 162 mod = SourceFileLoader(modname, modfile).load_module() 163 else: 164 for suff in imp.get_suffixes(): # pragma: part covered 165 if suff[0] == '.py': 166 break 167 168 with open(modfile, 'r') as f: 169 # pylint: disable=undefined-loop-variable 170 mod = imp.load_module(modname, f, modfile, suff) 171 172 return mod 173