diff --git a/changelog/678.bugfix.rst b/changelog/678.bugfix.rst new file mode 100644 index 0000000000..1ff55cfdb0 --- /dev/null +++ b/changelog/678.bugfix.rst @@ -0,0 +1 @@ +Make the :func:`.ext.commands.default_member_permissions` decorator always work in cogs. diff --git a/disnake/ext/commands/base_core.py b/disnake/ext/commands/base_core.py index 7a27ac2f9d..06c47ffd5f 100644 --- a/disnake/ext/commands/base_core.py +++ b/disnake/ext/commands/base_core.py @@ -223,6 +223,12 @@ def _ensure_assignment_on_copy(self, other: AppCommandT) -> AppCommandT: # _max_concurrency won't be None at this point other._max_concurrency = cast(MaxConcurrency, self._max_concurrency).copy() + if self.body._default_member_permissions != other.body._default_member_permissions and ( + "default_member_permissions" not in other.__original_kwargs__ + or self.body._default_member_permissions is not None + ): + other.body._default_member_permissions = self.body._default_member_permissions + try: other.on_error = self.on_error except AttributeError: diff --git a/disnake/ext/commands/ctx_menus_core.py b/disnake/ext/commands/ctx_menus_core.py index 2ce13caecb..6b666072f5 100644 --- a/disnake/ext/commands/ctx_menus_core.py +++ b/disnake/ext/commands/ctx_menus_core.py @@ -205,15 +205,9 @@ def __init__( self.auto_sync: bool = True if auto_sync is None else auto_sync try: - default_perms: int = func.__default_member_permissions__ + default_member_permissions = func.__default_member_permissions__ except AttributeError: pass - else: - if default_member_permissions is not None: - raise ValueError( - "Cannot set `default_member_permissions` in both parameter and decorator" - ) - default_member_permissions = default_perms dm_permission = True if dm_permission is None else dm_permission diff --git a/disnake/ext/commands/slash_core.py b/disnake/ext/commands/slash_core.py index 5662f415e5..0bddf125c5 100644 --- a/disnake/ext/commands/slash_core.py +++ b/disnake/ext/commands/slash_core.py @@ -417,15 +417,9 @@ def __init__( desc_loc = Localized._cast(description, False) try: - default_perms: int = func.__default_member_permissions__ + default_member_permissions = func.__default_member_permissions__ except AttributeError: pass - else: - if default_member_permissions is not None: - raise ValueError( - "Cannot set `default_member_permissions` in both parameter and decorator" - ) - default_member_permissions = default_perms dm_permission = True if dm_permission is None else dm_permission diff --git a/tests/ext/commands/test_base_core.py b/tests/ext/commands/test_base_core.py new file mode 100644 index 0000000000..ce8293543d --- /dev/null +++ b/tests/ext/commands/test_base_core.py @@ -0,0 +1,82 @@ +import pytest + +from disnake import Permissions +from disnake.ext import commands + + +class TestDefaultPermissions: + def test_decorator(self): + class Cog(commands.Cog): + @commands.slash_command(default_member_permissions=64) + async def cmd(self, _): + ... + + @commands.default_member_permissions(64) + @commands.slash_command() + async def above(self, _): + ... + + @commands.slash_command() + @commands.default_member_permissions(64) + async def below(self, _): + ... + + for c in (Cog, Cog()): + assert c.cmd.default_member_permissions == Permissions(64) + assert c.above.default_member_permissions == Permissions(64) + assert c.below.default_member_permissions == Permissions(64) + + def test_decorator_overwrite(self): + # putting the decorator above should fail + with pytest.raises(ValueError, match="Cannot set `default_member_permissions`"): + + class Cog(commands.Cog): + @commands.default_member_permissions(32) + @commands.slash_command(default_member_permissions=64) + async def above(self, _): + ... + + # putting the decorator below shouldn't fail + # (this is a side effect of how command copying works, + # and while this *should* probably fail, we're just testing + # for regressions for now) + class Cog2(commands.Cog): + @commands.slash_command(default_member_permissions=64) + @commands.default_member_permissions(32) + async def below(self, _): + ... + + for c in (Cog2, Cog2()): + assert c.below.default_member_permissions == Permissions(32) + + def test_attrs(self): + class Cog(commands.Cog, slash_command_attrs={"default_member_permissions": 32}): + @commands.slash_command() + async def no_overwrite(self, _): + ... + + @commands.slash_command(default_member_permissions=64) + async def overwrite(self, _): + ... + + @commands.default_member_permissions(64) + @commands.slash_command() + async def overwrite_decorator_above(self, _): + ... + + @commands.slash_command() + @commands.default_member_permissions(64) + async def overwrite_decorator_below(self, _): + ... + + assert Cog.no_overwrite.default_member_permissions is None + assert Cog().no_overwrite.default_member_permissions == Permissions(32) + + assert Cog.overwrite.default_member_permissions == Permissions(64) + assert Cog().overwrite.default_member_permissions == Permissions(64) + + assert Cog.overwrite_decorator_above.default_member_permissions == Permissions(64) + assert Cog().overwrite_decorator_above.default_member_permissions == Permissions(64) + + assert Cog.overwrite_decorator_below.default_member_permissions == Permissions(64) + assert Cog().overwrite_decorator_below.default_member_permissions == Permissions(64)