4
4
import warnings
5
5
6
6
import pytest
7
+ import coverage
7
8
from coverage .misc import CoverageException
8
9
9
10
from . import compat
@@ -48,6 +49,16 @@ def validate_fail_under(num_str):
48
49
return float (num_str )
49
50
50
51
52
+ def validate_contexts (arg ):
53
+ if coverage .version_info <= (5 , 0 ):
54
+ msg = '--cov-contexts is only supported with coverage.py >= 5.x'
55
+ raise argparse .ArgumentTypeError (msg )
56
+ if arg != "test" :
57
+ msg = '--cov-contexts=test is the only supported value'
58
+ raise argparse .ArgumentTypeError (msg )
59
+ return arg
60
+
61
+
51
62
class StoreReport (argparse .Action ):
52
63
def __call__ (self , parser , namespace , values , option_string = None ):
53
64
report_type , file = values
@@ -88,6 +99,9 @@ def pytest_addoption(parser):
88
99
'Default: False' )
89
100
group .addoption ('--cov-branch' , action = 'store_true' , default = None ,
90
101
help = 'Enable branch coverage.' )
102
+ group .addoption ('--cov-contexts' , action = 'store' , metavar = 'CONTEXT' ,
103
+ type = validate_contexts ,
104
+ help = 'Dynamic contexts to use. "test" for now.' )
91
105
92
106
93
107
def _prepare_cov_source (cov_source ):
@@ -131,6 +145,7 @@ def __init__(self, options, pluginmanager, start=True):
131
145
self .failed = False
132
146
self ._started = False
133
147
self ._disabled = False
148
+ self .test_contexts = False
134
149
self .options = options
135
150
136
151
is_dist = (getattr (options , 'numprocesses' , False ) or
@@ -146,6 +161,9 @@ def __init__(self, options, pluginmanager, start=True):
146
161
self .options .cov_report = {}
147
162
self .options .cov_source = _prepare_cov_source (self .options .cov_source )
148
163
164
+ if getattr (options , 'cov_contexts' , None ) == 'test' :
165
+ self .test_contexts = True
166
+
149
167
if is_dist and start :
150
168
self .start (engine .DistMaster )
151
169
elif start :
@@ -293,8 +311,12 @@ def pytest_runtest_setup(self, item):
293
311
# test is run in another process than session, run
294
312
# coverage manually
295
313
embed .init ()
314
+ if self .test_contexts :
315
+ self .switch_context (item , 'setup' )
296
316
297
317
def pytest_runtest_teardown (self , item ):
318
+ if self .test_contexts :
319
+ self .switch_context (item , 'teardown' )
298
320
embed .cleanup ()
299
321
300
322
@compat .hookwrapper
@@ -305,8 +327,14 @@ def pytest_runtest_call(self, item):
305
327
yield
306
328
self .cov_controller .resume ()
307
329
else :
330
+ if self .test_contexts :
331
+ self .switch_context (item , 'run' )
308
332
yield
309
333
334
+ def switch_context (self , item , when ):
335
+ context = "{item.nodeid}|{when}" .format (item = item , when = when )
336
+ self .cov_controller .cov .switch_context (context )
337
+
310
338
311
339
@pytest .fixture
312
340
def no_cover ():
0 commit comments