summaryrefslogtreecommitdiff
path: root/coverage
diff options
context:
space:
mode:
Diffstat (limited to 'coverage')
-rw-r--r--coverage/collector.py28
-rw-r--r--coverage/control.py9
-rw-r--r--coverage/ctracer/tracer.c28
-rw-r--r--coverage/ctracer/tracer.h2
-rw-r--r--coverage/pytracer.py10
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