summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coverage/control.py17
-rw-r--r--coverage/data.py34
2 files changed, 47 insertions, 4 deletions
diff --git a/coverage/control.py b/coverage/control.py
index 16cf74ee..13261de2 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -4,6 +4,7 @@
"""Core control stuff for coverage.py."""
import atexit
+import datetime
import inspect
import os
import platform
@@ -195,8 +196,6 @@ class Coverage(object):
is called.
"""
- from coverage import __version__
-
if self._inited:
return
@@ -282,7 +281,7 @@ class Coverage(object):
# environments (virtualenv, for example), these modules may be
# spread across a few locations. Look at all the candidate modules
# we've imported, and take all the different ones.
- for m in (atexit, inspect, os, platform, _structseq, traceback):
+ for m in (atexit, datetime, inspect, os, platform, _structseq, traceback):
if m is not None and hasattr(m, "__file__"):
self.pylib_dirs.add(self._canonical_dir(m))
if _structseq and not hasattr(_structseq, '__file__'):
@@ -780,6 +779,18 @@ class Coverage(object):
self.data.touch_file(py_file)
+ # Add run information.
+ from coverage import __version__
+
+ self.data.add_run_info(
+ collector="coverage.py v%s" % __version__,
+ when=datetime.datetime.now().isoformat(),
+ command_line=sys.argv,
+ python=sys.version.replace('\n', ''),
+ platform=platform.platform(),
+ implementation=platform.python_implementation(),
+ )
+
self._measured = False
return self.data
diff --git a/coverage/data.py b/coverage/data.py
index 386c1567..e8aaf1c0 100644
--- a/coverage/data.py
+++ b/coverage/data.py
@@ -19,7 +19,9 @@ from coverage.misc import CoverageException, file_be_gone
class CoverageData(object):
"""Manages collected coverage data, including file storage.
- This class is the public supported API to coverage.py's data.
+ This class is the public supported API to the data coverage.py collects
+ during program execution. It includes information about what code was
+ executed.
.. note::
@@ -81,6 +83,13 @@ class CoverageData(object):
#
# { 'file1': "django.coverage", ... }
#
+ # * run: a dict of information about the coverage.py run::
+ #
+ # { 'collector': 'coverage.py',
+ # 'collected': '20150724T162717',
+ # ...
+ # }
+ #
# Only one of `lines` or `arcs` will be present: with branch coverage, data
# is stored as arcs. Without branch coverage, it is stored as lines. The
# line data is easily recovered from the arcs: it is all the first elements
@@ -115,6 +124,9 @@ class CoverageData(object):
#
self._file_tracers = {}
+ # A dict of information about the coverage.py run.
+ self._run_info = {}
+
##
## Reading data
##
@@ -175,6 +187,10 @@ class CoverageData(object):
return self._file_tracers.get(filename, "")
return None
+ def run_info(self):
+ """Return the dict of run information."""
+ return self._run_info
+
def measured_files(self):
"""A list of all files that had been measured."""
return list(self._arcs or self._lines)
@@ -218,6 +234,7 @@ class CoverageData(object):
for fname, arcs in iitems(data.get('arcs', {}))
)
self._file_tracers = data.get('file_tracers', {})
+ self._run_info = data.get('run', {})
self._validate()
@@ -324,6 +341,17 @@ class CoverageData(object):
self._validate()
+ def add_run_info(self, **kwargs):
+ """Add information about the run.
+
+ Keywords are arbitrary, and are stored in the run dictionary. Values
+ must be JSON serializable. You may use this function more than once,
+ but repeated keywords overwrite each other.
+
+ """
+ self._run_info.update(kwargs)
+ self._validate()
+
def touch_file(self, filename):
"""Ensure that `filename` appears in the data, empty if needed."""
(self._arcs or self._lines).setdefault(filename, [])
@@ -343,6 +371,9 @@ class CoverageData(object):
if self._file_tracers:
file_data['file_tracers'] = self._file_tracers
+ if self._run_info:
+ file_data['run'] = self._run_info
+
# Write the data to the file.
file_obj.write(self.GO_AWAY)
json.dump(file_data, file_obj)
@@ -359,6 +390,7 @@ class CoverageData(object):
self._lines = {}
self._arcs = {}
self._file_tracers = {}
+ self._run_info = {}
self._validate()
def update(self, other_data, aliases=None):