3434 CTracer = None
3535
3636
37- def should_start_context (frame ):
38- """Who-Tests-What hack: Determine whether this frame begins a new who-context."""
39- fn_name = frame .f_code .co_name
40- if fn_name .startswith ("test" ):
41- return fn_name
42- return None
43-
44-
4537class Collector (object ):
4638 """Collects trace data.
4739
@@ -66,7 +58,10 @@ class Collector(object):
6658 # The concurrency settings we support here.
6759 SUPPORTED_CONCURRENCIES = set (["greenlet" , "eventlet" , "gevent" , "thread" ])
6860
69- def __init__ (self , should_trace , check_include , timid , branch , warn , concurrency ):
61+ def __init__ (
62+ self , should_trace , check_include , should_start_context ,
63+ timid , branch , warn , concurrency ,
64+ ):
7065 """Create a collector.
7166
7267 `should_trace` is a function, taking a file name and a frame, and
@@ -75,6 +70,11 @@ def __init__(self, should_trace, check_include, timid, branch, warn, concurrency
7570 `check_include` is a function taking a file name and a frame. It returns
7671 a boolean: True if the file should be traced, False if not.
7772
73+ `should_start_context` is a function taking a frame, and returning a
74+ string. If the frame should be the start of a new context, the string
75+ is the new context. If the frame should not be the start of a new
76+ context, return None.
77+
7878 If `timid` is true, then a slower simpler trace function will be
7979 used. This is important for some environments where manipulation of
8080 tracing functions make the faster more sophisticated trace function not
@@ -96,6 +96,7 @@ def __init__(self, should_trace, check_include, timid, branch, warn, concurrency
9696 """
9797 self .should_trace = should_trace
9898 self .check_include = check_include
99+ self .should_start_context = should_start_context
99100 self .warn = warn
100101 self .branch = branch
101102 self .threading = None
@@ -139,10 +140,6 @@ def __init__(self, should_trace, check_include, timid, branch, warn, concurrency
139140 )
140141 )
141142
142- # Who-Tests-What is just a hack at the moment, so turn it on with an
143- # environment variable.
144- self .wtw = int (os .getenv ('COVERAGE_WTW' , 0 ))
145-
146143 self .reset ()
147144
148145 if timid :
@@ -175,7 +172,11 @@ def tracer_name(self):
175172
176173 def _clear_data (self ):
177174 """Clear out existing data, but stay ready for more collection."""
178- self .data .clear ()
175+ # We used to used self.data.clear(), but that would remove filename
176+ # keys and data values that were still in use higher up the stack
177+ # when we are called as part of switch_context.
178+ for d in self .data .values ():
179+ d .clear ()
179180
180181 for tracer in self .tracers :
181182 tracer .reset_activity ()
@@ -187,10 +188,6 @@ def reset(self):
187188 # pairs as keys (if branch coverage).
188189 self .data = {}
189190
190- # A dict mapping contexts to data dictionaries.
191- self .contexts = {}
192- self .contexts [None ] = self .data
193-
194191 # A dictionary mapping file names to file tracer plugin names that will
195192 # handle them.
196193 self .file_tracers = {}
@@ -252,11 +249,13 @@ def _start_tracer(self):
252249 tracer .threading = self .threading
253250 if hasattr (tracer , 'check_include' ):
254251 tracer .check_include = self .check_include
255- if self .wtw :
256- if hasattr (tracer , 'should_start_context' ):
257- tracer .should_start_context = should_start_context
258- if hasattr (tracer , 'switch_context' ):
259- tracer .switch_context = self .switch_context
252+ if hasattr (tracer , 'should_start_context' ):
253+ tracer .should_start_context = self .should_start_context
254+ tracer .switch_context = self .switch_context
255+ elif self .should_start_context :
256+ raise CoverageException (
257+ "Can't support dynamic contexts with {}" .format (self .tracer_name ())
258+ )
260259
261260 fn = tracer .start ()
262261 self .tracers .append (tracer )
@@ -372,12 +371,9 @@ def _activity(self):
372371 return any (tracer .activity () for tracer in self .tracers )
373372
374373 def switch_context (self , new_context ):
375- """Who-Tests-What hack: switch to a new who-context."""
376- # Make a new data dict, or find the existing one, and switch all the
377- # tracers to use it.
378- data = self .contexts .setdefault (new_context , {})
379- for tracer in self .tracers :
380- tracer .data = data
374+ """Switch to a new dynamic context."""
375+ self .flush_data ()
376+ self .covdata .set_context (new_context )
381377
382378 def cached_abs_file (self , filename ):
383379 """A locally cached version of `abs_file`."""
@@ -415,20 +411,13 @@ def abs_file_dict(d):
415411 else :
416412 raise runtime_err # pylint: disable=raising-bad-type
417413
418- return dict ((self .cached_abs_file (k ), v ) for k , v in items )
414+ return dict ((self .cached_abs_file (k ), v ) for k , v in items if v )
419415
420416 if self .branch :
421417 self .covdata .add_arcs (abs_file_dict (self .data ))
422418 else :
423419 self .covdata .add_lines (abs_file_dict (self .data ))
424420 self .covdata .add_file_tracers (abs_file_dict (self .file_tracers ))
425421
426- if self .wtw :
427- # Just a hack, so just hack it.
428- import pprint
429- out_file = "coverage_wtw_{:06}.py" .format (os .getpid ())
430- with open (out_file , "w" ) as wtw_out :
431- pprint .pprint (self .contexts , wtw_out )
432-
433422 self ._clear_data ()
434423 return True
0 commit comments