diff options
Diffstat (limited to 'coverage')
-rw-r--r-- | coverage/collector.py | 28 | ||||
-rw-r--r-- | coverage/control.py | 9 | ||||
-rw-r--r-- | coverage/ctracer/tracer.c | 28 | ||||
-rw-r--r-- | coverage/ctracer/tracer.h | 2 | ||||
-rw-r--r-- | coverage/pytracer.py | 10 |
5 files changed, 62 insertions, 15 deletions
diff --git a/coverage/collector.py b/coverage/collector.py index 3e28b3b1..64abed49 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -162,6 +162,13 @@ class Collector(object): """Return the class name of the tracer we're using.""" return self._trace_class.__name__ + def _clear_data(self): + """Clear out existing data, but stay ready for more collection.""" + self.data.clear() + + for tracer in self.tracers: + tracer.reset_activity() + def reset(self): """Clear collected data, and prepare to collect more.""" # A dictionary mapping file names to dicts with line number keys (if not @@ -208,6 +215,8 @@ class Collector(object): # Our active Tracers. self.tracers = [] + self._clear_data() + def _start_tracer(self): """Start a new Tracer object, and store it in self.tracers.""" tracer = self._trace_class() @@ -267,6 +276,8 @@ class Collector(object): if self._collectors: self._collectors[-1].pause() + self.tracers = [] + # Check to see whether we had a fullcoverage tracer installed. If so, # get the stack frames it stashed away for us. traces0 = [] @@ -309,7 +320,6 @@ class Collector(object): ) self.pause() - self.tracers = [] # Remove this Collector from the stack, and resume the one underneath # (if any). @@ -338,6 +348,14 @@ class Collector(object): else: self._start_tracer() + def activity(self): + """Has any activity been traced? + + Returns a boolean, True if any trace function was invoked. + + """ + return any(tracer.activity() for tracer in self.tracers) + def switch_context(self, new_context): """Who-Tests-What hack: switch to a new who-context.""" # Make a new data dict, or find the existing one, and switch all the @@ -347,11 +365,7 @@ class Collector(object): tracer.data = data def save_data(self, covdata): - """Save the collected data to a `CoverageData`. - - Also resets the collector. - - """ + """Save the collected data to a `CoverageData`.""" def abs_file_dict(d): """Return a dict like d, but with keys modified by `abs_file`.""" return dict((abs_file(k), v) for k, v in iitems(d)) @@ -369,4 +383,4 @@ class Collector(object): with open(out_file, "w") as wtw_out: pprint.pprint(self.contexts, wtw_out) - self.reset() + self._clear_data() diff --git a/coverage/control.py b/coverage/control.py index a9b4b9ef..a12eb2ee 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -177,8 +177,6 @@ class Coverage(object): self._inited = False # Have we started collecting and not stopped it? self._started = False - # Have we measured some data and not harvested it? - self._measured = False # If we have sub-process measurement happening automatically, then we # want any explicit creation of a Coverage object to mean, this process @@ -671,7 +669,6 @@ class Coverage(object): self.collector.start() self._started = True - self._measured = True def stop(self): """Stop measuring code coverage.""" @@ -789,7 +786,7 @@ class Coverage(object): ) def get_data(self): - """Get the collected data and reset the collector. + """Get the collected data. Also warn about various problems collecting data. @@ -799,7 +796,8 @@ class Coverage(object): """ self._init() - if not self._measured: + + if not self.collector.activity(): return self.data self.collector.save_data(self.data) @@ -837,7 +835,6 @@ class Coverage(object): if self.config.note: self.data.add_run_info(note=self.config.note) - self._measured = False return self.data def _find_unexecuted_files(self, src_dir): diff --git a/coverage/ctracer/tracer.c b/coverage/ctracer/tracer.c index 619ccee9..ee112d83 100644 --- a/coverage/ctracer/tracer.c +++ b/coverage/ctracer/tracer.c @@ -340,8 +340,8 @@ CTracer_handle_call(CTracer *self, PyFrameObject *frame) CFileDisposition * pdisp = NULL; - STATS( self->stats.calls++; ) + self->activity = TRUE; /* Grow the stack. */ if (CTracer_set_pdata_stack(self) < 0) { @@ -1034,7 +1034,25 @@ CTracer_stop(CTracer *self, PyObject *args_unused) } static PyObject * -CTracer_get_stats(CTracer *self) +CTracer_activity(CTracer *self, PyObject *args_unused) +{ + if (self->activity) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject * +CTracer_reset_activity(CTracer *self, PyObject *args_unused) +{ + self->activity = FALSE; + Py_RETURN_NONE; +} + +static PyObject * +CTracer_get_stats(CTracer *self, PyObject *args_unused) { #if COLLECT_STATS return Py_BuildValue( @@ -1103,6 +1121,12 @@ CTracer_methods[] = { { "get_stats", (PyCFunction) CTracer_get_stats, METH_VARARGS, PyDoc_STR("Get statistics about the tracing") }, + { "activity", (PyCFunction) CTracer_activity, METH_VARARGS, + PyDoc_STR("Has there been any activity?") }, + + { "reset_activity", (PyCFunction) CTracer_reset_activity, METH_VARARGS, + PyDoc_STR("Reset the activity flag") }, + { NULL } }; diff --git a/coverage/ctracer/tracer.h b/coverage/ctracer/tracer.h index c174ae5a..d5d630fb 100644 --- a/coverage/ctracer/tracer.h +++ b/coverage/ctracer/tracer.h @@ -33,6 +33,8 @@ typedef struct CTracer { BOOL started; /* Are we tracing arcs, or just lines? */ BOOL tracing_arcs; + /* Have we had any activity? */ + BOOL activity; /* The data stack is a stack of dictionaries. Each dictionary collects diff --git a/coverage/pytracer.py b/coverage/pytracer.py index 452af721..3cf956fd 100644 --- a/coverage/pytracer.py +++ b/coverage/pytracer.py @@ -52,6 +52,7 @@ class PyTracer(object): self.last_exc_firstlineno = 0 self.thread = None self.stopped = False + self._activity = False self.in_atexit = False # On exit, self.in_atexit = True @@ -82,6 +83,7 @@ class PyTracer(object): if event == 'call': # Entering a new function context. Decide if we should trace # in this file. + self._activity = True self.data_stack.append((self.cur_file_dict, self.last_line)) filename = frame.f_code.co_filename disp = self.should_trace_cache.get(filename) @@ -168,6 +170,14 @@ class PyTracer(object): sys.settrace(None) + def activity(self): + """Has there been any activity?""" + return self._activity + + def reset_activity(self): + """Reset the activity() flag.""" + self._activity = False + def get_stats(self): """Return a dictionary of statistics, or None.""" return None |