Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: third_party/coverage-3.6/coverage/data.py

Issue 14988009: First cut of testing infrastructure for recipes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: nitfixen Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 """Coverage data for Coverage."""
2
3 import os
4
5 from coverage.backward import iitems, pickle, sorted # pylint: disable=W0622
6 from coverage.files import PathAliases
7 from coverage.misc import file_be_gone
8
9
10 class CoverageData(object):
11 """Manages collected coverage data, including file storage.
12
13 The data file format is a pickled dict, with these keys:
14
15 * collector: a string identifying the collecting software
16
17 * lines: a dict mapping filenames to sorted lists of line numbers
18 executed:
19 { 'file1': [17,23,45], 'file2': [1,2,3], ... }
20
21 * arcs: a dict mapping filenames to sorted lists of line number pairs:
22 { 'file1': [(17,23), (17,25), (25,26)], ... }
23
24 """
25
26 def __init__(self, basename=None, collector=None):
27 """Create a CoverageData.
28
29 `basename` is the name of the file to use for storing data.
30
31 `collector` is a string describing the coverage measurement software.
32
33 """
34 self.collector = collector or 'unknown'
35
36 self.use_file = True
37
38 # Construct the filename that will be used for data file storage, if we
39 # ever do any file storage.
40 self.filename = basename or ".coverage"
41 self.filename = os.path.abspath(self.filename)
42
43 # A map from canonical Python source file name to a dictionary in
44 # which there's an entry for each line number that has been
45 # executed:
46 #
47 # {
48 # 'filename1.py': { 12: None, 47: None, ... },
49 # ...
50 # }
51 #
52 self.lines = {}
53
54 # A map from canonical Python source file name to a dictionary with an
55 # entry for each pair of line numbers forming an arc:
56 #
57 # {
58 # 'filename1.py': { (12,14): None, (47,48): None, ... },
59 # ...
60 # }
61 #
62 self.arcs = {}
63
64 def usefile(self, use_file=True):
65 """Set whether or not to use a disk file for data."""
66 self.use_file = use_file
67
68 def read(self):
69 """Read coverage data from the coverage data file (if it exists)."""
70 if self.use_file:
71 self.lines, self.arcs = self._read_file(self.filename)
72 else:
73 self.lines, self.arcs = {}, {}
74
75 def write(self, suffix=None):
76 """Write the collected coverage data to a file.
77
78 `suffix` is a suffix to append to the base file name. This can be used
79 for multiple or parallel execution, so that many coverage data files
80 can exist simultaneously. A dot will be used to join the base name and
81 the suffix.
82
83 """
84 if self.use_file:
85 filename = self.filename
86 if suffix:
87 filename += "." + suffix
88 self.write_file(filename)
89
90 def erase(self):
91 """Erase the data, both in this object, and from its file storage."""
92 if self.use_file:
93 if self.filename:
94 file_be_gone(self.filename)
95 self.lines = {}
96 self.arcs = {}
97
98 def line_data(self):
99 """Return the map from filenames to lists of line numbers executed."""
100 return dict(
101 [(f, sorted(lmap.keys())) for f, lmap in iitems(self.lines)]
102 )
103
104 def arc_data(self):
105 """Return the map from filenames to lists of line number pairs."""
106 return dict(
107 [(f, sorted(amap.keys())) for f, amap in iitems(self.arcs)]
108 )
109
110 def write_file(self, filename):
111 """Write the coverage data to `filename`."""
112
113 # Create the file data.
114 data = {}
115
116 data['lines'] = self.line_data()
117 arcs = self.arc_data()
118 if arcs:
119 data['arcs'] = arcs
120
121 if self.collector:
122 data['collector'] = self.collector
123
124 # Write the pickle to the file.
125 fdata = open(filename, 'wb')
126 try:
127 pickle.dump(data, fdata, 2)
128 finally:
129 fdata.close()
130
131 def read_file(self, filename):
132 """Read the coverage data from `filename`."""
133 self.lines, self.arcs = self._read_file(filename)
134
135 def raw_data(self, filename):
136 """Return the raw pickled data from `filename`."""
137 fdata = open(filename, 'rb')
138 try:
139 data = pickle.load(fdata)
140 finally:
141 fdata.close()
142 return data
143
144 def _read_file(self, filename):
145 """Return the stored coverage data from the given file.
146
147 Returns two values, suitable for assigning to `self.lines` and
148 `self.arcs`.
149
150 """
151 lines = {}
152 arcs = {}
153 try:
154 data = self.raw_data(filename)
155 if isinstance(data, dict):
156 # Unpack the 'lines' item.
157 lines = dict([
158 (f, dict.fromkeys(linenos, None))
159 for f, linenos in iitems(data.get('lines', {}))
160 ])
161 # Unpack the 'arcs' item.
162 arcs = dict([
163 (f, dict.fromkeys(arcpairs, None))
164 for f, arcpairs in iitems(data.get('arcs', {}))
165 ])
166 except Exception:
167 pass
168 return lines, arcs
169
170 def combine_parallel_data(self, aliases=None):
171 """Combine a number of data files together.
172
173 Treat `self.filename` as a file prefix, and combine the data from all
174 of the data files starting with that prefix plus a dot.
175
176 If `aliases` is provided, it's a `PathAliases` object that is used to
177 re-map paths to match the local machine's.
178
179 """
180 aliases = aliases or PathAliases()
181 data_dir, local = os.path.split(self.filename)
182 localdot = local + '.'
183 for f in os.listdir(data_dir or '.'):
184 if f.startswith(localdot):
185 full_path = os.path.join(data_dir, f)
186 new_lines, new_arcs = self._read_file(full_path)
187 for filename, file_data in iitems(new_lines):
188 filename = aliases.map(filename)
189 self.lines.setdefault(filename, {}).update(file_data)
190 for filename, file_data in iitems(new_arcs):
191 filename = aliases.map(filename)
192 self.arcs.setdefault(filename, {}).update(file_data)
193 if f != local:
194 os.remove(full_path)
195
196 def add_line_data(self, line_data):
197 """Add executed line data.
198
199 `line_data` is { filename: { lineno: None, ... }, ...}
200
201 """
202 for filename, linenos in iitems(line_data):
203 self.lines.setdefault(filename, {}).update(linenos)
204
205 def add_arc_data(self, arc_data):
206 """Add measured arc data.
207
208 `arc_data` is { filename: { (l1,l2): None, ... }, ...}
209
210 """
211 for filename, arcs in iitems(arc_data):
212 self.arcs.setdefault(filename, {}).update(arcs)
213
214 def touch_file(self, filename):
215 """Ensure that `filename` appears in the data, empty if needed."""
216 self.lines.setdefault(filename, {})
217
218 def measured_files(self):
219 """A list of all files that had been measured."""
220 return list(self.lines.keys())
221
222 def executed_lines(self, filename):
223 """A map containing all the line numbers executed in `filename`.
224
225 If `filename` hasn't been collected at all (because it wasn't executed)
226 then return an empty map.
227
228 """
229 return self.lines.get(filename) or {}
230
231 def executed_arcs(self, filename):
232 """A map containing all the arcs executed in `filename`."""
233 return self.arcs.get(filename) or {}
234
235 def add_to_hash(self, filename, hasher):
236 """Contribute `filename`'s data to the Md5Hash `hasher`."""
237 hasher.update(self.executed_lines(filename))
238 hasher.update(self.executed_arcs(filename))
239
240 def summary(self, fullpath=False):
241 """Return a dict summarizing the coverage data.
242
243 Keys are based on the filenames, and values are the number of executed
244 lines. If `fullpath` is true, then the keys are the full pathnames of
245 the files, otherwise they are the basenames of the files.
246
247 """
248 summ = {}
249 if fullpath:
250 filename_fn = lambda f: f
251 else:
252 filename_fn = os.path.basename
253 for filename, lines in iitems(self.lines):
254 summ[filename_fn(filename)] = len(lines)
255 return summ
256
257 def has_arcs(self):
258 """Does this data have arcs?"""
259 return bool(self.arcs)
260
261
262 if __name__ == '__main__':
263 # Ad-hoc: show the raw data in a data file.
264 import pprint, sys
265 covdata = CoverageData()
266 if sys.argv[1:]:
267 fname = sys.argv[1]
268 else:
269 fname = covdata.filename
270 pprint.pprint(covdata.raw_data(fname))
OLDNEW
« no previous file with comments | « third_party/coverage-3.6/coverage/control.py ('k') | third_party/coverage-3.6/coverage/execfile.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698