apetest.plugin
module
APE's plugin infrastructure.
Each plugin is a separate module in the apetest.plugin
package.
Plugins can register command line options by defining the
following function:
def plugin_arguments(parser):
parser.add_argument('--cow', help='fetchez la vache')
The parser
argument is an instance of argparse.ArgumentParser
.
See the argparse
documentation for a detailed description of what
kind of argument parsing it supports.
It is not mandatory to implement plugin_arguments()
, but in general
plugins should not activate automatically, so there should at least
be a command line argument to enable them.
To instantiate plugins, the plugin module must define the following function:
def plugin_create(args):
if args.cow is not None:
yield CatapultPlugin(args.cow)
args
is an argparse.Namespace
that contains the result of the
command line parsing.
Each yielded object must implement the Plugin
interface.
If one of the requested plugins cannot be created, PluginError
should
be raised with a message that is meaningful to the end user.
Source code
# SPDX-License-Identifier: BSD-3-Clause
"""APE's plugin infrastructure.
Each plugin is a separate module in the `apetest.plugin` package.
Plugins can register command line options by defining the
following function:
def plugin_arguments(parser):
parser.add_argument('--cow', help='fetchez la vache')
The ``parser`` argument is an instance of `argparse.ArgumentParser`.
See the `argparse` documentation for a detailed description of what
kind of argument parsing it supports.
It is not mandatory to implement ``plugin_arguments()``, but in general
plugins should not activate automatically, so there should at least
be a command line argument to enable them.
To instantiate plugins, the plugin module must define the
following function:
def plugin_create(args):
if args.cow is not None:
yield CatapultPlugin(args.cow)
`args` is an `argparse.Namespace` that contains the result of the
command line parsing.
Each yielded object must implement the `Plugin` interface.
If one of the requested plugins cannot be created, `PluginError` should
be raised with a message that is meaningful to the end user.
"""
from importlib import import_module
from logging import getLogger
from pkgutil import iter_modules
_LOG = getLogger(__name__)
class PluginError(Exception):
"""A plugin module can raise this in `plugin_create` when it fails
to create the `Plugin` instances requested by the command line
arguments.
"""
class Plugin:
"""Plugin interface: your plugin class should inherit this and override
one or more methods.
"""
def close(self):
"""Tells the plugin to release any resources (processes, sockets
etc.) that it may have acquired.
There will not be any more calls to the plugin after it is closed.
The default implementation does nothing.
"""
def resource_loaded(self, data, content_type_header, report):
"""Called when a resource has been loaded.
Parameters:
data: bytes
The resource contents.
content_type_header: str
The HTTP `Content-Type` header received for this resource,
including `charset` if the server sent it.
report: apetest.report.Report
Report to which problems found in the resource can be logged.
Plugins can override this method to perform checks on the raw
resource data. The default implementation does nothing.
"""
def report_added(self, report):
"""Called when a `apetest.report.Report` has been finished.
Plugins can override this method to act on the report data.
The default implementation does nothing.
"""
def postprocess(self, scribe):
"""Called when the test run has finished.
Plugins can override this method to process the results.
The default implementation does nothing.
"""
class PluginCollection:
"""Keeps a collection of `Plugin` instances and dispatches calls to
each of them.
"""
def __init__(self, plugins):
"""Initialize a collection containing `plugins`."""
self.plugins = tuple(plugins)
def __getattr__(self, name):
if hasattr(Plugin, name):
return self.__dispatch(name)
else:
raise AttributeError(name)
def __dispatch(self, name):
def dispatch(*args, **kvargs):
for plugin in self.plugins:
getattr(plugin, name)(*args, **kvargs)
return dispatch
def load_plugins():
"""Discover and import plugin modules.
Yields:
module
Imported plugin module.
Errors will be logged to the default logger.
"""
for finder_, name, ispkg_ in iter_modules(__path__, 'apetest.plugin.'):
try:
yield import_module(name)
except Exception: # pylint: disable=broad-except
_LOG.exception('Error importing plugin module "%s":', name)
def add_plugin_arguments(module, parser):
"""Ask a plugin module to register its command line arguments.
Parameters:
module
Plugin module.
parser: argparse.ArgumentParser
Command line parser on which arguments must be registered.
Errors will be logged to the default logger.
"""
try:
func = getattr(module, 'plugin_arguments')
except AttributeError:
_LOG.info('Plugin module "%s" does not implement plugin_arguments()',
module.__name__)
else:
try:
func(parser)
except Exception: # pylint: disable=broad-except
_LOG.exception('Error registering command line arguments for '
'plugin module "%s":', module.__name__)
def create_plugins(module, args):
"""Ask a plugin module to create `Plugin` objects according to
the command line arguments.
Parameters:
module
Plugin module.
args: argparse.Namespace
Parsed command line arguments.
Errors will be logged to the default logger.
Exceptions will be re-raised after logging.
"""
try:
func = getattr(module, 'plugin_create')
except AttributeError:
_LOG.error('Plugin module "%s" does not implement plugin_create()',
module.__name__)
raise
def _log_yield():
try:
yield from func(args)
except PluginError as ex:
_LOG.error('Could not instantiate plugin in module "%s": %s',
module.__name__, ex)
raise
except Exception: # pylint: disable=broad-except
_LOG.exception('Error instantiating plugin module "%s":',
module.__name__)
raise
for plugin in _log_yield():
if isinstance(plugin, Plugin):
yield plugin
else:
_LOG.error('Module "%s" created a plugin of type "%s", '
'which does not inherit from the Plugin class.',
module.__name__, plugin.__class__.__name__)
raise TypeError(plugin.__class__)}
Sub-modules
apetest.plugin.checkhtml
-
Plugin that checks HTML and optionally CSS …
apetest.plugin.controlcenter
-
Plugin that monitors the SoftFab Control Center's log while it is being tested …
apetest.plugin.softfab
-
Plugin that creates a properties file summarizing the test results …
Functions
def add_plugin_arguments(module, parser)
-
Ask a plugin module to register its command line arguments.
Parameters
module
- Plugin module.
parser
:argparse.ArgumentParser
- Command line parser on which arguments must be registered.
Errors will be logged to the default logger.
Source code
def add_plugin_arguments(module, parser): """Ask a plugin module to register its command line arguments. Parameters: module Plugin module. parser: argparse.ArgumentParser Command line parser on which arguments must be registered. Errors will be logged to the default logger. """ try: func = getattr(module, 'plugin_arguments') except AttributeError: _LOG.info('Plugin module "%s" does not implement plugin_arguments()', module.__name__) else: try: func(parser) except Exception: # pylint: disable=broad-except _LOG.exception('Error registering command line arguments for ' 'plugin module "%s":', module.__name__)}
def create_plugins(module, args)
-
Ask a plugin module to create
Plugin
objects according to the command line arguments.Parameters
module
- Plugin module.
args
:argparse.Namespace
- Parsed command line arguments.
Errors will be logged to the default logger. Exceptions will be re-raised after logging.
Source code
def create_plugins(module, args): """Ask a plugin module to create `Plugin` objects according to the command line arguments. Parameters: module Plugin module. args: argparse.Namespace Parsed command line arguments. Errors will be logged to the default logger. Exceptions will be re-raised after logging. """ try: func = getattr(module, 'plugin_create') except AttributeError: _LOG.error('Plugin module "%s" does not implement plugin_create()', module.__name__) raise def _log_yield(): try: yield from func(args) except PluginError as ex: _LOG.error('Could not instantiate plugin in module "%s": %s', module.__name__, ex) raise except Exception: # pylint: disable=broad-except _LOG.exception('Error instantiating plugin module "%s":', module.__name__) raise for plugin in _log_yield(): if isinstance(plugin, Plugin): yield plugin else: _LOG.error('Module "%s" created a plugin of type "%s", ' 'which does not inherit from the Plugin class.', module.__name__, plugin.__class__.__name__) raise TypeError(plugin.__class__)}
def load_plugins()
-
Discover and import plugin modules.
Yields
module
- Imported plugin module.
Errors will be logged to the default logger.
Source code
def load_plugins(): """Discover and import plugin modules. Yields: module Imported plugin module. Errors will be logged to the default logger. """ for finder_, name, ispkg_ in iter_modules(__path__, 'apetest.plugin.'): try: yield import_module(name) except Exception: # pylint: disable=broad-except _LOG.exception('Error importing plugin module "%s":', name)}
Classes
class Plugin
-
Plugin interface: your plugin class should inherit this and override one or more methods.
Source code
class Plugin: """Plugin interface: your plugin class should inherit this and override one or more methods. """ def close(self): """Tells the plugin to release any resources (processes, sockets etc.) that it may have acquired. There will not be any more calls to the plugin after it is closed. The default implementation does nothing. """ def resource_loaded(self, data, content_type_header, report): """Called when a resource has been loaded. Parameters: data: bytes The resource contents. content_type_header: str The HTTP `Content-Type` header received for this resource, including `charset` if the server sent it. report: apetest.report.Report Report to which problems found in the resource can be logged. Plugins can override this method to perform checks on the raw resource data. The default implementation does nothing. """ def report_added(self, report): """Called when a `apetest.report.Report` has been finished. Plugins can override this method to act on the report data. The default implementation does nothing. """ def postprocess(self, scribe): """Called when the test run has finished. Plugins can override this method to process the results. The default implementation does nothing. """}
Subclasses
Methods
def close(self)
-
Tells the plugin to release any resources (processes, sockets etc.) that it may have acquired.
There will not be any more calls to the plugin after it is closed. The default implementation does nothing.
Source code
def close(self): """Tells the plugin to release any resources (processes, sockets etc.) that it may have acquired. There will not be any more calls to the plugin after it is closed. The default implementation does nothing. """}
def postprocess(self, scribe)
-
Called when the test run has finished.
Plugins can override this method to process the results. The default implementation does nothing.
Source code
def postprocess(self, scribe): """Called when the test run has finished. Plugins can override this method to process the results. The default implementation does nothing. """}
def report_added(self, report)
-
Called when a
Report
has been finished.Plugins can override this method to act on the report data. The default implementation does nothing.
Source code
def report_added(self, report): """Called when a `apetest.report.Report` has been finished. Plugins can override this method to act on the report data. The default implementation does nothing. """}
def resource_loaded(self, data, content_type_header, report)
-
Called when a resource has been loaded.
Parameters
data
:bytes
- The resource contents.
content_type_header
:str
- The HTTP
Content-Type
header received for this resource, includingcharset
if the server sent it. report
:Report
- Report to which problems found in the resource can be logged.
Plugins can override this method to perform checks on the raw resource data. The default implementation does nothing.
Source code
def resource_loaded(self, data, content_type_header, report): """Called when a resource has been loaded. Parameters: data: bytes The resource contents. content_type_header: str The HTTP `Content-Type` header received for this resource, including `charset` if the server sent it. report: apetest.report.Report Report to which problems found in the resource can be logged. Plugins can override this method to perform checks on the raw resource data. The default implementation does nothing. """}
class PluginCollection
-
Keeps a collection of
Plugin
instances and dispatches calls to each of them.Source code
class PluginCollection: """Keeps a collection of `Plugin` instances and dispatches calls to each of them. """ def __init__(self, plugins): """Initialize a collection containing `plugins`.""" self.plugins = tuple(plugins) def __getattr__(self, name): if hasattr(Plugin, name): return self.__dispatch(name) else: raise AttributeError(name) def __dispatch(self, name): def dispatch(*args, **kvargs): for plugin in self.plugins: getattr(plugin, name)(*args, **kvargs) return dispatch}
Methods
def __init__(self, plugins)
-
Initialize a collection containing
plugins
.Source code
def __init__(self, plugins): """Initialize a collection containing `plugins`.""" self.plugins = tuple(plugins)}
class PluginError (ancestors: builtins.Exception, builtins.BaseException)
-
A plugin module can raise this in
plugin_create
when it fails to create thePlugin
instances requested by the command line arguments.Source code
class PluginError(Exception): """A plugin module can raise this in `plugin_create` when it fails to create the `Plugin` instances requested by the command line arguments. """}