|
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 |
1 """Add things to old Pythons so I can pretend they are newer.""" |
4 """Add things to old Pythons so I can pretend they are newer.""" |
2 |
5 |
3 # This file does lots of tricky stuff, so disable a bunch of lintisms. |
6 # This file does lots of tricky stuff, so disable a bunch of pylint warnings. |
4 # pylint: disable=F0401,W0611,W0622 |
7 # pylint: disable=redefined-builtin |
5 # F0401: Unable to import blah |
8 # pylint: disable=unused-import |
6 # W0611: Unused import blah |
9 # pylint: disable=no-name-in-module |
7 # W0622: Redefining built-in blah |
|
8 |
10 |
9 import os, re, sys |
11 import sys |
10 |
12 |
11 # Python 2.3 doesn't have `set` |
13 from coverage import env |
12 try: |
|
13 set = set # new in 2.4 |
|
14 except NameError: |
|
15 from sets import Set as set |
|
16 |
14 |
17 # Python 2.3 doesn't have `sorted`. |
|
18 try: |
|
19 sorted = sorted |
|
20 except NameError: |
|
21 def sorted(iterable): |
|
22 """A 2.3-compatible implementation of `sorted`.""" |
|
23 lst = list(iterable) |
|
24 lst.sort() |
|
25 return lst |
|
26 |
15 |
27 # Python 2.3 doesn't have `reversed`. |
16 # Pythons 2 and 3 differ on where to get StringIO. |
28 try: |
|
29 reversed = reversed |
|
30 except NameError: |
|
31 def reversed(iterable): |
|
32 """A 2.3-compatible implementation of `reversed`.""" |
|
33 lst = list(iterable) |
|
34 return lst[::-1] |
|
35 |
|
36 # rpartition is new in 2.5 |
|
37 try: |
|
38 "".rpartition |
|
39 except AttributeError: |
|
40 def rpartition(s, sep): |
|
41 """Implement s.rpartition(sep) for old Pythons.""" |
|
42 i = s.rfind(sep) |
|
43 if i == -1: |
|
44 return ('', '', s) |
|
45 else: |
|
46 return (s[:i], sep, s[i+len(sep):]) |
|
47 else: |
|
48 def rpartition(s, sep): |
|
49 """A common interface for new Pythons.""" |
|
50 return s.rpartition(sep) |
|
51 |
|
52 # Pythons 2 and 3 differ on where to get StringIO |
|
53 try: |
17 try: |
54 from cStringIO import StringIO |
18 from cStringIO import StringIO |
55 BytesIO = StringIO |
|
56 except ImportError: |
19 except ImportError: |
57 from io import StringIO, BytesIO |
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 |
58 |
27 |
59 # What's a string called? |
28 # What's a string called? |
60 try: |
29 try: |
61 string_class = basestring |
30 string_class = basestring |
62 except NameError: |
31 except NameError: |
63 string_class = str |
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 |
64 |
39 |
65 # Where do pickles come from? |
40 # Where do pickles come from? |
66 try: |
41 try: |
67 import cPickle as pickle |
42 import cPickle as pickle |
68 except ImportError: |
43 except ImportError: |
84 else: |
59 else: |
85 def iitems(d): |
60 def iitems(d): |
86 """Produce the items from dict `d`.""" |
61 """Produce the items from dict `d`.""" |
87 return d.iteritems() |
62 return d.iteritems() |
88 |
63 |
89 # Exec is a statement in Py2, a function in Py3 |
64 # Getting the `next` function from an iterator is different in 2 and 3. |
90 if sys.version_info >= (3, 0): |
65 try: |
91 def exec_code_object(code, global_map): |
66 iter([]).next |
92 """A wrapper around exec().""" |
67 except AttributeError: |
93 exec(code, global_map) |
68 def iternext(seq): |
|
69 """Get the `next` function for iterating over `seq`.""" |
|
70 return iter(seq).__next__ |
94 else: |
71 else: |
95 # OK, this is pretty gross. In Py2, exec was a statement, but that will |
72 def iternext(seq): |
96 # be a syntax error if we try to put it in a Py3 file, even if it is never |
73 """Get the `next` function for iterating over `seq`.""" |
97 # executed. So hide it inside an evaluated string literal instead. |
74 return iter(seq).next |
98 eval( |
|
99 compile( |
|
100 "def exec_code_object(code, global_map):\n" |
|
101 " exec code in global_map\n", |
|
102 "<exec_function>", "exec" |
|
103 ) |
|
104 ) |
|
105 |
|
106 # Reading Python source and interpreting the coding comment is a big deal. |
|
107 if sys.version_info >= (3, 0): |
|
108 # Python 3.2 provides `tokenize.open`, the best way to open source files. |
|
109 import tokenize |
|
110 try: |
|
111 open_source = tokenize.open # pylint: disable=E1101 |
|
112 except AttributeError: |
|
113 from io import TextIOWrapper |
|
114 detect_encoding = tokenize.detect_encoding # pylint: disable=E1101 |
|
115 # Copied from the 3.2 stdlib: |
|
116 def open_source(fname): |
|
117 """Open a file in read only mode using the encoding detected by |
|
118 detect_encoding(). |
|
119 """ |
|
120 buffer = open(fname, 'rb') |
|
121 encoding, _ = detect_encoding(buffer.readline) |
|
122 buffer.seek(0) |
|
123 text = TextIOWrapper(buffer, encoding, line_buffering=True) |
|
124 text.mode = 'r' |
|
125 return text |
|
126 else: |
|
127 def open_source(fname): |
|
128 """Open a source file the best way.""" |
|
129 return open(fname, "rU") |
|
130 |
|
131 |
75 |
132 # Python 3.x is picky about bytes and strings, so provide methods to |
76 # Python 3.x is picky about bytes and strings, so provide methods to |
133 # get them right, and make them no-ops in 2.x |
77 # get them right, and make them no-ops in 2.x |
134 if sys.version_info >= (3, 0): |
78 if env.PY3: |
135 def to_bytes(s): |
79 def to_bytes(s): |
136 """Convert string `s` to bytes.""" |
80 """Convert string `s` to bytes.""" |
137 return s.encode('utf8') |
81 return s.encode('utf8') |
138 |
|
139 def to_string(b): |
|
140 """Convert bytes `b` to a string.""" |
|
141 return b.decode('utf8') |
|
142 |
82 |
143 def binary_bytes(byte_values): |
83 def binary_bytes(byte_values): |
144 """Produce a byte string with the ints from `byte_values`.""" |
84 """Produce a byte string with the ints from `byte_values`.""" |
145 return bytes(byte_values) |
85 return bytes(byte_values) |
146 |
86 |
148 """Turn an element of a bytes object into an int.""" |
88 """Turn an element of a bytes object into an int.""" |
149 return byte_value |
89 return byte_value |
150 |
90 |
151 def bytes_to_ints(bytes_value): |
91 def bytes_to_ints(bytes_value): |
152 """Turn a bytes object into a sequence of ints.""" |
92 """Turn a bytes object into a sequence of ints.""" |
153 # In Py3, iterating bytes gives ints. |
93 # In Python 3, iterating bytes gives ints. |
154 return bytes_value |
94 return bytes_value |
155 |
95 |
156 else: |
96 else: |
157 def to_bytes(s): |
97 def to_bytes(s): |
158 """Convert string `s` to bytes (no-op in 2.x).""" |
98 """Convert string `s` to bytes (no-op in 2.x).""" |
159 return s |
99 return s |
160 |
100 |
161 def to_string(b): |
|
162 """Convert bytes `b` to a string (no-op in 2.x).""" |
|
163 return b |
|
164 |
|
165 def binary_bytes(byte_values): |
101 def binary_bytes(byte_values): |
166 """Produce a byte string with the ints from `byte_values`.""" |
102 """Produce a byte string with the ints from `byte_values`.""" |
167 return "".join([chr(b) for b in byte_values]) |
103 return "".join(chr(b) for b in byte_values) |
168 |
104 |
169 def byte_to_int(byte_value): |
105 def byte_to_int(byte_value): |
170 """Turn an element of a bytes object into an int.""" |
106 """Turn an element of a bytes object into an int.""" |
171 return ord(byte_value) |
107 return ord(byte_value) |
172 |
108 |
173 def bytes_to_ints(bytes_value): |
109 def bytes_to_ints(bytes_value): |
174 """Turn a bytes object into a sequence of ints.""" |
110 """Turn a bytes object into a sequence of ints.""" |
175 for byte in bytes_value: |
111 for byte in bytes_value: |
176 yield ord(byte) |
112 yield ord(byte) |
177 |
113 |
178 # Md5 is available in different places. |
114 |
179 try: |
115 try: |
180 import hashlib |
116 # In Python 2.x, the builtins were in __builtin__ |
181 md5 = hashlib.md5 |
117 BUILTINS = sys.modules['__builtin__'] |
|
118 except KeyError: |
|
119 # In Python 3.x, they're in builtins |
|
120 BUILTINS = sys.modules['builtins'] |
|
121 |
|
122 |
|
123 # imp was deprecated in Python 3.3 |
|
124 try: |
|
125 import importlib |
|
126 import importlib.util |
|
127 imp = None |
182 except ImportError: |
128 except ImportError: |
183 import md5 |
129 importlib = None |
184 md5 = md5.new |
|
185 |
130 |
186 # |
131 # We only want to use importlib if it has everything we need. |
187 # eflag: FileType = Python2 |
132 try: |
|
133 importlib_util_find_spec = importlib.util.find_spec |
|
134 except Exception: |
|
135 import imp |
|
136 importlib_util_find_spec = None |
|
137 |
|
138 # What is the .pyc magic number for this version of Python? |
|
139 try: |
|
140 PYC_MAGIC_NUMBER = importlib.util.MAGIC_NUMBER |
|
141 except AttributeError: |
|
142 PYC_MAGIC_NUMBER = imp.get_magic() |
|
143 |
|
144 |
|
145 def import_local_file(modname): |
|
146 """Import a local file as a module. |
|
147 |
|
148 Opens a file in the current directory named `modname`.py, imports it |
|
149 as `modname`, and returns the module object. |
|
150 |
|
151 """ |
|
152 try: |
|
153 from importlib.machinery import SourceFileLoader |
|
154 except ImportError: |
|
155 SourceFileLoader = None |
|
156 |
|
157 modfile = modname + '.py' |
|
158 if SourceFileLoader: |
|
159 mod = SourceFileLoader(modname, modfile).load_module() |
|
160 else: |
|
161 for suff in imp.get_suffixes(): # pragma: part covered |
|
162 if suff[0] == '.py': |
|
163 break |
|
164 |
|
165 with open(modfile, 'r') as f: |
|
166 # pylint: disable=undefined-loop-variable |
|
167 mod = imp.load_module(modname, f, modfile, suff) |
|
168 |
|
169 return mod |