sopel.plugins.handlers#
Sopel’s plugin handlers.
New in version 7.0.
Between a plugin (or “module”) and Sopel’s core, Plugin Handlers are used. It
is an interface (defined by the AbstractPluginHandler
abstract class),
that acts as a proxy between Sopel and the plugin, making a clear separation
between how the bot behaves and how the plugins work.
From the Sopel
class, a plugin must be:
loaded, using
load()
setup (if required), using
setup()
and eventually registered using
register()
Each subclass of AbstractPluginHandler
must implement its methods in
order to be used in the application.
At the moment, three types of plugin are handled:
PyModulePlugin
: manages plugins that can be imported as Python module from a Python package, i.e. wherefrom package import name
worksPyFilePlugin
: manages plugins that are Python files on the filesystem or Python directory (with an__init__.py
file inside), that cannot be directly imported and extra steps are necessaryEntryPointPlugin
: manages plugins that are declared by an entry point; it otherwise behaves like aPyModulePlugin
All expose the same interface and thereby abstract the internal implementation away from the rest of the application.
Important
This is all relatively new. Its usage and documentation is for Sopel core development and advanced developers. It is subject to rapid changes between versions without much (or any) warning.
Do not build your plugin based on what is here, you do not need to.
- class sopel.plugins.handlers.AbstractPluginHandler#
Base class for plugin handlers.
This abstract class defines the interface Sopel uses to configure, load, shutdown, etc. a Sopel plugin (or “module”).
It is through this interface that Sopel will interact with its plugins, whether internal (from
sopel.builtins
) or external (from the Python files in a directory, tosopel_modules.*
subpackages).Sopel’s loader will create a “Plugin Handler” for each plugin it finds, to which it then delegates loading the plugin, listing its functions (commands, jobs, etc.), configuring it, and running any required actions on shutdown (either upon exiting Sopel or unloading that plugin).
- abstract configure(settings)#
Configure Sopel’s
settings
for this plugin.- Parameters:
settings (
sopel.config.Config
) – Sopel’s configuration
This method will be called by Sopel’s configuration wizard.
- abstract get_capability_requests() list[plugin_decorators.capability] #
Retrieve the plugin’s list of capability requests.
- abstract get_label() str #
Retrieve a display label for the plugin.
- Returns:
a human readable label for display purpose
- Return type:
This method should, at least, return
<module_name> plugin
.
- abstract get_meta_description() PluginMetaDescription #
Retrieve a meta description for the plugin.
- Returns:
Metadata about the plugin
- Return type:
The expected keys are detailed in
PluginMetaDescription
.
- abstract get_version()#
Retrieve the plugin’s version.
- Returns:
the plugin’s version string
- Return type:
- abstract has_configure() bool #
Tell if the plugin has a configure action.
- Returns:
True
if the plugin has aconfigure
action,False
otherwise- Return type:
- abstract has_setup() bool #
Tell if the plugin has a setup action.
- Returns:
True
if the plugin has a setup,False
otherwise- Return type:
- abstract has_shutdown() bool #
Tell if the plugin has a shutdown action.
- Returns:
True
if the plugin has ashutdown
action,False
otherwise- Return type:
- abstract is_loaded() bool #
Tell if the plugin is loaded or not.
- Returns:
True
if the plugin is loaded,False
otherwise- Return type:
This must return
True
if theload()
method has been called with success.
- abstract load()#
Load the plugin.
This method must be called first, in order to setup, register, shutdown, or configure the plugin later.
- name: str#
Plugin identifier.
The name of a plugin identifies this plugin: when Sopel loads a plugin, it will store its information under that identifier.
- abstract register(bot)#
Register the plugin with the
bot
.- Parameters:
bot (
sopel.bot.Sopel
) – instance of Sopel
- abstract reload()#
Reload the plugin.
This method can be called once the plugin is already loaded. It will take care of reloading the plugin from its source.
- abstract setup(bot)#
Run the plugin’s setup action.
- Parameters:
bot (
sopel.bot.Sopel
) – instance of Sopel
- abstract shutdown(bot)#
Run the plugin’s shutdown action.
- Parameters:
bot (
sopel.bot.Sopel
) – instance of Sopel
- abstract unregister(bot)#
Unregister the plugin from the
bot
.- Parameters:
bot (
sopel.bot.Sopel
) – instance of Sopel
- class sopel.plugins.handlers.EntryPointPlugin(entry_point)#
Sopel plugin loaded from an entry point.
- Parameters:
entry_point – an entry point object
This handler loads a Sopel plugin exposed by a package’s entry point. It expects to be able to load a module object from the entry point, and to work as a
PyModulePlugin
from that module.By default, Sopel searches within the entry point group
sopel.plugins
. To use that for their own plugins, developers must define an entry point either in theirsetup.py
file or theirsetup.cfg
file:# in setup.py file setup( name='my_plugin', version='1.0', entry_points={ 'sopel.plugins': [ 'custom = my_plugin.path.to.plugin', ], } )
And this plugin can be loaded with:
>>> from importlib_metadata import entry_points >>> from sopel.plugins.handlers import EntryPointPlugin >>> plugin = [ ... EntryPointPlugin(ep) ... for ep in entry_points(group='sopel.plugins', name='custom') ... ][0] >>> plugin.load() >>> plugin.name 'custom'
In this example, the plugin
custom
is loaded from an entry point. Unlike thePyModulePlugin
, the name is not derived from the actual Python module, but from its entry point’s name.See also
Sopel uses the
find_entry_point_plugins()
function internally to search entry points.Entry points are a standard packaging mechanism for Python, used by other applications (such as
pytest
) for their plugins.The
importlib_metadata
backport package is used for consistency across all of Sopel’s supported Python versions. Its API matches that ofimportlib.metadata
from Python 3.10 and up; Sopel will drop this external requirement when practical.- PLUGIN_TYPE = 'setup-entrypoint'#
The plugin’s type.
Metadata for the plugin; this should be considered to be a constant and should not be modified at runtime.
- get_meta_description() PluginMetaDescription #
Retrieve a meta description for the plugin.
- Returns:
Metadata about the plugin
- Return type:
The expected keys are detailed in
PluginMetaDescription
.This implementation uses its entry point definition as the
source
value:{ 'name': 'example', 'type': 'setup-entrypoint', 'label': 'example plugin', 'source': 'example = my_plugin.example', 'version': '3.1.2', }
- get_version() str | None #
Retrieve the plugin’s version.
- Returns:
the plugin’s version string
- Return type:
Optional[str]
- load()#
Load the plugin’s module using
importlib.import_module()
.This method assumes the module is available through
sys.path
.
- class sopel.plugins.handlers.PluginMetaDescription(*args, **kwargs)#
Meta description of a plugin, as a dictionary.
This dictionary is expected to contain specific keys:
name: a short name for the plugin
label: a descriptive label for the plugin; see
get_label()
type: the plugin’s type
source: the plugin’s source (filesystem path, python module/import path, etc.)
version: the plugin’s version string if available, otherwise
None
- class sopel.plugins.handlers.PyFilePlugin(filename)#
Sopel plugin loaded from the filesystem outside of the Python path.
This plugin handler can be used to load a Sopel plugin from the filesystem, either a Python
.py
file or a directory containing an__init__.py
file, and behaves like aPyModulePlugin
:>>> from sopel.plugins.handlers import PyFilePlugin >>> plugin = PyFilePlugin('/home/sopel/.sopel/plugins/custom.py') >>> plugin.load() >>> plugin.name 'custom'
In this example, the plugin
custom
is loaded from its filename despite not being in the Python path.- PLUGIN_TYPE = 'python-file'#
The plugin’s type.
Metadata for the plugin; this should be considered to be a constant and should not be modified at runtime.
- get_meta_description() PluginMetaDescription #
Retrieve a meta description for the plugin.
- Returns:
Metadata about the plugin
- Return type:
The expected keys are detailed in
PluginMetaDescription
.This implementation uses its source file’s path as the
source
value:{ 'name': 'example', 'type': 'python-file', 'label': 'example plugin', 'source': '/home/username/.sopel/plugins/example.py', 'version': '3.1.2', }
- load()#
Load the plugin’s module using
importlib.import_module()
.This method assumes the module is available through
sys.path
.
- name: str#
Plugin identifier.
The name of a plugin identifies this plugin: when Sopel loads a plugin, it will store its information under that identifier.
- reload()#
Reload the plugin.
Unlike
PyModulePlugin
, it is not possible to use thereload
function (either from imp or importlib), because the module might not be available throughsys.path
.
- class sopel.plugins.handlers.PyModulePlugin(name, package=None)#
Sopel plugin loaded from a Python module or package.
A
PyModulePlugin
represents a Sopel plugin that is a Python module (or package) that can be imported directly.This:
>>> import sys >>> from sopel.plugins.handlers import PyModulePlugin >>> plugin = PyModulePlugin('xkcd', 'sopel.builtins') >>> plugin.module_name 'sopel.builtins.xkcd' >>> plugin.load() >>> plugin.module_name in sys.modules True
Is the same as this:
>>> import sys >>> from sopel.builtins import xkcd >>> 'sopel.builtins.xkcd' in sys.modules True
- PLUGIN_TYPE = 'python-module'#
The plugin’s type.
Metadata for the plugin; this should be considered to be a constant and should not be modified at runtime.
- configure(settings)#
Configure Sopel’s
settings
for this plugin.- Parameters:
settings (
sopel.config.Config
) – Sopel’s configuration
This method will be called by Sopel’s configuration wizard.
- get_capability_requests() list[plugin_decorators.capability] #
Retrieve the plugin’s list of capability requests.
- get_label()#
Retrieve a display label for the plugin.
- Returns:
a human readable label for display purpose
- Return type:
By default, this is
<name> plugin
. If the plugin’s module has a docstring, its first line is used as the plugin’s label.
- get_meta_description() PluginMetaDescription #
Retrieve a meta description for the plugin.
- Returns:
Metadata about the plugin
- Return type:
The expected keys are detailed in
PluginMetaDescription
.This implementation uses its module’s dotted import path as the
source
value:{ 'name': 'example', 'type': 'python-module', 'label': 'example plugin', 'source': 'sopel_modules.example', 'version': '3.1.2', }
- get_version() str | None #
Retrieve the plugin’s version.
- Returns:
the plugin’s version string
- Return type:
Optional[str]
- has_configure()#
Tell if the plugin has a configure action.
- Returns:
True
if the plugin has aconfigure
action,False
otherwise- Return type:
The plugin has a configure action if its module has a
configure
attribute. This attribute is expected to be a callable.
- has_setup()#
Tell if the plugin has a setup action.
- Returns:
True
if the plugin has a setup,False
otherwise- Return type:
The plugin has a setup action if its module has a
setup
attribute. This attribute is expected to be a callable.
- has_shutdown()#
Tell if the plugin has a shutdown action.
- Returns:
True
if the plugin has ashutdown
action,False
otherwise- Return type:
The plugin has a shutdown action if its module has a
shutdown
attribute. This attribute is expected to be a callable.
- is_loaded()#
Tell if the plugin is loaded or not.
- Returns:
True
if the plugin is loaded,False
otherwise- Return type:
This must return
True
if theload()
method has been called with success.
- load()#
Load the plugin’s module using
importlib.import_module()
.This method assumes the module is available through
sys.path
.
- name: str#
Plugin identifier.
The name of a plugin identifies this plugin: when Sopel loads a plugin, it will store its information under that identifier.
- register(bot: Sopel) None #
Register the plugin with the
bot
.- Parameters:
bot (
sopel.bot.Sopel
) – instance of Sopel
- reload()#
Reload the plugin’s module using
importlib.reload()
.This method assumes the plugin is already loaded.
- setup(bot)#
Run the plugin’s setup action.
- Parameters:
bot (
sopel.bot.Sopel
) – instance of Sopel
- shutdown(bot)#
Run the plugin’s shutdown action.
- Parameters:
bot (
sopel.bot.Sopel
) – instance of Sopel
- unregister(bot)#
Unregister the plugin from the
bot
.- Parameters:
bot (
sopel.bot.Sopel
) – instance of Sopel