1 """Miscellaneous stuff for Coverage.""" |
1 """Miscellaneous stuff for Coverage.""" |
2 |
2 |
3 def nice_pair(pair): |
3 def nice_pair(pair): |
4 """Make a nice string representation of a pair of numbers. |
4 """Make a nice string representation of a pair of numbers. |
5 |
5 |
6 If the numbers are equal, just return the number, otherwise return the pair |
6 If the numbers are equal, just return the number, otherwise return the pair |
7 with a dash between them, indicating the range. |
7 with a dash between them, indicating the range. |
8 |
8 |
9 """ |
9 """ |
10 start, end = pair |
10 start, end = pair |
11 if start == end: |
11 if start == end: |
12 return "%d" % start |
12 return "%d" % start |
13 else: |
13 else: |
18 """Nicely format a list of line numbers. |
18 """Nicely format a list of line numbers. |
19 |
19 |
20 Format a list of line numbers for printing by coalescing groups of lines as |
20 Format a list of line numbers for printing by coalescing groups of lines as |
21 long as the lines represent consecutive statements. This will coalesce |
21 long as the lines represent consecutive statements. This will coalesce |
22 even if there are gaps between statements. |
22 even if there are gaps between statements. |
23 |
23 |
24 For example, if `statements` is [1,2,3,4,5,10,11,12,13,14] and |
24 For example, if `statements` is [1,2,3,4,5,10,11,12,13,14] and |
25 `lines` is [1,2,5,10,11,13,14] then the result will be "1-2, 5-11, 13-14". |
25 `lines` is [1,2,5,10,11,13,14] then the result will be "1-2, 5-11, 13-14". |
26 |
26 |
27 """ |
27 """ |
28 pairs = [] |
28 pairs = [] |
29 i = 0 |
29 i = 0 |
30 j = 0 |
30 j = 0 |
31 start = None |
31 start = None |
32 pairs = [] |
|
33 while i < len(statements) and j < len(lines): |
32 while i < len(statements) and j < len(lines): |
34 if statements[i] == lines[j]: |
33 if statements[i] == lines[j]: |
35 if start == None: |
34 if start == None: |
36 start = lines[j] |
35 start = lines[j] |
37 end = lines[j] |
36 end = lines[j] |
38 j = j + 1 |
37 j += 1 |
39 elif start: |
38 elif start: |
40 pairs.append((start, end)) |
39 pairs.append((start, end)) |
41 start = None |
40 start = None |
42 i = i + 1 |
41 i += 1 |
43 if start: |
42 if start: |
44 pairs.append((start, end)) |
43 pairs.append((start, end)) |
45 ret = ', '.join(map(nice_pair, pairs)) |
44 ret = ', '.join(map(nice_pair, pairs)) |
46 return ret |
45 return ret |
47 |
46 |
48 |
47 |
|
48 def expensive(fn): |
|
49 """A decorator to cache the result of an expensive operation. |
|
50 |
|
51 Only applies to methods with no arguments. |
|
52 |
|
53 """ |
|
54 attr = "_cache_" + fn.__name__ |
|
55 def _wrapped(self): |
|
56 """Inner fn that checks the cache.""" |
|
57 if not hasattr(self, attr): |
|
58 setattr(self, attr, fn(self)) |
|
59 return getattr(self, attr) |
|
60 return _wrapped |
|
61 |
|
62 |
49 class CoverageException(Exception): |
63 class CoverageException(Exception): |
50 """An exception specific to Coverage.""" |
64 """An exception specific to Coverage.""" |
51 pass |
65 pass |
|
66 |
|
67 class NoSource(CoverageException): |
|
68 """Used to indicate we couldn't find the source for a module.""" |
|
69 pass |