DebugClients/Python/coverage/backward.py

changeset 4489
d0d6e4ad31bd
parent 3499
f2d4b02c7e88
child 4491
0d8612e24fef
equal deleted inserted replaced
4481:456c58fc64b0 4489:d0d6e4ad31bd
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

eric ide

mercurial