• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
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
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 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
105else:
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
124try:
125    # In Python 2.x, the builtins were in __builtin__
126    BUILTINS = sys.modules['__builtin__']
127except 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
133try:
134    import importlib
135    import importlib.util
136    imp = None
137except ImportError:
138    importlib = None
139
140# We only want to use importlib if it has everything we need.
141try:
142    importlib_util_find_spec = importlib.util.find_spec
143except Exception:
144    import imp
145    importlib_util_find_spec = None
146
147# What is the .pyc magic number for this version of Python?
148try:
149    PYC_MAGIC_NUMBER = importlib.util.MAGIC_NUMBER
150except AttributeError:
151    PYC_MAGIC_NUMBER = imp.get_magic()
152
153
154def 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