Skip to content

Commit

Permalink
plugin: bot's new interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Exirel committed Mar 25, 2019
1 parent d347a38 commit 6ccad67
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 1 deletion.
71 changes: 71 additions & 0 deletions sopel/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from __future__ import unicode_literals, absolute_import, print_function, division

import collections
import itertools
import os
import re
import sys
Expand Down Expand Up @@ -58,6 +59,7 @@ def __init__(self, config, daemon=False):
'medium': collections.defaultdict(list),
'low': collections.defaultdict(list)
}
self._plugins = {}
self.config = config
"""The :class:`sopel.config.Config` for the current Sopel instance."""
self.doc = {}
Expand Down Expand Up @@ -221,6 +223,75 @@ def setup(self):
else:
stderr("Warning: Couldn't load any modules")

def reload_plugin(self, name):
if name not in self._plugins:
# TODO: raise more specific exception
raise Exception('Plugin %s is not loaded' % name)

plugin = self._plugins[name]
# tear down
plugin.shutdown(self)
plugin.unregister(self)
print('Unloaded: %s' % name)
# reload & setup
plugin.reload()
plugin.setup(self)
plugin.register(self)
print('Reloaded: %s' % name)

def reload_plugins(self):
"""Reload all plugins
First, it shutdown & unregister all plugins, then it reload, setup, and
register all of them.
"""
registered = list(self._plugins.items())
# tear down all plugins
for name, plugin in registered:
plugin.shutdown(self)
plugin.unregister(self)
print('Unloaded: %s' % name)

# reload & setup all plugins
for name, plugin in registered:
plugin.reload()
plugin.setup(self)
plugin.register(self)
print('Reloaded: %s' % name)

def add_plugin(self, plugin, callables, jobs, shutdowns, urls):
"""Add a loaded plugin to the bot's registry"""
self._plugins[plugin.name] = plugin
self.register(callables, jobs, shutdowns, urls)

def remove_plugin(self, plugin, callables, jobs, shutdowns, urls):
"""Remove a loaded plugin from the bot's registry"""
name = plugin.name
if name not in self._plugins:
# TODO: raise more specific exception
raise Exception('Plugin %s is not loaded' % name)

try:
# remove commands, jobs, and shutdown functions
for func in itertools.chain(callables, jobs, shutdowns):
self.unregister(func)

# remove URL callback handlers
for func in urls:
regex = func.url_regex
if func == self.memory['url_callbacks'].get(regex):
del self.memory['url_callbacks'][regex]
except: # noqa
# TODO: consider logging?
raise # re-raised
else:
# remove plugin from registry
del self._plugins[name]

def has_plugin(self, name):
"""Tell if the bot has registered this plugin by its name"""
return name in self._plugins

def unregister(self, obj):
if not callable(obj):
return
Expand Down
14 changes: 13 additions & 1 deletion sopel/plugins/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ def register(self, bot):
"""
raise NotImplementedError

def unregister(self, bot):
"""Unregister the plugin from the ``bot``
:param bot: instance of Sopel
:type bot: :class:`sopel.bot.Sopel`
"""
raise NotImplementedError

def shutdown(self, bot):
"""Take action on bot's shutdown
Expand Down Expand Up @@ -216,7 +224,11 @@ def has_setup(self):

def register(self, bot):
relevant_parts = loader.clean_module(self._module, bot.config)
bot.register(*relevant_parts)
bot.add_plugin(self, *relevant_parts)

def unregister(self, bot):
relevant_parts = loader.clean_module(self._module, bot.config)
bot.remove_plugin(self, *relevant_parts)

def shutdown(self, bot):
if self.has_shutdown():
Expand Down

0 comments on commit 6ccad67

Please sign in to comment.