36 return ISOLATED_MODULES[mod] |
36 return ISOLATED_MODULES[mod] |
37 |
37 |
38 os = isolate_module(os) |
38 os = isolate_module(os) |
39 |
39 |
40 |
40 |
|
41 def dummy_decorator_with_args(*args_unused, **kwargs_unused): |
|
42 """Dummy no-op implementation of a decorator with arguments.""" |
|
43 def _decorator(func): |
|
44 return func |
|
45 return _decorator |
|
46 |
|
47 |
41 # Use PyContracts for assertion testing on parameters and returns, but only if |
48 # Use PyContracts for assertion testing on parameters and returns, but only if |
42 # we are running our own test suite. |
49 # we are running our own test suite. |
43 if env.TESTING: |
50 if env.TESTING: |
44 from contracts import contract # pylint: disable=unused-import |
51 from contracts import contract # pylint: disable=unused-import |
45 from contracts import new_contract as raw_new_contract |
52 from contracts import new_contract as raw_new_contract |
55 |
62 |
56 # Define contract words that PyContract doesn't have. |
63 # Define contract words that PyContract doesn't have. |
57 new_contract('bytes', lambda v: isinstance(v, bytes)) |
64 new_contract('bytes', lambda v: isinstance(v, bytes)) |
58 if env.PY3: |
65 if env.PY3: |
59 new_contract('unicode', lambda v: isinstance(v, unicode_class)) |
66 new_contract('unicode', lambda v: isinstance(v, unicode_class)) |
60 else: # pragma: not covered |
67 |
61 # We aren't using real PyContracts, so just define a no-op decorator as a |
68 def one_of(argnames): |
62 # stunt double. |
69 """Ensure that only one of the argnames is non-None.""" |
63 def contract(**unused): |
70 def _decorator(func): |
64 """Dummy no-op implementation of `contract`.""" |
71 argnameset = set(name.strip() for name in argnames.split(",")) |
65 return lambda func: func |
72 def _wrapped(*args, **kwargs): |
|
73 vals = [kwargs.get(name) for name in argnameset] |
|
74 assert sum(val is not None for val in vals) == 1 |
|
75 return func(*args, **kwargs) |
|
76 return _wrapped |
|
77 return _decorator |
|
78 else: # pragma: not testing |
|
79 # We aren't using real PyContracts, so just define our decorators as |
|
80 # stunt-double no-ops. |
|
81 contract = dummy_decorator_with_args |
|
82 one_of = dummy_decorator_with_args |
66 |
83 |
67 def new_contract(*args_unused, **kwargs_unused): |
84 def new_contract(*args_unused, **kwargs_unused): |
68 """Dummy no-op implementation of `new_contract`.""" |
85 """Dummy no-op implementation of `new_contract`.""" |
69 pass |
86 pass |
70 |
87 |
91 even if there are gaps between statements. |
108 even if there are gaps between statements. |
92 |
109 |
93 For example, if `statements` is [1,2,3,4,5,10,11,12,13,14] and |
110 For example, if `statements` is [1,2,3,4,5,10,11,12,13,14] and |
94 `lines` is [1,2,5,10,11,13,14] then the result will be "1-2, 5-11, 13-14". |
111 `lines` is [1,2,5,10,11,13,14] then the result will be "1-2, 5-11, 13-14". |
95 |
112 |
96 """ |
113 Both `lines` and `statements` can be any iterable. All of the elements of |
97 pairs = [] |
114 `lines` must be in `statements`, and all of the values must be positive |
98 i = 0 |
115 integers. |
99 j = 0 |
116 |
100 start = None |
117 """ |
101 statements = sorted(statements) |
118 statements = sorted(statements) |
102 lines = sorted(lines) |
119 lines = sorted(lines) |
103 while i < len(statements) and j < len(lines): |
120 |
104 if statements[i] == lines[j]: |
121 pairs = [] |
105 if start is None: |
122 start = None |
106 start = lines[j] |
123 lidx = 0 |
107 end = lines[j] |
124 for stmt in statements: |
108 j += 1 |
125 if lidx >= len(lines): |
|
126 break |
|
127 if stmt == lines[lidx]: |
|
128 lidx += 1 |
|
129 if not start: |
|
130 start = stmt |
|
131 end = stmt |
109 elif start: |
132 elif start: |
110 pairs.append((start, end)) |
133 pairs.append((start, end)) |
111 start = None |
134 start = None |
112 i += 1 |
|
113 if start: |
135 if start: |
114 pairs.append((start, end)) |
136 pairs.append((start, end)) |
115 ret = ', '.join(map(nice_pair, pairs)) |
137 ret = ', '.join(map(nice_pair, pairs)) |
116 return ret |
138 return ret |
117 |
139 |
127 attr = "_once_" + fn.__name__ |
149 attr = "_once_" + fn.__name__ |
128 |
150 |
129 def _wrapped(self): |
151 def _wrapped(self): |
130 """Inner function that checks the cache.""" |
152 """Inner function that checks the cache.""" |
131 if hasattr(self, attr): |
153 if hasattr(self, attr): |
132 raise Exception("Shouldn't have called %s more than once" % fn.__name__) |
154 raise AssertionError("Shouldn't have called %s more than once" % fn.__name__) |
133 setattr(self, attr, True) |
155 setattr(self, attr, True) |
134 return fn(self) |
156 return fn(self) |
135 return _wrapped |
157 return _wrapped |
136 else: |
158 else: |
137 return fn |
159 return fn # pragma: not testing |
138 |
160 |
139 |
161 |
140 def bool_or_none(b): |
162 def bool_or_none(b): |
141 """Return bool(b), but preserve None.""" |
163 """Return bool(b), but preserve None.""" |
142 if b is None: |
164 if b is None: |
177 self.md5 = hashlib.md5() |
199 self.md5 = hashlib.md5() |
178 |
200 |
179 def update(self, v): |
201 def update(self, v): |
180 """Add `v` to the hash, recursively if needed.""" |
202 """Add `v` to the hash, recursively if needed.""" |
181 self.md5.update(to_bytes(str(type(v)))) |
203 self.md5.update(to_bytes(str(type(v)))) |
182 if isinstance(v, string_class): |
204 if isinstance(v, unicode_class): |
183 self.md5.update(to_bytes(v)) |
205 self.md5.update(v.encode('utf8')) |
184 elif isinstance(v, bytes): |
206 elif isinstance(v, bytes): |
185 self.md5.update(v) |
207 self.md5.update(v) |
186 elif v is None: |
208 elif v is None: |
187 pass |
209 pass |
188 elif isinstance(v, (int, float)): |
210 elif isinstance(v, (int, float)): |
225 thing=thing, name=name, func_name=func_name |
247 thing=thing, name=name, func_name=func_name |
226 ) |
248 ) |
227 ) |
249 ) |
228 |
250 |
229 |
251 |
230 class CoverageException(Exception): |
252 class SimpleRepr(object): |
231 """An exception specific to coverage.py.""" |
253 """A mixin implementing a simple __repr__.""" |
|
254 def __repr__(self): |
|
255 return "<{klass} @{id:x} {attrs}>".format( |
|
256 klass=self.__class__.__name__, |
|
257 id=id(self) & 0xFFFFFF, |
|
258 attrs=" ".join("{}={!r}".format(k, v) for k, v in self.__dict__.items()), |
|
259 ) |
|
260 |
|
261 |
|
262 class BaseCoverageException(Exception): |
|
263 """The base of all Coverage exceptions.""" |
|
264 pass |
|
265 |
|
266 |
|
267 class CoverageException(BaseCoverageException): |
|
268 """A run-of-the-mill exception specific to coverage.py.""" |
232 pass |
269 pass |
233 |
270 |
234 |
271 |
235 class NoSource(CoverageException): |
272 class NoSource(CoverageException): |
236 """We couldn't find the source for a module.""" |
273 """We couldn't find the source for a module.""" |