aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRapptz <[email protected]>2016-01-08 20:37:13 -0500
committerRapptz <[email protected]>2016-01-08 20:37:13 -0500
commitc06dbbd1f003f2444862e40bd3cce011e8307887 (patch)
treec9fedf551d4d22bcfaf9b1be8263080dc847dcb6
parent[commands] Change prefix callback signature and add when_mentioned. (diff)
downloaddiscord.py-c06dbbd1f003f2444862e40bd3cce011e8307887.tar.xz
discord.py-c06dbbd1f003f2444862e40bd3cce011e8307887.zip
[commands] Add support for registering more than one event listener.
-rw-r--r--discord/ext/commands/bot.py93
1 files changed, 93 insertions, 0 deletions
diff --git a/discord/ext/commands/bot.py b/discord/ext/commands/bot.py
index 965f0de9..5387df1a 100644
--- a/discord/ext/commands/bot.py
+++ b/discord/ext/commands/bot.py
@@ -66,6 +66,9 @@ class Bot(GroupMixin, discord.Client):
def __init__(self, command_prefix, **options):
super().__init__(**options)
self.command_prefix = command_prefix
+ self.extra_events = {}
+
+ # internal helpers
def _get_variable(self, name):
stack = inspect.stack()
@@ -82,6 +85,28 @@ class Bot(GroupMixin, discord.Client):
return prefix
@asyncio.coroutine
+ def _run_extra(self, coro, event_name, *args, **kwargs):
+ try:
+ yield from coro(*args, **kwargs)
+ except asyncio.CancelledError:
+ pass
+ except Exception:
+ try:
+ yield from self.on_error(event_name, *args, **kwargs)
+ except asyncio.CancelledError:
+ pass
+
+ def dispatch(self, event_name, *args, **kwargs):
+ super().dispatch(event_name, *args, **kwargs)
+ ev = 'on_' + event_name
+ if ev in self.extra_events:
+ for event in self.extra_events[ev]:
+ coro = self._run_extra(event, event_name, *args, **kwargs)
+ discord.utils.create_task(coro, loop=self.loop)
+
+ # utility "send_*" functions
+
+ @asyncio.coroutine
def say(self, content):
"""|coro|
@@ -179,6 +204,74 @@ class Bot(GroupMixin, discord.Client):
destination = self._get_variable('_internal_channel')
yield from self.send_typing(destination)
+ # listener registration
+
+ def add_listener(self, func, name=None):
+ """The non decorator alternative to :meth:`listen`.
+
+ Parameters
+ -----------
+ func : coroutine
+ The extra event to listen to.
+ name : Optional[str]
+ The name of the command to use. Defaults to ``func.__name__``.
+
+ Examples
+ ---------
+
+ .. code-block:: python
+
+ async def on_ready(): pass
+ async def my_message(message): pass
+
+ bot.add_listener(on_ready)
+ bot.add_listener(my_message, 'on_message')
+
+ """
+ name = func.__name__ if name is None else name
+
+ if not asyncio.iscoroutinefunction(func):
+ func = asyncio.coroutine(func)
+
+ if name in self.extra_events:
+ self.extra_events[name].append(func)
+ else:
+ self.extra_events[name] = [func]
+
+ def listen(self, name=None):
+ """A decorator that registers another function as an external
+ event listener. Basically this allows you to listen to multiple
+ events from different places e.g. such as :func:`discord.on_ready`
+
+ If the function being listened to is not a coroutine, it makes it into
+ a coroutine a la :meth:`Client.async_event`.
+
+ Examples
+ ---------
+
+ .. code-block:: python
+
+ @bot.listen
+ async def on_message(message):
+ print('one')
+
+ # in some other file...
+
+ @bot.listen('on_message')
+ async def my_message(message):
+ print('two')
+
+ Would print one and two in an unspecified order.
+ """
+
+ def decorator(func):
+ self.add_listener(func, name)
+ return func
+
+ return decorator
+
+ # command processing
+
@asyncio.coroutine
def process_commands(self, message):
"""|coro|