From 7efd4f50062f750df145102fc07c87fc49599bbe Mon Sep 17 00:00:00 2001 From: Christine Lytwynec Date: Tue, 21 Apr 2015 11:28:13 -0400 Subject: Added ability to combine coverage data files from multiple directories into one file via command line args. --- coverage/control.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 563925e..4a9ac72 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -717,7 +717,7 @@ class Coverage(object): self._harvest_data() self.data.write(suffix=data_suffix) - def combine(self): + def combine(self, data_dirs=None): """Combine together a number of similarly-named coverage data files. All coverage data files whose name starts with `data_file` (from the @@ -733,7 +733,7 @@ class Coverage(object): result = paths[0] for pattern in paths[1:]: aliases.add(pattern, result) - self.data.combine_parallel_data(aliases=aliases) + self.data.combine_parallel_data(aliases=aliases, data_dirs=data_dirs) def _harvest_data(self): """Get the collected data and reset the collector. -- cgit v1.2.1 From 161556f47ec6b8f7c0232c21fdbdd7cc25bd3d8e Mon Sep 17 00:00:00 2001 From: Christine Lytwynec Date: Wed, 22 Apr 2015 11:45:55 -0400 Subject: Update docstring and command line help text. --- coverage/control.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 4a9ac72..2c8d384 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -724,6 +724,10 @@ class Coverage(object): coverage() constructor) will be read, and combined together into the current measurements. + `data_dirs` is a list of directories from which data files should be + combined. If no list is passed, then the data files from the current + directory will be combined. + """ self._init() aliases = None -- cgit v1.2.1 From 9520d008fb6a006aa70ae341906b0be18f40cd41 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 17 May 2015 18:36:30 -0400 Subject: Use PyContracts so we can declare/enforce parameter and return types. This commit doesn't add any uses of PyContracts, but gets the machinery in place. --- coverage/control.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 2c8d384..defba56 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -169,7 +169,7 @@ class Coverage(object): self.source_pkgs = self.file_locator = None self.data = self.collector = None self.plugins = self.file_tracing_plugins = None - self.pylib_dirs = self.cover_dir = None + self.pylib_dirs = self.cover_dirs = None self.data_suffix = self.run_suffix = None self._exclude_re = None self.debug = None @@ -301,7 +301,12 @@ class Coverage(object): # To avoid tracing the coverage code itself, we skip anything located # where we are. - self.cover_dir = self._canonical_dir(__file__) + self.cover_dirs = [self._canonical_dir(__file__)] + if env.TESTING: + # When testing, we use PyContracts, which should be considered + # part of coverage. + import contracts + self.cover_dirs.append(self._canonical_dir(contracts)) # Set the reporting precision. Numbers.set_precision(self.config.precision) @@ -315,8 +320,8 @@ class Coverage(object): self.source_match = TreeMatcher(self.source) self.source_pkgs_match = ModuleMatcher(self.source_pkgs) else: - if self.cover_dir: - self.cover_match = TreeMatcher([self.cover_dir]) + if self.cover_dirs: + self.cover_match = TreeMatcher(self.cover_dirs) if self.pylib_dirs: self.pylib_match = TreeMatcher(self.pylib_dirs) if self.include: @@ -1033,7 +1038,7 @@ class Coverage(object): info = [ ('version', covmod.__version__), ('coverage', covmod.__file__), - ('cover_dir', self.cover_dir), + ('cover_dirs', self.cover_dirs), ('pylib_dirs', self.pylib_dirs), ('tracer', self.collector.tracer_name()), ('file_tracing_plugins', ft_plugins), -- cgit v1.2.1 From cc3a20140e4bd1472be4ce288a379c923ef6ff39 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Mon, 25 May 2015 14:33:25 -0400 Subject: Normalize measured data's filenames before adding to data. --- coverage/control.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index defba56..574c874 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -754,10 +754,13 @@ class Coverage(object): if not self._measured: return + def abs_file_dict(d): + return dict((abs_file(k), v) for k,v in iitems(d)) + # TODO: seems like this parallel structure is getting kinda old... - self.data.add_line_data(self.collector.get_line_data()) - self.data.add_arc_data(self.collector.get_arc_data()) - self.data.add_plugin_data(self.collector.get_plugin_data()) + self.data.add_line_data(abs_file_dict(self.collector.get_line_data())) + self.data.add_arc_data(abs_file_dict(self.collector.get_arc_data())) + self.data.add_plugin_data(abs_file_dict(self.collector.get_plugin_data())) self.collector.reset() # If there are still entries in the source_pkgs list, then we never -- cgit v1.2.1 From ab39466c7b13b71ffc826722bfad0c9471b1f096 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Mon, 25 May 2015 16:59:11 -0400 Subject: Add a docstring --- coverage/control.py | 1 + 1 file changed, 1 insertion(+) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 574c874..4bb6866 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -755,6 +755,7 @@ class Coverage(object): return 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)) # TODO: seems like this parallel structure is getting kinda old... -- cgit v1.2.1 From f15f22fd1ac7da4a4ad7dfd21015126420df64d0 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Wed, 3 Jun 2015 14:23:29 -0400 Subject: PyContracts now uses six, so exclude six during testing. --- coverage/control.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 4bb6866..d05b844 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -304,9 +304,11 @@ class Coverage(object): self.cover_dirs = [self._canonical_dir(__file__)] if env.TESTING: # When testing, we use PyContracts, which should be considered - # part of coverage. - import contracts - self.cover_dirs.append(self._canonical_dir(contracts)) + # part of coverage, and it uses six. Exclude those directories just + # as we exclude ourselves. + import contracts, six + for mod in [contracts, six]: + self.cover_dirs.append(self._canonical_dir(mod)) # Set the reporting precision. Numbers.set_precision(self.config.precision) -- cgit v1.2.1 From 5416b815eb4ce3d525868b17d5b3fa1e92fcad6c Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 13 Jun 2015 08:22:00 -0400 Subject: Move plugin support stuff into plugin_support.py --- coverage/control.py | 49 +------------------------------------------------ 1 file changed, 1 insertion(+), 48 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index d05b844..9256edb 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -24,6 +24,7 @@ from coverage.misc import CoverageException, bool_or_none, join_regex from coverage.misc import file_be_gone, overrides from coverage.monkey import patch_multiprocessing from coverage.plugin import CoveragePlugin, FileReporter +from coverage.plugin_support import Plugins from coverage.python import PythonFileReporter from coverage.results import Analysis, Numbers from coverage.summary import SummaryReporter @@ -1163,51 +1164,3 @@ def process_startup(): # A hack for debugging testing in sub-processes. _TEST_NAME_FILE = "" # "/tmp/covtest.txt" - - -class Plugins(object): - """The currently loaded collection of coverage.py plugins.""" - - def __init__(self): - self.order = [] - self.names = {} - - @classmethod - def load_plugins(cls, modules, config): - """Load plugins from `modules`. - - Returns a list of loaded and configured plugins. - - """ - plugins = cls() - - for module in modules: - __import__(module) - mod = sys.modules[module] - - plugin_class = getattr(mod, "Plugin", None) - if plugin_class: - options = config.get_plugin_options(module) - plugin = plugin_class(options) - plugin._coverage_plugin_name = module - plugin._coverage_enabled = True - plugins.order.append(plugin) - plugins.names[module] = plugin - else: - raise CoverageException( - "Plugin module %r didn't define a Plugin class" % module - ) - - return plugins - - def __nonzero__(self): - return bool(self.order) - - __bool__ = __nonzero__ - - def __iter__(self): - return iter(self.order) - - def get(self, plugin_name): - """Return a plugin by name.""" - return self.names[plugin_name] -- cgit v1.2.1 From f230be76462efd15f48f216631f4d90db8d5685d Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 13 Jun 2015 14:19:45 -0400 Subject: Change FileLocator from a class to module-level functions --- coverage/control.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 9256edb..3cae1d3 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -9,14 +9,14 @@ import socket import sys import traceback -from coverage import env +from coverage import env, files from coverage.annotate import AnnotateReporter from coverage.backward import string_class, iitems from coverage.collector import Collector from coverage.config import CoverageConfig from coverage.data import CoverageData from coverage.debug import DebugControl -from coverage.files import FileLocator, TreeMatcher, FnmatchMatcher +from coverage.files import TreeMatcher, FnmatchMatcher from coverage.files import PathAliases, find_python_files, prep_patterns from coverage.files import ModuleMatcher, abs_file from coverage.html import HtmlReporter @@ -167,7 +167,7 @@ class Coverage(object): # Other instance attributes, set later. self.omit = self.include = self.source = None - self.source_pkgs = self.file_locator = None + self.source_pkgs = None self.data = self.collector = None self.plugins = self.file_tracing_plugins = None self.pylib_dirs = self.cover_dirs = None @@ -214,14 +214,14 @@ class Coverage(object): self._exclude_re = {} self._exclude_regex_stale() - self.file_locator = FileLocator() + files.set_relative_directory() # The source argument can be directories or package names. self.source = [] self.source_pkgs = [] for src in self.config.source or []: if os.path.exists(src): - self.source.append(self.file_locator.canonical_filename(src)) + self.source.append(files.canonical_filename(src)) else: self.source_pkgs.append(src) @@ -468,7 +468,7 @@ class Coverage(object): if filename.endswith("$py.class"): filename = filename[:-9] + ".py" - canonical = self.file_locator.canonical_filename(filename) + canonical = files.canonical_filename(filename) disp.canonical_filename = canonical # Try the plugins, see if they have an opinion about the file. @@ -486,10 +486,9 @@ class Coverage(object): if file_tracer.has_dynamic_source_filename(): disp.has_dynamic_filename = True else: - disp.source_filename = \ - self.file_locator.canonical_filename( - file_tracer.source_filename() - ) + disp.source_filename = files.canonical_filename( + file_tracer.source_filename() + ) break except Exception: self._warn( @@ -740,7 +739,7 @@ class Coverage(object): self._init() aliases = None if self.config.paths: - aliases = PathAliases(self.file_locator) + aliases = PathAliases() for paths in self.config.paths.values(): result = paths[0] for pattern in paths[1:]: @@ -792,7 +791,7 @@ class Coverage(object): # Find files that were never executed at all. for src in self.source: for py_file in find_python_files(src): - py_file = self.file_locator.canonical_filename(py_file) + py_file = files.canonical_filename(py_file) if self.omit_match and self.omit_match.match(py_file): # Turns out this file was omitted, so don't pull it back @@ -872,9 +871,7 @@ class Coverage(object): # The FileReporter can have a name attribute, but if it doesn't, we'll # supply it as the relative path to self.filename. if not hasattr(file_reporter, "name"): - file_reporter.name = self.file_locator.relative_filename( - file_reporter.filename - ) + file_reporter.name = files.relative_filename(file_reporter.filename) return file_reporter @@ -1013,7 +1010,7 @@ class Coverage(object): outfile = open(self.config.xml_output, "w") file_to_close = outfile try: - reporter = XmlReporter(self, self.config, self.file_locator) + reporter = XmlReporter(self, self.config) return reporter.report(morfs, outfile=outfile) except CoverageException: delete_file = True -- cgit v1.2.1 From 18f7ecbc364a2e95def74d6e7546e920cc38e238 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 14 Jun 2015 09:41:01 -0400 Subject: Debugging plugin wrappers --- coverage/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 3cae1d3..b982c79 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -202,7 +202,7 @@ class Coverage(object): self.debug = DebugControl(self.config.debug, self._debug_file) # Load plugins - self.plugins = Plugins.load_plugins(self.config.plugins, self.config) + self.plugins = Plugins.load_plugins(self.config.plugins, self.config, self.debug) self.file_tracing_plugins = [] for plugin in self.plugins: -- cgit v1.2.1 From 744bad2b1d1b376bbf46575ef0ae214741935b4f Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 14 Jun 2015 11:48:00 -0400 Subject: COVERAGE_DEBUG can set the debug configuration options --- coverage/control.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index b982c79..9ac091d 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -139,6 +139,9 @@ class Coverage(object): env_data_file = os.environ.get('COVERAGE_FILE') if env_data_file: self.config.data_file = env_data_file + debugs = os.environ.get('COVERAGE_DEBUG') + if debugs: + self.config.debug.extend(debugs.split(",")) # 4: from constructor arguments: self.config.from_args( -- cgit v1.2.1 From 23db5d3939149ebc9281333241208f66b6df8065 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 2 Jul 2015 07:18:01 -0400 Subject: Exec'ing code gives the wrong filename. A warning now, while we figure it out. Part of #380. --- coverage/control.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 9ac091d..48c0c1c 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -435,6 +435,7 @@ class Coverage(object): Returns a FileDisposition object. """ + original_filename = filename disp = FileDisposition(filename) def nope(disp, reason): @@ -452,6 +453,10 @@ class Coverage(object): dunder_file = frame.f_globals.get('__file__') if dunder_file: filename = self._source_for_file(dunder_file) + if os.path.basename(original_filename) != os.path.basename(filename): + # Files shouldn't be renamed when moved. This happens when + # exec'ing code, not sure why yet. + self._warn("File was renamed?: %r became %r" % (original_filename, filename)) if not filename: # Empty string is pretty useless. -- cgit v1.2.1 From 59c5ea34cc0da1b552dba03c0c7f34a83ee94e72 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 3 Jul 2015 07:44:30 -0400 Subject: The file-rename warning needs to take into account. --- coverage/control.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 48c0c1c..6a03db7 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -453,10 +453,11 @@ class Coverage(object): dunder_file = frame.f_globals.get('__file__') if dunder_file: filename = self._source_for_file(dunder_file) - if os.path.basename(original_filename) != os.path.basename(filename): - # Files shouldn't be renamed when moved. This happens when - # exec'ing code, not sure why yet. - self._warn("File was renamed?: %r became %r" % (original_filename, filename)) + if original_filename and not original_filename.startswith('<'): + if os.path.basename(original_filename) != os.path.basename(filename): + # Files shouldn't be renamed when moved. This happens when + # exec'ing code, not sure why yet. + self._warn("File was renamed?: %r became %r" % (original_filename, filename)) if not filename: # Empty string is pretty useless. -- cgit v1.2.1 From 1dba726d05dcdbd1be7d4b987151d691b0a7c535 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 4 Jul 2015 20:53:13 -0400 Subject: Remove the last vestige of FileReporter.name --- coverage/control.py | 5 ----- 1 file changed, 5 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 6a03db7..e4e67d3 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -877,11 +877,6 @@ class Coverage(object): else: file_reporter = PythonFileReporter(morf, self) - # The FileReporter can have a name attribute, but if it doesn't, we'll - # supply it as the relative path to self.filename. - if not hasattr(file_reporter, "name"): - file_reporter.name = files.relative_filename(file_reporter.filename) - return file_reporter def _get_file_reporters(self, morfs=None): -- cgit v1.2.1 From 152d22cfbae8a8371acabe35ae3de61fb31708d3 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 5 Jul 2015 11:07:11 -0400 Subject: Change how plugins are initialized. No more Plugin. Now coverage_init. --- coverage/control.py | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index e4e67d3..1dbf067 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -21,9 +21,9 @@ from coverage.files import PathAliases, find_python_files, prep_patterns from coverage.files import ModuleMatcher, abs_file from coverage.html import HtmlReporter from coverage.misc import CoverageException, bool_or_none, join_regex -from coverage.misc import file_be_gone, overrides +from coverage.misc import file_be_gone from coverage.monkey import patch_multiprocessing -from coverage.plugin import CoveragePlugin, FileReporter +from coverage.plugin import FileReporter from coverage.plugin_support import Plugins from coverage.python import PythonFileReporter from coverage.results import Analysis, Numbers @@ -172,7 +172,7 @@ class Coverage(object): self.omit = self.include = self.source = None self.source_pkgs = None self.data = self.collector = None - self.plugins = self.file_tracing_plugins = None + self.plugins = None self.pylib_dirs = self.cover_dirs = None self.data_suffix = self.run_suffix = None self._exclude_re = None @@ -207,11 +207,6 @@ class Coverage(object): # Load plugins self.plugins = Plugins.load_plugins(self.config.plugins, self.config, self.debug) - self.file_tracing_plugins = [] - for plugin in self.plugins: - if overrides(plugin, "file_tracer", CoveragePlugin): - self.file_tracing_plugins.append(plugin) - # _exclude_re is a dict that maps exclusion list names to compiled # regexes. self._exclude_re = {} @@ -246,17 +241,17 @@ class Coverage(object): ) # Early warning if we aren't going to be able to support plugins. - if self.file_tracing_plugins and not self.collector.supports_plugins: + if self.plugins.file_tracers and not self.collector.supports_plugins: self._warn( "Plugin file tracers (%s) aren't supported with %s" % ( ", ".join( plugin._coverage_plugin_name - for plugin in self.file_tracing_plugins + for plugin in self.plugins.file_tracers ), self.collector.tracer_name(), ) ) - for plugin in self.file_tracing_plugins: + for plugin in self.plugins.file_tracers: plugin._coverage_enabled = False # Suffixes are a bit tricky. We want to use the data suffix only when @@ -482,7 +477,7 @@ class Coverage(object): # Try the plugins, see if they have an opinion about the file. plugin = None - for plugin in self.file_tracing_plugins: + for plugin in self.plugins.file_tracers: if not plugin._coverage_enabled: continue @@ -1037,7 +1032,7 @@ class Coverage(object): implementation = "unknown" ft_plugins = [] - for ft in self.file_tracing_plugins: + for ft in self.plugins.file_tracers: ft_name = ft._coverage_plugin_name if not ft._coverage_enabled: ft_name += " (disabled)" @@ -1049,7 +1044,7 @@ class Coverage(object): ('cover_dirs', self.cover_dirs), ('pylib_dirs', self.pylib_dirs), ('tracer', self.collector.tracer_name()), - ('file_tracing_plugins', ft_plugins), + ('plugins.file_tracers', ft_plugins), ('config_files', self.config.attempted_config_files), ('configs_read', self.config.config_files), ('data_path', self.data.filename), -- cgit v1.2.1 From 90a95fdd608dc94d052a1b79667d60bb41f9dd31 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 11 Jul 2015 08:49:20 -0400 Subject: If __file__ disagrees with the frame, use the frame info. Fixes #380. --- coverage/control.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 1dbf067..91365e1 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -449,10 +449,12 @@ class Coverage(object): if dunder_file: filename = self._source_for_file(dunder_file) if original_filename and not original_filename.startswith('<'): - if os.path.basename(original_filename) != os.path.basename(filename): + orig = os.path.basename(original_filename) + if orig != os.path.basename(filename): # Files shouldn't be renamed when moved. This happens when - # exec'ing code, not sure why yet. - self._warn("File was renamed?: %r became %r" % (original_filename, filename)) + # exec'ing code. If it seems like something is wrong with + # the frame's filename, then just use the original. + filename = original_filename if not filename: # Empty string is pretty useless. -- cgit v1.2.1 From 07d978ab2220b2ee5b6c4e116783d8a313cbf46b Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 11 Jul 2015 11:13:52 -0400 Subject: The use_cache method is no longer supported. --- coverage/control.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 91365e1..7fc1170 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -601,13 +601,10 @@ class Coverage(object): sys.stderr.write("Coverage.py warning: %s\n" % msg) def use_cache(self, usecache): - """Control the use of a data file (incorrectly called a cache). - - `usecache` is true or false, whether to read and write data on disk. - - """ + """Obsolete method.""" self._init() - self.data.usefile(usecache) + if not usecache: + self._warn("use_cache(False) is no longer supported.") def load(self): """Load previously-collected coverage data from the data file.""" -- cgit v1.2.1 From 69f9797b9e8da52c649cadd0c240775af21a163f Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 11 Jul 2015 12:07:14 -0400 Subject: Analysis doesn't need a Coverage object, it needs a CoverageData object. --- coverage/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 7fc1170..56ce7c9 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -848,7 +848,7 @@ class Coverage(object): if not isinstance(it, FileReporter): it = self._get_file_reporter(it) - return Analysis(self, it) + return Analysis(self.data, it) def _get_file_reporter(self, morf): """Get a FileReporter for a module or filename.""" -- cgit v1.2.1 From ca28146789b130435e1fe583ccf668fcb0c53b4e Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 11 Jul 2015 17:18:36 -0400 Subject: Split off CoverageDataFiles from CoverageData --- coverage/control.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 56ce7c9..43f0790 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -14,7 +14,7 @@ from coverage.annotate import AnnotateReporter from coverage.backward import string_class, iitems from coverage.collector import Collector from coverage.config import CoverageConfig -from coverage.data import CoverageData +from coverage.data import CoverageData, CoverageDataFiles from coverage.debug import DebugControl from coverage.files import TreeMatcher, FnmatchMatcher from coverage.files import PathAliases, find_python_files, prep_patterns @@ -171,7 +171,7 @@ class Coverage(object): # Other instance attributes, set later. self.omit = self.include = self.source = None self.source_pkgs = None - self.data = self.collector = None + self.data = self.data_files = self.collector = None self.plugins = None self.pylib_dirs = self.cover_dirs = None self.data_suffix = self.run_suffix = None @@ -271,8 +271,10 @@ class Coverage(object): # data file will be written into the directory where the process # started rather than wherever the process eventually chdir'd to. self.data = CoverageData( - basename=self.config.data_file, collector="coverage v%s" % __version__, + ) + self.data_files = CoverageDataFiles( + basename=self.config.data_file, debug=self.debug, ) @@ -610,7 +612,7 @@ class Coverage(object): """Load previously-collected coverage data from the data file.""" self._init() self.collector.reset() - self.data.read() + self.data_files.read(self.data) def start(self): """Start measuring code coverage. @@ -657,6 +659,7 @@ class Coverage(object): self._init() self.collector.reset() self.data.erase() + self.data_files.erase() def clear_exclude(self, which='exclude'): """Clear the exclude list.""" @@ -725,7 +728,7 @@ class Coverage(object): ) self._harvest_data() - self.data.write(suffix=data_suffix) + self.data_files.write(self.data, suffix=data_suffix) def combine(self, data_dirs=None): """Combine together a number of similarly-named coverage data files. @@ -747,7 +750,7 @@ class Coverage(object): result = paths[0] for pattern in paths[1:]: aliases.add(pattern, result) - self.data.combine_parallel_data(aliases=aliases, data_dirs=data_dirs) + self.data_files.combine_parallel_data(self.data, aliases=aliases, data_dirs=data_dirs) def _harvest_data(self): """Get the collected data and reset the collector. @@ -1046,7 +1049,7 @@ class Coverage(object): ('plugins.file_tracers', ft_plugins), ('config_files', self.config.attempted_config_files), ('configs_read', self.config.config_files), - ('data_path', self.data.filename), + ('data_path', self.data_files.filename), ('python', sys.version.replace('\n', '')), ('platform', platform.platform()), ('implementation', implementation), -- cgit v1.2.1 From a2742dd17a0536eddba983e6716a4931ce0d9fe0 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 11 Jul 2015 17:23:07 -0400 Subject: Clean up the unused debug argument to CoverageDataFiles --- coverage/control.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 43f0790..2217006 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -273,10 +273,7 @@ class Coverage(object): self.data = CoverageData( collector="coverage v%s" % __version__, ) - self.data_files = CoverageDataFiles( - basename=self.config.data_file, - debug=self.debug, - ) + self.data_files = CoverageDataFiles(basename=self.config.data_file) # The dirs for files considered "installed with the interpreter". self.pylib_dirs = set() -- cgit v1.2.1 From 3eed96c1321c23b7fb578827fe1fb75d16bbde9a Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 11 Jul 2015 20:21:21 -0400 Subject: Coverage._harvest_data is now Coverage.get_data --- coverage/control.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 2217006..4097601 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -724,7 +724,7 @@ class Coverage(object): random.randint(0, 999999) ) - self._harvest_data() + self.get_data() self.data_files.write(self.data, suffix=data_suffix) def combine(self, data_dirs=None): @@ -749,11 +749,14 @@ class Coverage(object): aliases.add(pattern, result) self.data_files.combine_parallel_data(self.data, aliases=aliases, data_dirs=data_dirs) - def _harvest_data(self): + def get_data(self): """Get the collected data and reset the collector. Also warn about various problems collecting data. + Returns: + :class:`CoverageData`: the collected coverage data. + """ self._init() if not self._measured: @@ -804,6 +807,7 @@ class Coverage(object): self.data.touch_file(py_file) self._measured = False + return self.data # Backward compatibility with version 1. def analysis(self, morf): @@ -844,7 +848,7 @@ class Coverage(object): Returns an `Analysis` object. """ - self._harvest_data() + self.get_data() if not isinstance(it, FileReporter): it = self._get_file_reporter(it) @@ -915,7 +919,7 @@ class Coverage(object): Returns a float, the total percentage covered. """ - self._harvest_data() + self.get_data() self.config.from_args( ignore_errors=ignore_errors, omit=omit, include=include, show_missing=show_missing, skip_covered=skip_covered, @@ -937,7 +941,7 @@ class Coverage(object): See `coverage.report()` for other arguments. """ - self._harvest_data() + self.get_data() self.config.from_args( ignore_errors=ignore_errors, omit=omit, include=include ) @@ -963,7 +967,7 @@ class Coverage(object): Returns a float, the total percentage covered. """ - self._harvest_data() + self.get_data() self.config.from_args( ignore_errors=ignore_errors, omit=omit, include=include, html_dir=directory, extra_css=extra_css, html_title=title, @@ -987,7 +991,7 @@ class Coverage(object): Returns a float, the total percentage covered. """ - self._harvest_data() + self.get_data() self.config.from_args( ignore_errors=ignore_errors, omit=omit, include=include, xml_output=outfile, -- cgit v1.2.1 From f0f5f4d942574c50604658c851c80782908df7eb Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 12 Jul 2015 13:41:54 -0400 Subject: More reworking of the data api --- coverage/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 4097601..412f7ae 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -860,7 +860,7 @@ class Coverage(object): if isinstance(morf, string_class): abs_morf = abs_file(morf) - plugin_name = self.data.plugin_data().get(abs_morf) + plugin_name = self.data.plugin_name(abs_morf) if plugin_name: plugin = self.plugins.get(plugin_name) -- cgit v1.2.1 From 64754bc5b434543b6d7ff7d6d2d4ede6def03990 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 12 Jul 2015 20:40:38 -0400 Subject: More simplification of the data api --- coverage/control.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 412f7ae..84d5d03 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -767,9 +767,9 @@ class Coverage(object): return dict((abs_file(k), v) for k,v in iitems(d)) # TODO: seems like this parallel structure is getting kinda old... - self.data.add_line_data(abs_file_dict(self.collector.get_line_data())) - self.data.add_arc_data(abs_file_dict(self.collector.get_arc_data())) - self.data.add_plugin_data(abs_file_dict(self.collector.get_plugin_data())) + self.data.add_lines(abs_file_dict(self.collector.get_line_data())) + self.data.add_arcs(abs_file_dict(self.collector.get_arc_data())) + self.data.add_plugins(abs_file_dict(self.collector.get_plugin_data())) self.collector.reset() # If there are still entries in the source_pkgs list, then we never -- cgit v1.2.1 From 7358802affc00c6819ccb864ecf233fbf849a806 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Wed, 15 Jul 2015 20:11:34 -0400 Subject: Move suffix logic into data.py --- coverage/control.py | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 84d5d03..ca3660a 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -4,8 +4,6 @@ import atexit import inspect import os import platform -import random -import socket import sys import traceback @@ -283,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, os, platform, random, socket, _structseq): + for m in (atexit, 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__'): @@ -708,24 +706,8 @@ class Coverage(object): def save(self): """Save the collected coverage data to the data file.""" self._init() - data_suffix = self.data_suffix - if data_suffix is True: - # If data_suffix was a simple true value, then make a suffix with - # plenty of distinguishing information. We do this here in - # `save()` at the last minute so that the pid will be correct even - # if the process forks. - extra = "" - if _TEST_NAME_FILE: # pragma: debugging - with open(_TEST_NAME_FILE) as f: - test_name = f.read() - extra = "." + test_name - data_suffix = "%s%s.%s.%06d" % ( - socket.gethostname(), extra, os.getpid(), - random.randint(0, 999999) - ) - self.get_data() - self.data_files.write(self.data, suffix=data_suffix) + self.data_files.write(self.data, suffix=self.data_suffix) def combine(self, data_dirs=None): """Combine together a number of similarly-named coverage data files. @@ -1159,7 +1141,3 @@ def process_startup(): cov.start() cov._warn_no_data = False cov._warn_unimported_source = False - - -# A hack for debugging testing in sub-processes. -_TEST_NAME_FILE = "" # "/tmp/covtest.txt" -- cgit v1.2.1 From 7ba0ddecf52511fefcf618c11a85baddab132be4 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 16 Jul 2015 15:40:23 -0400 Subject: Add a boolean interpretation of CoverageData. --- coverage/control.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index ca3660a..7c14e1b 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -772,8 +772,7 @@ class Coverage(object): ) # Find out if we got any data. - summary = self.data.summary() - if not summary and self._warn_no_data: + if not self.data and self._warn_no_data: self._warn("No data was collected.") # Find files that were never executed at all. -- cgit v1.2.1 From f749a4bd0a01b452e3378cf85c8e760be9bb1ade Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 18 Jul 2015 14:09:54 -0400 Subject: Refactor collector->data; data has only one of lines and arcs. Now the collector communicates directly with the data, and control is less involved. In the data, when measuring arcs, only arcs are stored. Lines are calculated as needed. This saves space in the data file, and is faster. --- coverage/control.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 7c14e1b..3f6f5ac 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -744,15 +744,7 @@ class Coverage(object): if not self._measured: return - 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)) - - # TODO: seems like this parallel structure is getting kinda old... - self.data.add_lines(abs_file_dict(self.collector.get_line_data())) - self.data.add_arcs(abs_file_dict(self.collector.get_arc_data())) - self.data.add_plugins(abs_file_dict(self.collector.get_plugin_data())) - self.collector.reset() + self.collector.save_data(self.data) # If there are still entries in the source_pkgs list, then we never # encountered those packages. -- cgit v1.2.1 From caae3057c6e8ac32ca7a6e306d131f181df8686f Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Mon, 20 Jul 2015 17:49:39 -0400 Subject: Add docs to CoverageData. --- coverage/control.py | 1 + 1 file changed, 1 insertion(+) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 3f6f5ac..9ccd3b2 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -270,6 +270,7 @@ class Coverage(object): # started rather than wherever the process eventually chdir'd to. self.data = CoverageData( collector="coverage v%s" % __version__, + debug=self.debug, ) self.data_files = CoverageDataFiles(basename=self.config.data_file) -- cgit v1.2.1 From 77d826ef74d4602730cea5c4ac4a440cfbeb3303 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 21 Jul 2015 09:29:39 -0400 Subject: Remove CoverageData(collector=), we'll do it differently soon. --- coverage/control.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 9ccd3b2..e1931a5 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -268,10 +268,7 @@ class Coverage(object): # Create the data file. We do this at construction time so that the # data file will be written into the directory where the process # started rather than wherever the process eventually chdir'd to. - self.data = CoverageData( - collector="coverage v%s" % __version__, - debug=self.debug, - ) + self.data = CoverageData(debug=self.debug) self.data_files = CoverageDataFiles(basename=self.config.data_file) # The dirs for files considered "installed with the interpreter". -- cgit v1.2.1 From d6a7a11f8c5a8e73a9dfd9a1ce602df775d04586 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 23 Jul 2015 21:22:30 -0400 Subject: Refer to the project consistenly as coverage.py. #275 --- coverage/control.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index e1931a5..ef9b8f1 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -293,13 +293,13 @@ class Coverage(object): structseq_file = structseq_new.__code__.co_filename self.pylib_dirs.add(self._canonical_dir(structseq_file)) - # To avoid tracing the coverage code itself, we skip anything located - # where we are. + # To avoid tracing the coverage.py code itself, we skip anything + # located where we are. self.cover_dirs = [self._canonical_dir(__file__)] if env.TESTING: # When testing, we use PyContracts, which should be considered - # part of coverage, and it uses six. Exclude those directories just - # as we exclude ourselves. + # part of coverage.py, and it uses six. Exclude those directories + # just as we exclude ourselves. import contracts, six for mod in [contracts, six]: self.cover_dirs.append(self._canonical_dir(mod)) @@ -549,8 +549,8 @@ class Coverage(object): if self.pylib_match and self.pylib_match.match(filename): return "is in the stdlib" - # We exclude the coverage code itself, since a little of it will be - # measured otherwise. + # We exclude the coverage.py code itself, since a little of it + # will be measured otherwise. if self.cover_match and self.cover_match.match(filename): return "is part of coverage.py" @@ -1114,7 +1114,7 @@ def process_startup(): # because some virtualenv configurations make the same directory visible # twice in sys.path. This means that the .pth file will be found twice, # and executed twice, executing this function twice. We set a global - # flag (an attribute on this function) to indicate that coverage has + # flag (an attribute on this function) to indicate that coverage.py has # already been started, so we can avoid doing it twice. # # https://bitbucket.org/ned/coveragepy/issue/340/keyerror-subpy has more @@ -1122,7 +1122,7 @@ def process_startup(): if hasattr(process_startup, "done"): # We've annotated this function before, so we must have already - # started coverage in this process. Nothing to do. + # started coverage.py in this process. Nothing to do. return process_startup.done = True -- cgit v1.2.1 From dc0d0c613de54cd5af74a1d3ac9d86235dc0aee9 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 24 Jul 2015 10:43:46 -0400 Subject: Add license mention to the top of all files. #313. --- coverage/control.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index ef9b8f1..d565013 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -1,4 +1,7 @@ -"""Core control stuff for Coverage.""" +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt + +"""Core control stuff for coverage.py.""" import atexit import inspect -- cgit v1.2.1 From 7d968589567efd3e6e8765f7b1605e2e6d7f1ba0 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 24 Jul 2015 12:21:15 -0400 Subject: Use more specific names than 'plugins', since there will be more of them in the future. --- coverage/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index d565013..48ee47b 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -834,7 +834,7 @@ class Coverage(object): if isinstance(morf, string_class): abs_morf = abs_file(morf) - plugin_name = self.data.plugin_name(abs_morf) + plugin_name = self.data.file_tracer(abs_morf) if plugin_name: plugin = self.plugins.get(plugin_name) -- cgit v1.2.1 From 63ddb1b6a615d956fb7305adab7fcc7e876ffffb Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 25 Jul 2015 07:14:10 -0400 Subject: No need to conditionalize python_implementation any more. --- coverage/control.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 48ee47b..16cf74e 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -1003,10 +1003,6 @@ class Coverage(object): import coverage as covmod self._init() - try: - implementation = platform.python_implementation() - except AttributeError: - implementation = "unknown" ft_plugins = [] for ft in self.plugins.file_tracers: @@ -1027,7 +1023,7 @@ class Coverage(object): ('data_path', self.data_files.filename), ('python', sys.version.replace('\n', '')), ('platform', platform.platform()), - ('implementation', implementation), + ('implementation', platform.python_implementation()), ('executable', sys.executable), ('cwd', os.getcwd()), ('path', sys.path), -- cgit v1.2.1 From c8d2b60b40bdc459280b3dafa40fb42ae57e4a3a Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 25 Jul 2015 07:57:01 -0400 Subject: Experiment with run information stored in the data file. --- coverage/control.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 16cf74e..13261de 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 -- cgit v1.2.1 From fd2284632777a235ac663b7b9912246b30bc538b Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 26 Jul 2015 06:56:58 -0400 Subject: Get rid of napoleon style docstrings, they don't format nicely. --- coverage/control.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 13261de..a9d5cb4 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -736,8 +736,7 @@ class Coverage(object): Also warn about various problems collecting data. - Returns: - :class:`CoverageData`: the collected coverage data. + Returns a :class:`CoverageData`, the collected coverage data. """ self._init() -- cgit v1.2.1 From cebcf636b2b092e95796ae18d2dda0a485c9cec8 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 26 Jul 2015 08:26:53 -0400 Subject: Write just one short string to run_info --- coverage/control.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index a9d5cb4..86c40b4 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -4,7 +4,6 @@ """Core control stuff for coverage.py.""" import atexit -import datetime import inspect import os import platform @@ -281,7 +280,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, datetime, inspect, os, platform, _structseq, traceback): + for m in (atexit, 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__'): @@ -782,12 +781,11 @@ class Coverage(object): 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(), + system=" ".join([ + platform.python_implementation(), + platform.python_version(), + platform.system(), + ]) ) self._measured = False -- cgit v1.2.1 From 6e3d5fa212ef7d6c9694e0c118f9c94a8711e150 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 26 Jul 2015 09:11:38 -0400 Subject: Call it brief_sys to avoid collision with other names --- coverage/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 86c40b4..2ad0db0 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -781,7 +781,7 @@ class Coverage(object): from coverage import __version__ self.data.add_run_info( - system=" ".join([ + brief_sys=" ".join([ platform.python_implementation(), platform.python_version(), platform.system(), -- cgit v1.2.1 From 5c98172ff46513e182196b59b2b432b416ce2010 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 26 Jul 2015 15:03:11 -0400 Subject: New config option: run:note lets you annotate the data file. --- coverage/control.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 2ad0db0..8a671fe 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -788,6 +788,9 @@ class Coverage(object): ]) ) + if self.config.note: + self.data.add_run_info(note=self.config.note) + self._measured = False return self.data -- cgit v1.2.1 From 7397bb2a2f4f2dcbe7804d0abaf5aafcb73cf182 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Wed, 29 Jul 2015 20:07:55 -0400 Subject: Remove an unneeded import. --- coverage/control.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 8a671fe..76960a4 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -778,8 +778,6 @@ class Coverage(object): self.data.touch_file(py_file) # Add run information. - from coverage import __version__ - self.data.add_run_info( brief_sys=" ".join([ platform.python_implementation(), -- cgit v1.2.1 From 7f0e87b3e2a99968e7e49eb8b7d2231b801b7da9 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 30 Jul 2015 07:13:45 -0400 Subject: Refactoring cmdline in prep for getting --append to work again. --- coverage/control.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 76960a4..80bd853 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -721,6 +721,7 @@ class Coverage(object): """ self._init() + aliases = None if self.config.paths: aliases = PathAliases() @@ -728,6 +729,7 @@ class Coverage(object): result = paths[0] for pattern in paths[1:]: aliases.add(pattern, result) + self.data_files.combine_parallel_data(self.data, aliases=aliases, data_dirs=data_dirs) def get_data(self): -- cgit v1.2.1 From e812f4dd7e82a9de6323b139c9ae3e02cd16d7f0 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 30 Jul 2015 07:34:37 -0400 Subject: Clean up from the merge of PR 62 Remove the globbing option. Added a test. Corrected parameter names and docs. Updated the AUTHORS file. --- coverage/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 80bd853..deeeae4 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -730,7 +730,7 @@ class Coverage(object): for pattern in paths[1:]: aliases.add(pattern, result) - self.data_files.combine_parallel_data(self.data, aliases=aliases, data_dirs=data_dirs) + self.data_files.combine_parallel_data(self.data, aliases=aliases, data_paths=data_dirs) def get_data(self): """Get the collected data and reset the collector. -- cgit v1.2.1 From 8b9ba53c845a304dfddc5a78cf0107365edc505d Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 30 Jul 2015 10:10:08 -0400 Subject: Get --append working again. --- coverage/control.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index deeeae4..8e51c2c 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -708,19 +708,21 @@ class Coverage(object): self.get_data() self.data_files.write(self.data, suffix=self.data_suffix) - def combine(self, data_dirs=None): + def combine(self, data_paths=None): """Combine together a number of similarly-named coverage data files. All coverage data files whose name starts with `data_file` (from the coverage() constructor) will be read, and combined together into the current measurements. - `data_dirs` is a list of directories from which data files should be - combined. If no list is passed, then the data files from the current - directory will be combined. + `data_paths` is a list of files or directories from which data should + be combined. If no list is passed, then the data files from the + directory indicated by the current data file (probably the current + directory) will be combined. """ self._init() + self.get_data() aliases = None if self.config.paths: @@ -730,7 +732,7 @@ class Coverage(object): for pattern in paths[1:]: aliases.add(pattern, result) - self.data_files.combine_parallel_data(self.data, aliases=aliases, data_paths=data_dirs) + self.data_files.combine_parallel_data(self.data, aliases=aliases, data_paths=data_paths) def get_data(self): """Get the collected data and reset the collector. -- cgit v1.2.1 From 74fb855535ade275af20f2afc8097ff9723a0831 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 30 Jul 2015 21:54:39 -0400 Subject: Erasing in parallel mode now deletes all the data files. #262 --- coverage/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 8e51c2c..3ff7e2a 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -653,7 +653,7 @@ class Coverage(object): self._init() self.collector.reset() self.data.erase() - self.data_files.erase() + self.data_files.erase(parallel=self.config.parallel) def clear_exclude(self, which='exclude'): """Clear the exclude list.""" -- cgit v1.2.1 From 7756e176258fb96525f1e90ee4995c65b099b81a Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 1 Aug 2015 08:00:02 -0400 Subject: Implement FileDisposition in C for speed. Final part of fix for #387. --- coverage/control.py | 60 +++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 3ff7e2a..4396374 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -427,7 +427,7 @@ class Coverage(object): """ original_filename = filename - disp = FileDisposition(filename) + disp = _disposition_init(self.collector.file_disposition_class, filename) def nope(disp, reason): """Simple helper to make it easy to return NO.""" @@ -570,7 +570,7 @@ class Coverage(object): """ disp = self._should_trace_internal(filename, frame) if self.debug.should('trace'): - self.debug.write(disp.debug_message()) + self.debug.write(_disposition_debug_msg(disp)) return disp def _check_include_omit_etc(self, filename, frame): @@ -1065,36 +1065,32 @@ class Coverage(object): return info -class FileDisposition(object): - """A simple object for noting a number of details of files to trace.""" - def __init__(self, original_filename): - self.original_filename = original_filename - self.canonical_filename = original_filename - self.source_filename = None - self.trace = False - self.reason = "" - self.file_tracer = None - self.has_dynamic_filename = False - - def __repr__(self): - ret = "FileDisposition %r" % (self.original_filename,) - if self.trace: - ret += " trace" - else: - ret += " notrace=%r" % (self.reason,) - if self.file_tracer: - ret += " file_tracer=%r" % (self.file_tracer,) - return "<" + ret + ">" - - def debug_message(self): - """Produce a debugging message explaining the outcome.""" - if self.trace: - msg = "Tracing %r" % (self.original_filename,) - if self.file_tracer: - msg += ": will be traced by %r" % self.file_tracer - else: - msg = "Not tracing %r: %s" % (self.original_filename, self.reason) - return msg +# FileDisposition "methods": FileDisposition is a pure value object, so it can +# be implemented in either C or Python. Acting on them is done with these +# functions. + +def _disposition_init(cls, original_filename): + """Construct and initialize a new FileDisposition object.""" + disp = cls() + disp.original_filename = original_filename + disp.canonical_filename = original_filename + disp.source_filename = None + disp.trace = False + disp.reason = "" + disp.file_tracer = None + disp.has_dynamic_filename = False + return disp + + +def _disposition_debug_msg(disp): + """Make a nice debug message of what the FileDisposition is doing.""" + if disp.trace: + msg = "Tracing %r" % (disp.original_filename,) + if disp.file_tracer: + msg += ": will be traced by %r" % disp.file_tracer + else: + msg = "Not tracing %r: %s" % (disp.original_filename, disp.reason) + return msg def process_startup(): -- cgit v1.2.1 From 9559181fa49011bc94e51c967010e2cb49714d15 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 1 Aug 2015 12:42:04 -0400 Subject: Plugins can get built-in python reporting. --- coverage/control.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'coverage/control.py') diff --git a/coverage/control.py b/coverage/control.py index 4396374..4837356 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -844,6 +844,7 @@ class Coverage(object): def _get_file_reporter(self, morf): """Get a FileReporter for a module or filename.""" plugin = None + file_reporter = "python" if isinstance(morf, string_class): abs_morf = abs_file(morf) @@ -859,7 +860,8 @@ class Coverage(object): plugin._coverage_plugin_name, morf ) ) - else: + + if file_reporter == "python": file_reporter = PythonFileReporter(morf, self) return file_reporter -- cgit v1.2.1