diff --git a/CHANGELOG.md b/CHANGELOG.md index 88bf77570b..946ca1905a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,8 @@ These changes are available on the `master` branch, but have not yet been releas ([#2042](https://github.com/Pycord-Development/pycord/pull/2042)) - Added `icon` and `unicode_emoji` to `Guild.create_role`. ([#2086](https://github.com/Pycord-Development/pycord/pull/2086)) +- Added `cooldown` and `max_concurrency` to `SlashCommandGroup`. + ([#2091](https://github.com/Pycord-Development/pycord/pull/2091)) - Added new embedded activities, Gartic Phone and Jamspace. ([#2102](https://github.com/Pycord-Development/pycord/pull/2102)) - Added `bridge.Context` as a shortcut to `Union` of subclasses. @@ -131,6 +133,8 @@ These changes are available on the `master` branch, but have not yet been releas ([#2079](https://github.com/Pycord-Development/pycord/pull/2079)) - Fixed `HTTPException` when trying to create a forum thread with files. ([#2075](https://github.com/Pycord-Development/pycord/pull/2075)) +- Fixed `before_invoke` not being run for `SlashCommandGroup`. + ([#2091](https://github.com/Pycord-Development/pycord/pull/2091)) - Fixed `AttributeError` when accessing a `Select`'s values when it hasn't been interacted with. ([#2104](https://github.com/Pycord-Development/pycord/pull/2104)) diff --git a/discord/commands/core.py b/discord/commands/core.py index 90a614a786..3f0018f88f 100644 --- a/discord/commands/core.py +++ b/discord/commands/core.py @@ -84,6 +84,7 @@ from .. import Permissions from ..cog import Cog + from ..ext.commands.cooldowns import CooldownMapping, MaxConcurrency T = TypeVar("T") CogT = TypeVar("CogT", bound="Cog") @@ -294,18 +295,17 @@ async def prepare(self, ctx: ApplicationContext) -> None: f"The check functions for the command {self.name} failed" ) - if hasattr(self, "_max_concurrency"): - if self._max_concurrency is not None: - # For this application, context can be duck-typed as a Message - await self._max_concurrency.acquire(ctx) # type: ignore # ctx instead of non-existent message + if self._max_concurrency is not None: + # For this application, context can be duck-typed as a Message + await self._max_concurrency.acquire(ctx) # type: ignore # ctx instead of non-existent message - try: - self._prepare_cooldowns(ctx) - await self.call_before_hooks(ctx) - except: - if self._max_concurrency is not None: - await self._max_concurrency.release(ctx) # type: ignore # ctx instead of non-existent message - raise + try: + self._prepare_cooldowns(ctx) + await self.call_before_hooks(ctx) + except: + if self._max_concurrency is not None: + await self._max_concurrency.release(ctx) # type: ignore # ctx instead of non-existent message + raise def is_on_cooldown(self, ctx: ApplicationContext) -> bool: """Checks whether the command is currently on cooldown. @@ -1119,6 +1119,8 @@ def __init__( description: str | None = None, guild_ids: list[int] | None = None, parent: SlashCommandGroup | None = None, + cooldown: CooldownMapping | None = None, + max_concurrency: MaxConcurrency | None = None, **kwargs, ) -> None: self.name = str(name) @@ -1153,6 +1155,33 @@ def __init__( "description_localizations", MISSING ) + # similar to ApplicationCommand + from ..ext.commands.cooldowns import BucketType, CooldownMapping, MaxConcurrency + + # no need to getattr, since slash cmds groups cant be created using a decorator + + if cooldown is None: + buckets = CooldownMapping(cooldown, BucketType.default) + elif isinstance(cooldown, CooldownMapping): + buckets = cooldown + else: + raise TypeError( + "Cooldown must be a an instance of CooldownMapping or None." + ) + + self._buckets: CooldownMapping = buckets + + # no need to getattr, since slash cmds groups cant be created using a decorator + + if max_concurrency is not None and not isinstance( + max_concurrency, MaxConcurrency + ): + raise TypeError( + "max_concurrency must be an instance of MaxConcurrency or None" + ) + + self._max_concurrency: MaxConcurrency | None = max_concurrency + @property def module(self) -> str | None: return self.__module__