From e4daedd92e87d8b662057138282b3868984ac750 Mon Sep 17 00:00:00 2001 From: Om1609 Date: Thu, 23 Feb 2023 17:51:45 +0530 Subject: [PATCH 1/5] add `once` decorator to discord.Client --- discord/client.py | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/discord/client.py b/discord/client.py index b8b1057e67..07bba3bf41 100644 --- a/discord/client.py +++ b/discord/client.py @@ -1286,6 +1286,64 @@ async def on_ready(): _log.debug("%s has successfully been registered as an event", coro.__name__) return coro + def once( + self, name: str = MISSING, check: Callable[..., bool] | None = None + ) -> Coro: + """A decorator that registers an event to listen to only once. + + You can find more info about the events on the :ref:`documentation below `. + + The events must be a :ref:`coroutine `, if not, :exc:`TypeError` is raised. + + Parameters + ---------- + name: :class:`str` + The name of the event we want to listen to. This is passed to + :py:meth:`~discord.Client.wait_for`. Defaults to ``func.__name__``. + check: Optional[Callable[..., :class:`bool`]] + A predicate to check what to wait for. The arguments must meet the + parameters of the event being waited for. + + Raises + ------ + TypeError + The coroutine passed is not actually a coroutine. + + Example + ------- + + .. code-block:: python3 + + @client.once() + async def ready(): + print('Ready!') + """ + + def decorator(func: Coro) -> Coro: + if not asyncio.iscoroutinefunction(func): + raise TypeError("event registered must be a coroutine function") + + async def wrapped() -> None: + nonlocal name + nonlocal check + + name = func.__name__ if name is MISSING else name + + args = await self.wait_for(name, check=check) + + arg_len = func.__code__.co_argcount + if arg_len == 0 and args is None: + await func() + elif arg_len == 1: + await func(args) + else: + await func(*args) + + self.loop.create_task(wrapped()) + return func + + return decorator + async def change_presence( self, *, From ed4e6cbe5d1b0cb188efaf53c2fa721ec1030dec Mon Sep 17 00:00:00 2001 From: Om <92863779+Om1609@users.noreply.github.com> Date: Fri, 24 Feb 2023 19:31:32 +0530 Subject: [PATCH 2/5] Add changelog entry for `@client.once()` Signed-off-by: Om <92863779+Om1609@users.noreply.github.com> --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97d1d56853..806ff4ae7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ These changes are available on the `master` branch, but have not yet been releas - Added new events `on_bridge_command`, `on_bridge_command_completion`, and `on_bridge_command_error`. ([#1916](https://github.com/Pycord-Development/pycord/pull/1916)) +- Added a `@client.once()` decorator that works like a one-time event listener. + ([#1940](https://github.com/Pycord-Development/pycord/pull/1940)) ### Fixed From 0336598a5ed5fa05cf80ce29bde42346627e7421 Mon Sep 17 00:00:00 2001 From: Om <92863779+Om1609@users.noreply.github.com> Date: Fri, 24 Feb 2023 20:15:30 +0530 Subject: [PATCH 3/5] Update CHANGELOG.md Co-authored-by: BobDotCom <71356958+BobDotCom@users.noreply.github.com> Signed-off-by: Om <92863779+Om1609@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 806ff4ae7d..791df31a1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ These changes are available on the `master` branch, but have not yet been releas - Added new events `on_bridge_command`, `on_bridge_command_completion`, and `on_bridge_command_error`. ([#1916](https://github.com/Pycord-Development/pycord/pull/1916)) -- Added a `@client.once()` decorator that works like a one-time event listener. +- Added the `@client.once()` decorator, which serves as a one-time event listener. ([#1940](https://github.com/Pycord-Development/pycord/pull/1940)) ### Fixed From e5ef8d2519e44288c84925ca4b757bae37345404 Mon Sep 17 00:00:00 2001 From: Om <92863779+Om1609@users.noreply.github.com> Date: Fri, 24 Feb 2023 21:00:06 +0530 Subject: [PATCH 4/5] update docs for `@client.once` --- docs/api/clients.rst | 10 ++++++++-- docs/api/events.rst | 12 +++++++++--- docs/ext/commands/api.rst | 5 ++++- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/api/clients.rst b/docs/api/clients.rst index 8bf10cff4f..9c186666ec 100644 --- a/docs/api/clients.rst +++ b/docs/api/clients.rst @@ -10,7 +10,7 @@ Bots .. autoclass:: Bot :members: :inherited-members: - :exclude-members: command, event, message_command, slash_command, user_command, listen + :exclude-members: command, event, message_command, slash_command, user_command, listen, once .. automethod:: Bot.command(**kwargs) :decorator: @@ -29,6 +29,9 @@ Bots .. automethod:: Bot.listen(name=None) :decorator: + + .. automethod:: Bot.once(name=None, check=None) + :decorator: .. attributetable:: AutoShardedBot .. autoclass:: AutoShardedBot @@ -41,7 +44,7 @@ Clients .. attributetable:: Client .. autoclass:: Client :members: - :exclude-members: fetch_guilds, event + :exclude-members: fetch_guilds, event, once .. automethod:: Client.event() :decorator: @@ -49,6 +52,9 @@ Clients .. automethod:: Client.fetch_guilds :async-for: + .. automethod:: Client.once(name=None, check=None) + :decorator: + .. attributetable:: AutoShardedClient .. autoclass:: AutoShardedClient :members: diff --git a/docs/api/events.rst b/docs/api/events.rst index 10e2039c7d..ec7894b43b 100644 --- a/docs/api/events.rst +++ b/docs/api/events.rst @@ -7,10 +7,11 @@ Event Reference This section outlines the different types of events listened by :class:`Client`. -There are 3 ways to register an event, the first way is through the use of +There are 4 ways to register an event, the first way is through the use of :meth:`Client.event`. The second way is through subclassing :class:`Client` and -overriding the specific events. The third way is through the use of :meth:`Client.listen`, which can be used to assign multiple -event handlers instead of only one like in :meth:`Client.event`. For example: +overriding the specific events. The third way is through the use of :meth:`Client.listen`, +which can be used to assign multiple event handlers instead of only one like in :meth:`Client.event`. +The fourth way is through the use of :meth:`Client.once`, which serves as a one-time event listener. For example: .. code-block:: python :emphasize-lines: 17, 22 @@ -39,6 +40,11 @@ event handlers instead of only one like in :meth:`Client.event`. For example: @client.listen() async def on_message(message: discord.Message): print(f"Received {message.content}") + + # Runs only for the 1st 'on_message' event. Can be useful for listening to 'on_ready' + @client.once() + async def message(message: discord.Message): + print(f"Received {message.content}") If an event handler raises an exception, :func:`on_error` will be called diff --git a/docs/ext/commands/api.rst b/docs/ext/commands/api.rst index 355a8a1020..f7c4606529 100644 --- a/docs/ext/commands/api.rst +++ b/docs/ext/commands/api.rst @@ -23,7 +23,7 @@ Bot .. autoclass:: discord.ext.commands.Bot :members: :inherited-members: - :exclude-members: after_invoke, before_invoke, check, check_once, command, event, group, listen + :exclude-members: after_invoke, before_invoke, check, check_once, command, event, group, listen, once .. automethod:: Bot.after_invoke() :decorator: @@ -48,6 +48,9 @@ Bot .. automethod:: Bot.listen(name=None) :decorator: + + .. automethod:: Bot.once(name=None, check=None) + :decorator: AutoShardedBot ~~~~~~~~~~~~~~ From edf1abab216fe673843163db85247f32c643ea80 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 15:31:05 +0000 Subject: [PATCH 5/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/api/clients.rst | 2 +- docs/api/events.rst | 6 +++--- docs/ext/commands/api.rst | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/api/clients.rst b/docs/api/clients.rst index 9c186666ec..aeae87cbcb 100644 --- a/docs/api/clients.rst +++ b/docs/api/clients.rst @@ -29,7 +29,7 @@ Bots .. automethod:: Bot.listen(name=None) :decorator: - + .. automethod:: Bot.once(name=None, check=None) :decorator: diff --git a/docs/api/events.rst b/docs/api/events.rst index ec7894b43b..4903ae8f92 100644 --- a/docs/api/events.rst +++ b/docs/api/events.rst @@ -9,8 +9,8 @@ This section outlines the different types of events listened by :class:`Client`. There are 4 ways to register an event, the first way is through the use of :meth:`Client.event`. The second way is through subclassing :class:`Client` and -overriding the specific events. The third way is through the use of :meth:`Client.listen`, -which can be used to assign multiple event handlers instead of only one like in :meth:`Client.event`. +overriding the specific events. The third way is through the use of :meth:`Client.listen`, +which can be used to assign multiple event handlers instead of only one like in :meth:`Client.event`. The fourth way is through the use of :meth:`Client.once`, which serves as a one-time event listener. For example: .. code-block:: python @@ -40,7 +40,7 @@ The fourth way is through the use of :meth:`Client.once`, which serves as a one- @client.listen() async def on_message(message: discord.Message): print(f"Received {message.content}") - + # Runs only for the 1st 'on_message' event. Can be useful for listening to 'on_ready' @client.once() async def message(message: discord.Message): diff --git a/docs/ext/commands/api.rst b/docs/ext/commands/api.rst index f7c4606529..119a8de10c 100644 --- a/docs/ext/commands/api.rst +++ b/docs/ext/commands/api.rst @@ -48,7 +48,7 @@ Bot .. automethod:: Bot.listen(name=None) :decorator: - + .. automethod:: Bot.once(name=None, check=None) :decorator: