aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--discord/ext/commands/bot.py53
-rw-r--r--discord/ext/commands/core.py6
2 files changed, 58 insertions, 1 deletions
diff --git a/discord/ext/commands/bot.py b/discord/ext/commands/bot.py
index 7b6cd675..2515a833 100644
--- a/discord/ext/commands/bot.py
+++ b/discord/ext/commands/bot.py
@@ -27,6 +27,8 @@ DEALINGS IN THE SOFTWARE.
import asyncio
import discord
import inspect
+import importlib
+import sys
from .core import GroupMixin, Command
from .view import StringView
@@ -78,6 +80,7 @@ class Bot(GroupMixin, discord.Client):
self.command_prefix = command_prefix
self.extra_events = {}
self.cogs = {}
+ self.extensions = {}
# internal helpers
@@ -262,7 +265,6 @@ class Bot(GroupMixin, discord.Client):
except ValueError:
pass
-
def listen(self, name=None):
"""A decorator that registers another function as an external
event listener. Basically this allows you to listen to multiple
@@ -375,6 +377,55 @@ class Bot(GroupMixin, discord.Client):
if name.startswith('on_'):
self.remove_listener(member)
+ # extensions
+
+ def load_extension(self, name):
+ if name in self.extensions:
+ return
+
+ lib = importlib.import_module(name)
+ try:
+ lib.setup(self)
+ except AttributeError:
+ raise discord.ClientException('extension does not have a setup function')
+
+ self.extensions[name] = lib
+
+ def unload_extension(self, name):
+ lib = self.extensions.get(name)
+ if lib is None:
+ return
+
+ # find all references to the module
+
+ # remove the cogs registered from the module
+ for cogname, cog in self.cogs.copy().items():
+ if cog.__module__ is lib:
+ self.remove_cog(cogname)
+
+ # first remove all the commands from the module
+ for command in self.commands.copy().values():
+ if command.module is lib:
+ command.module = None
+ if isinstance(command, GroupMixin):
+ command.recursively_remove_all_commands()
+ self.remove_command(command.name)
+
+ # then remove all the listeners from the module
+ for event_list in self.extra_events.copy().values():
+ remove = []
+ for index, event in enumerate(event_list):
+ if inspect.getmodule(event) is lib:
+ remove.append(index)
+
+ for index in reversed(remove):
+ del event_list[index]
+
+ # finally remove the import..
+ del lib
+ del self.extensions[name]
+ del sys.modules[name]
+
# command processing
@asyncio.coroutine
diff --git a/discord/ext/commands/core.py b/discord/ext/commands/core.py
index 14135b08..731bd187 100644
--- a/discord/ext/commands/core.py
+++ b/discord/ext/commands/core.py
@@ -316,6 +316,12 @@ class GroupMixin:
self.commands = {}
super().__init__(**kwargs)
+ def recursively_remove_all_commands(self):
+ for command in self.commands.copy().values():
+ if isinstance(command, GroupMixin):
+ command.recursively_remove_all_commands()
+ self.remove_command(command.name)
+
def add_command(self, command):
"""Adds a :class:`Command` or its superclasses into the internal list
of commands.