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

Side by Side Diff: third_party/coverage/misc.py

Issue 63813002: Add python coverage 3.7 to depot tools. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 7 years, 1 month 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
« no previous file with comments | « third_party/coverage/htmlfiles/style.css ('k') | third_party/coverage/parser.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 """Miscellaneous stuff for Coverage."""
2
3 import errno
4 import inspect
5 import os
6 import sys
7
8 from coverage.backward import md5, sorted # pylint: disable=W0622
9 from coverage.backward import string_class, to_bytes
10
11
12 def nice_pair(pair):
13 """Make a nice string representation of a pair of numbers.
14
15 If the numbers are equal, just return the number, otherwise return the pair
16 with a dash between them, indicating the range.
17
18 """
19 start, end = pair
20 if start == end:
21 return "%d" % start
22 else:
23 return "%d-%d" % (start, end)
24
25
26 def format_lines(statements, lines):
27 """Nicely format a list of line numbers.
28
29 Format a list of line numbers for printing by coalescing groups of lines as
30 long as the lines represent consecutive statements. This will coalesce
31 even if there are gaps between statements.
32
33 For example, if `statements` is [1,2,3,4,5,10,11,12,13,14] and
34 `lines` is [1,2,5,10,11,13,14] then the result will be "1-2, 5-11, 13-14".
35
36 """
37 pairs = []
38 i = 0
39 j = 0
40 start = None
41 while i < len(statements) and j < len(lines):
42 if statements[i] == lines[j]:
43 if start == None:
44 start = lines[j]
45 end = lines[j]
46 j += 1
47 elif start:
48 pairs.append((start, end))
49 start = None
50 i += 1
51 if start:
52 pairs.append((start, end))
53 ret = ', '.join(map(nice_pair, pairs))
54 return ret
55
56
57 def short_stack():
58 """Return a string summarizing the call stack."""
59 stack = inspect.stack()[:0:-1]
60 return "\n".join(["%30s : %s @%d" % (t[3],t[1],t[2]) for t in stack])
61
62
63 def expensive(fn):
64 """A decorator to cache the result of an expensive operation.
65
66 Only applies to methods with no arguments.
67
68 """
69 attr = "_cache_" + fn.__name__
70 def _wrapped(self):
71 """Inner fn that checks the cache."""
72 if not hasattr(self, attr):
73 setattr(self, attr, fn(self))
74 return getattr(self, attr)
75 return _wrapped
76
77
78 def bool_or_none(b):
79 """Return bool(b), but preserve None."""
80 if b is None:
81 return None
82 else:
83 return bool(b)
84
85
86 def join_regex(regexes):
87 """Combine a list of regexes into one that matches any of them."""
88 if len(regexes) > 1:
89 return "|".join(["(%s)" % r for r in regexes])
90 elif regexes:
91 return regexes[0]
92 else:
93 return ""
94
95
96 def file_be_gone(path):
97 """Remove a file, and don't get annoyed if it doesn't exist."""
98 try:
99 os.remove(path)
100 except OSError:
101 _, e, _ = sys.exc_info()
102 if e.errno != errno.ENOENT:
103 raise
104
105
106 class Hasher(object):
107 """Hashes Python data into md5."""
108 def __init__(self):
109 self.md5 = md5()
110
111 def update(self, v):
112 """Add `v` to the hash, recursively if needed."""
113 self.md5.update(to_bytes(str(type(v))))
114 if isinstance(v, string_class):
115 self.md5.update(to_bytes(v))
116 elif isinstance(v, (int, float)):
117 self.update(str(v))
118 elif isinstance(v, (tuple, list)):
119 for e in v:
120 self.update(e)
121 elif isinstance(v, dict):
122 keys = v.keys()
123 for k in sorted(keys):
124 self.update(k)
125 self.update(v[k])
126 else:
127 for k in dir(v):
128 if k.startswith('__'):
129 continue
130 a = getattr(v, k)
131 if inspect.isroutine(a):
132 continue
133 self.update(k)
134 self.update(a)
135
136 def digest(self):
137 """Retrieve the digest of the hash."""
138 return self.md5.digest()
139
140
141 class CoverageException(Exception):
142 """An exception specific to Coverage."""
143 pass
144
145 class NoSource(CoverageException):
146 """We couldn't find the source for a module."""
147 pass
148
149 class NoCode(NoSource):
150 """We couldn't find any code at all."""
151 pass
152
153 class NotPython(CoverageException):
154 """A source file turned out not to be parsable Python."""
155 pass
156
157 class ExceptionDuringRun(CoverageException):
158 """An exception happened while running customer code.
159
160 Construct it with three arguments, the values from `sys.exc_info`.
161
162 """
163 pass
OLDNEW
« no previous file with comments | « third_party/coverage/htmlfiles/style.css ('k') | third_party/coverage/parser.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698