Source code for spyder.api.plugin_registration.mixins
# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)
"""
Spyder API plugin registration mixins.
"""
# Standard library imports
import logging
from spyder.api.exceptions import SpyderAPIError
from spyder.api.plugins import Plugins
logger = logging.getLogger(__name__)
[docs]
class SpyderPluginObserver:
"""
This mixin enables a class to receive notifications when a plugin
is available, by registering methods using the
:func:`spyder.api.plugin_registration.decorators.on_plugin_available`
decorator.
When any of the requested plugins is ready, the corresponding registered
method is called.
Notes
-----
This mixin will only operate over the plugin requirements listed under
`REQUIRES` and `OPTIONAL` class constants.
"""
def __init__(self):
self._plugin_listeners = {}
self._plugin_teardown_listeners = {}
for method_name in dir(self):
method = getattr(self, method_name, None)
if hasattr(method, '_plugin_listen'):
plugin_listen = method._plugin_listen
# Check if plugin is listed among REQUIRES and OPTIONAL.
# Note: We can't do this validation for the Layout plugin
# because it depends on all plugins through the Plugins.All
# wildcard.
if (
self.NAME != Plugins.Layout and
(plugin_listen not in self.REQUIRES + self.OPTIONAL)
):
raise SpyderAPIError(
f"Method {method_name} of {self} is trying to watch "
f"plugin {plugin_listen}, but that plugin is not "
f"listed in REQUIRES nor OPTIONAL."
)
logger.debug(
f'Method {method_name} is watching plugin {plugin_listen}'
)
self._plugin_listeners[plugin_listen] = method_name
if hasattr(method, '_plugin_teardown'):
plugin_teardown = method._plugin_teardown
# Check if plugin is listed among REQUIRES and OPTIONAL.
# Note: We can't do this validation for the Layout plugin
# because it depends on all plugins through the Plugins.All
# wildcard.
if (
self.NAME != Plugins.Layout and
(plugin_teardown not in self.REQUIRES + self.OPTIONAL)
):
raise SpyderAPIError(
f"Method {method_name} of {self} is trying to watch "
f"plugin {plugin_teardown}, but that plugin is not "
f"listed in REQUIRES nor OPTIONAL."
)
logger.debug(f'Method {method_name} will handle plugin '
f'teardown for {plugin_teardown}')
self._plugin_teardown_listeners[plugin_teardown] = method_name
def _on_plugin_available(self, plugin: str):
"""
Handle plugin availability and redirect it to plugin-specific
startup handlers.
Parameters
----------
plugin: str
Name of the plugin that was notified as available.
"""
# Call plugin specific handler
if plugin in self._plugin_listeners:
method_name = self._plugin_listeners[plugin]
method = getattr(self, method_name)
logger.debug(f'Calling {method}')
method()
# Call global plugin handler
if '__all' in self._plugin_listeners:
method_name = self._plugin_listeners['__all']
method = getattr(self, method_name)
method(plugin)
def _on_plugin_teardown(self, plugin: str):
"""
Handle plugin teardown and redirect it to plugin-specific teardown
handlers.
Parameters
----------
plugin: str
Name of the plugin that is going through its teardown process.
"""
# Call plugin specific handler
if plugin in self._plugin_teardown_listeners:
method_name = self._plugin_teardown_listeners[plugin]
method = getattr(self, method_name)
logger.debug(f'Calling {method}')
method()