summaryrefslogtreecommitdiff
path: root/coverage
diff options
context:
space:
mode:
Diffstat (limited to 'coverage')
-rw-r--r--coverage/control.py23
-rw-r--r--coverage/misc.py23
-rw-r--r--coverage/plugin_support.py70
3 files changed, 65 insertions, 51 deletions
diff --git a/coverage/control.py b/coverage/control.py
index e4e67d3a..1dbf0672 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),
diff --git a/coverage/misc.py b/coverage/misc.py
index 0dad0559..21b7333c 100644
--- a/coverage/misc.py
+++ b/coverage/misc.py
@@ -158,29 +158,6 @@ class Hasher(object):
return self.md5.hexdigest()
-def overrides(obj, method_name, base_class):
- """Does `obj` override the `method_name` it got from `base_class`?
-
- Determine if `obj` implements the method called `method_name`, which it
- inherited from `base_class`.
-
- Returns a boolean.
-
- """
- klass = obj.__class__
- klass_func = getattr(klass, method_name)
- base_func = getattr(base_class, method_name)
-
- # Python 2/3 compatibility: Python 2 returns an instancemethod object, the
- # function is the .im_func attribute. Python 3 returns a plain function
- # object already.
- if env.PY2:
- klass_func = klass_func.im_func
- base_func = base_func.im_func
-
- return klass_func is not base_func
-
-
# TODO: abc?
def _needs_to_implement(that, func_name):
"""Helper to raise NotImplementedError in interface stubs."""
diff --git a/coverage/plugin_support.py b/coverage/plugin_support.py
index 4f22c137..ae72f797 100644
--- a/coverage/plugin_support.py
+++ b/coverage/plugin_support.py
@@ -13,6 +13,10 @@ class Plugins(object):
def __init__(self):
self.order = []
self.names = {}
+ self.file_tracers = []
+
+ self.current_module = None
+ self.debug = None
@classmethod
def load_plugins(cls, modules, config, debug=None):
@@ -22,30 +26,68 @@ class Plugins(object):
"""
plugins = cls()
+ plugins.debug = debug
for module in modules:
+ plugins.current_module = module
__import__(module)
mod = sys.modules[module]
- plugin_class = getattr(mod, "Plugin", None)
- if not plugin_class:
- raise CoverageException("Plugin module %r didn't define a Plugin class" % module)
+ coverage_init = getattr(mod, "coverage_init", None)
+ if not coverage_init:
+ raise CoverageException(
+ "Plugin module %r didn't define a coverage_init function" % module
+ )
options = config.get_plugin_options(module)
- plugin = plugin_class(options)
- if debug and debug.should('plugin'):
- debug.write("Loaded plugin %r: %r" % (module, plugin))
- labelled = LabelledDebug("plugin %r" % (module,), debug)
- plugin = DebugPluginWrapper(plugin, labelled)
-
- # pylint: disable=attribute-defined-outside-init
- plugin._coverage_plugin_name = module
- plugin._coverage_enabled = True
- plugins.order.append(plugin)
- plugins.names[module] = plugin
+ coverage_init(plugins, options)
+ plugins.current_module = None
return plugins
+ def add_file_tracer(self, plugin):
+ """Add a file tracer plugin.
+
+ ``plugin`` must implement the :meth:`CoveragePlugin.file_tracer` method.
+
+ """
+ self._add_plugin(plugin, self.file_tracers)
+
+ def add_noop(self, plugin):
+ """Add a plugin that does nothing.
+
+ This is only useful for testing the plugin support.
+
+ """
+ self._add_plugin(plugin, None)
+
+ def _add_plugin(self, plugin, specialized):
+ """Add a plugin object.
+
+ Arguments:
+ plugin (CoveragePlugin): the plugin to add.
+
+ specialized (list): the list of plugins to add this to.
+
+ Returns:
+ plugin: may be a different object than passed in.
+
+ """
+ plugin_name = "%s.%s" % (self.current_module, plugin.__class__.__name__)
+ if self.debug and self.debug.should('plugin'):
+ self.debug.write("Loaded plugin %r: %r" % (self.current_module, plugin))
+ labelled = LabelledDebug("plugin %r" % (self.current_module,), self.debug)
+ plugin = DebugPluginWrapper(plugin, labelled)
+
+ # pylint: disable=attribute-defined-outside-init
+ plugin._coverage_plugin_name = plugin_name
+ plugin._coverage_enabled = True
+ self.order.append(plugin)
+ self.names[plugin_name] = plugin
+ if specialized is not None:
+ specialized.append(plugin)
+ return plugin
+
def __nonzero__(self):
return bool(self.order)