1
1
"""Coverage controllers for use by pytest-cov and nose-cov."""
2
2
import contextlib
3
3
import copy
4
+ import functools
4
5
import os
5
6
import random
6
7
import socket
@@ -31,6 +32,25 @@ def _backup(obj, attr):
31
32
setattr (obj , attr , backup )
32
33
33
34
35
+ def _ensure_topdir (meth ):
36
+ @functools .wraps (meth )
37
+ def ensure_topdir_wrapper (self , * args , ** kwargs ):
38
+ try :
39
+ original_cwd = os .getcwd ()
40
+ except OSError :
41
+ # Looks like it's gone, this is non-ideal because a side-effect will
42
+ # be introduced in the tests here but we can't do anything about it.
43
+ original_cwd = None
44
+ os .chdir (self .topdir )
45
+ try :
46
+ return meth (self , * args , ** kwargs )
47
+ finally :
48
+ if original_cwd is not None :
49
+ os .chdir (original_cwd )
50
+
51
+ return ensure_topdir_wrapper
52
+
53
+
34
54
class CovController (object ):
35
55
"""Base class for different plugin implementations."""
36
56
@@ -50,15 +70,26 @@ def __init__(self, cov_source, cov_report, cov_config, cov_append, cov_branch, c
50
70
self .node_descs = set ()
51
71
self .failed_workers = []
52
72
self .topdir = os .getcwd ()
73
+ self .is_collocated = None
53
74
75
+ @contextlib .contextmanager
76
+ def ensure_topdir (self ):
77
+ original_cwd = os .getcwd ()
78
+ os .chdir (self .topdir )
79
+ yield
80
+ os .chdir (original_cwd )
81
+
82
+ @_ensure_topdir
54
83
def pause (self ):
55
84
self .cov .stop ()
56
85
self .unset_env ()
57
86
87
+ @_ensure_topdir
58
88
def resume (self ):
59
89
self .cov .start ()
60
90
self .set_env ()
61
91
92
+ @_ensure_topdir
62
93
def set_env (self ):
63
94
"""Put info about coverage into the env so that subprocesses can activate coverage."""
64
95
if self .cov_source is None :
@@ -99,6 +130,7 @@ def sep(stream, s, txt):
99
130
out = '%s %s %s\n ' % (s * sep_len , txt , s * (sep_len + sep_extra ))
100
131
stream .write (out )
101
132
133
+ @_ensure_topdir
102
134
def summary (self , stream ):
103
135
"""Produce coverage reports."""
104
136
total = None
@@ -171,6 +203,7 @@ def summary(self, stream):
171
203
class Central (CovController ):
172
204
"""Implementation for centralised operation."""
173
205
206
+ @_ensure_topdir
174
207
def start (self ):
175
208
cleanup ()
176
209
@@ -190,6 +223,7 @@ def start(self):
190
223
self .cov .start ()
191
224
self .set_env ()
192
225
226
+ @_ensure_topdir
193
227
def finish (self ):
194
228
"""Stop coverage, save data to file and set the list of coverage objects to report on."""
195
229
@@ -209,6 +243,7 @@ def finish(self):
209
243
class DistMaster (CovController ):
210
244
"""Implementation for distributed master."""
211
245
246
+ @_ensure_topdir
212
247
def start (self ):
213
248
cleanup ()
214
249
@@ -259,7 +294,7 @@ def testnodedown(self, node, error):
259
294
socket .gethostname (), os .getpid (),
260
295
random .randint (0 , 999999 ),
261
296
output ['cov_worker_node_id' ]
262
- )
297
+ )
263
298
264
299
cov = coverage .Coverage (source = self .cov_source ,
265
300
branch = self .cov_branch ,
@@ -284,6 +319,7 @@ def testnodedown(self, node, error):
284
319
node_desc = self .get_node_desc (rinfo .platform , rinfo .version_info )
285
320
self .node_descs .add (node_desc )
286
321
322
+ @_ensure_topdir
287
323
def finish (self ):
288
324
"""Combines coverage data and sets the list of coverage objects to report on."""
289
325
@@ -299,7 +335,9 @@ def finish(self):
299
335
class DistWorker (CovController ):
300
336
"""Implementation for distributed workers."""
301
337
338
+ @_ensure_topdir
302
339
def start (self ):
340
+
303
341
cleanup ()
304
342
305
343
# Determine whether we are collocated with master.
@@ -323,6 +361,7 @@ def start(self):
323
361
self .cov .start ()
324
362
self .set_env ()
325
363
364
+ @_ensure_topdir
326
365
def finish (self ):
327
366
"""Stop coverage and send relevant info back to the master."""
328
367
self .unset_env ()
0 commit comments