summaryrefslogtreecommitdiff
path: root/coverage/plugin.py
diff options
context:
space:
mode:
Diffstat (limited to 'coverage/plugin.py')
-rw-r--r--coverage/plugin.py84
1 files changed, 65 insertions, 19 deletions
diff --git a/coverage/plugin.py b/coverage/plugin.py
index 84d81a28..35be41a9 100644
--- a/coverage/plugin.py
+++ b/coverage/plugin.py
@@ -8,16 +8,15 @@ class CoveragePlugin(object):
def __init__(self, options):
self.options = options
- def trace_judge(self):
- """Return a callable that can decide whether to trace a file or not.
+ def trace_judge(self, disposition):
+ """Decide whether to trace this file with this plugin.
- The callable should take a filename, and return a coverage.TraceDisposition
- object.
+ Set disposition.trace to True if this plugin should trace this file.
+ May also set other attributes in `disposition`.
"""
return None
- # TODO: why does trace_judge return a callable, but source_file_name is callable?
def source_file_name(self, filename):
"""Return the source name for a given Python filename.
@@ -39,24 +38,71 @@ class CoveragePlugin(object):
"""
return None
+ def code_unit_class(self, morf):
+ """Return the CodeUnit class to use for a module or filename."""
+ return None
+
+
+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()
-def load_plugins(modules, config):
- """Load plugins from `modules`.
+ for module in modules:
+ __import__(module)
+ mod = sys.modules[module]
- Returns a list of loaded and configured plugins.
+ plugin_class = getattr(mod, "Plugin", None)
+ if plugin_class:
+ options = config.get_plugin_options(module)
+ plugin = plugin_class(options)
+ plugin.__name__ = module
+ plugins.order.append(plugin)
+ plugins.names[module] = plugin
+
+ return plugins
+
+ def __iter__(self):
+ return iter(self.order)
+
+ def get(self, module):
+ return self.names[module]
+
+
+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.
"""
- plugins = []
+ 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 sys.version_info < (3, 0):
+ klass_func = klass_func.im_func
+ base_func = base_func.im_func
- for module in modules:
- __import__(module)
- mod = sys.modules[module]
+ return klass_func is not base_func
- plugin_class = getattr(mod, "Plugin", None)
- if plugin_class:
- options = config.get_plugin_options(module)
- plugin = plugin_class(options)
- plugin.__name__ = module
- plugins.append(plugin)
- return plugins
+def plugin_implements(obj, method_name):
+ """Does the plugin `obj` implement `method_name`?"""
+ return overrides(obj, method_name, CoveragePlugin)