Skip to content

Commit

Permalink
feat: new command sync options (#806)
Browse files Browse the repository at this point in the history
Signed-off-by: arl <[email protected]>
Co-authored-by: shiftinv <[email protected]>
  • Loading branch information
onerandomusername and shiftinv authored Oct 26, 2022
1 parent 0b3f1dd commit 6a9ce72
Show file tree
Hide file tree
Showing 15 changed files with 461 additions and 108 deletions.
1 change: 1 addition & 0 deletions changelog/265.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
|commands| Add :class:`~disnake.ext.commands.CommandSyncFlags` to provide sync configuration to :class:`~disnake.ext.commands.Bot` and :class:`~disnake.ext.commands.InteractionBot` (and their autosharded variants) as ``command_sync_flags``.
1 change: 1 addition & 0 deletions changelog/433.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
|commands| Add :class:`~disnake.ext.commands.CommandSyncFlags` to provide sync configuration to :class:`~disnake.ext.commands.Bot` and :class:`~disnake.ext.commands.InteractionBot` (and their autosharded variants) as ``command_sync_flags``.
1 change: 1 addition & 0 deletions changelog/468.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
|commands| Add :class:`~disnake.ext.commands.CommandSyncFlags` to provide sync configuration to :class:`~disnake.ext.commands.Bot` and :class:`~disnake.ext.commands.InteractionBot` (and their autosharded variants) as ``command_sync_flags``.
1 change: 1 addition & 0 deletions changelog/806.deprecate.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
|commands| Deprecate the ``sync_commands``, ``sync_commands_debug``, and ``sync_commands_on_cog_unload`` parameters of :class:`~disnake.ext.commands.Bot` and :class:`~disnake.ext.commands.InteractionBot`. These have been replaced with the ``command_sync_flags`` parameter which takes a :class:`~disnake.ext.commands.CommandSyncFlags` instance.
1 change: 1 addition & 0 deletions changelog/806.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
|commands| Add :class:`~disnake.ext.commands.CommandSyncFlags` to provide sync configuration to :class:`~disnake.ext.commands.Bot` and :class:`~disnake.ext.commands.InteractionBot` (and their autosharded variants) as ``command_sync_flags``.
1 change: 1 addition & 0 deletions disnake/ext/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .custom_warnings import *
from .errors import *
from .flag_converter import *
from .flags import *
from .help import *
from .params import *
from .slash_core import *
61 changes: 49 additions & 12 deletions disnake/ext/commands/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from ._types import MaybeCoro
from .bot_base import PrefixType
from .flags import CommandSyncFlags
from .help import HelpCommand


Expand Down Expand Up @@ -61,18 +62,31 @@ class Bot(BotBase, InteractionBotBase, disnake.Client):
.. versionadded:: 2.1
command_sync_flags: :class:`.ext.commands.CommandSyncFlags`
The command sync flags for the session. This is a way of
controlling when and how application commands will be synced with the Discord API.
If not given, defaults to :func:`CommandSyncFlags.default`.
.. versionadded:: 2.7
sync_commands: :class:`bool`
Whether to enable automatic synchronization of application commands in your code.
Defaults to ``True``, which means that commands in API are automatically synced
with the commands in your code.
.. versionadded:: 2.1
.. deprecated:: 2.7
Replaced with ``command_sync_flags``.
sync_commands_on_cog_unload: :class:`bool`
Whether to sync the application commands on cog unload / reload. Defaults to ``True``.
.. versionadded:: 2.1
.. deprecated:: 2.7
Replaced with ``command_sync_flags``.
sync_commands_debug: :class:`bool`
Whether to always show sync debug logs (uses ``INFO`` log level if it's enabled, prints otherwise).
If disabled, uses the default ``DEBUG`` log level which isn't shown unless the log level is changed manually.
Expand All @@ -85,6 +99,9 @@ class Bot(BotBase, InteractionBotBase, disnake.Client):
Changes the log level of corresponding messages from ``DEBUG`` to ``INFO`` or ``print``\\s them,
instead of controlling whether they are enabled at all.
.. deprecated:: 2.7
Replaced with ``command_sync_flags``.
localization_provider: :class:`.LocalizationProtocol`
An implementation of :class:`.LocalizationProtocol` to use for localization of
application commands.
Expand Down Expand Up @@ -216,10 +233,11 @@ def __init__(
owner_ids: Optional[Set[int]] = None,
reload: bool = False,
case_insensitive: bool = False,
sync_commands: bool = True,
sync_commands_debug: bool = False,
sync_commands_on_cog_unload: bool = True,
command_sync_flags: CommandSyncFlags = ...,
test_guilds: Optional[Sequence[int]] = None,
sync_commands: bool = ...,
sync_commands_debug: bool = ...,
sync_commands_on_cog_unload: bool = ...,
asyncio_debug: bool = False,
loop: Optional[asyncio.AbstractEventLoop] = None,
shard_id: Optional[int] = None,
Expand Down Expand Up @@ -267,10 +285,11 @@ def __init__(
owner_ids: Optional[Set[int]] = None,
reload: bool = False,
case_insensitive: bool = False,
sync_commands: bool = True,
sync_commands_debug: bool = False,
sync_commands_on_cog_unload: bool = True,
command_sync_flags: CommandSyncFlags = ...,
test_guilds: Optional[Sequence[int]] = None,
sync_commands: bool = ...,
sync_commands_debug: bool = ...,
sync_commands_on_cog_unload: bool = ...,
asyncio_debug: bool = False,
loop: Optional[asyncio.AbstractEventLoop] = None,
shard_ids: Optional[List[int]] = None, # instead of shard_id
Expand Down Expand Up @@ -317,18 +336,31 @@ class InteractionBot(InteractionBotBase, disnake.Client):
.. versionadded:: 2.1
command_sync_flags: :class:`.ext.commands.CommandSyncFlags`
The command sync flags for the session. This is a way of
controlling when and how application commands will be synced with the Discord API.
If not given, defaults to :func:`CommandSyncFlags.default`.
.. versionadded:: 2.7
sync_commands: :class:`bool`
Whether to enable automatic synchronization of application commands in your code.
Defaults to ``True``, which means that commands in API are automatically synced
with the commands in your code.
.. versionadded:: 2.1
.. deprecated:: 2.7
Replaced with ``command_sync_flags``.
sync_commands_on_cog_unload: :class:`bool`
Whether to sync the application commands on cog unload / reload. Defaults to ``True``.
.. versionadded:: 2.1
.. deprecated:: 2.7
Replaced with ``command_sync_flags``.
sync_commands_debug: :class:`bool`
Whether to always show sync debug logs (uses ``INFO`` log level if it's enabled, prints otherwise).
If disabled, uses the default ``DEBUG`` log level which isn't shown unless the log level is changed manually.
Expand All @@ -341,6 +373,9 @@ class InteractionBot(InteractionBotBase, disnake.Client):
Changes the log level of corresponding messages from ``DEBUG`` to ``INFO`` or ``print``\\s them,
instead of controlling whether they are enabled at all.
.. deprecated:: 2.7
Replaced with ``command_sync_flags``.
localization_provider: :class:`.LocalizationProtocol`
An implementation of :class:`.LocalizationProtocol` to use for localization of
application commands.
Expand Down Expand Up @@ -399,10 +434,11 @@ def __init__(
owner_id: Optional[int] = None,
owner_ids: Optional[Set[int]] = None,
reload: bool = False,
sync_commands: bool = True,
sync_commands_debug: bool = False,
sync_commands_on_cog_unload: bool = True,
command_sync_flags: CommandSyncFlags = ...,
test_guilds: Optional[Sequence[int]] = None,
sync_commands: bool = ...,
sync_commands_debug: bool = ...,
sync_commands_on_cog_unload: bool = ...,
asyncio_debug: bool = False,
loop: Optional[asyncio.AbstractEventLoop] = None,
shard_id: Optional[int] = None,
Expand Down Expand Up @@ -443,10 +479,11 @@ def __init__(
owner_id: Optional[int] = None,
owner_ids: Optional[Set[int]] = None,
reload: bool = False,
sync_commands: bool = True,
sync_commands_debug: bool = False,
sync_commands_on_cog_unload: bool = True,
command_sync_flags: CommandSyncFlags = ...,
test_guilds: Optional[Sequence[int]] = None,
sync_commands: bool = ...,
sync_commands_debug: bool = ...,
sync_commands_on_cog_unload: bool = ...,
asyncio_debug: bool = False,
loop: Optional[asyncio.AbstractEventLoop] = None,
shard_ids: Optional[List[int]] = None, # instead of shard_id
Expand Down
4 changes: 2 additions & 2 deletions disnake/ext/commands/cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@ def _inject(self, bot: AnyBot) -> Self:
bot.add_listener(getattr(self, method_name), name)

try:
if bot._sync_commands_on_cog_unload:
if bot._command_sync_flags.sync_on_cog_actions:
bot._schedule_delayed_command_sync()
except NotImplementedError:
pass
Expand Down Expand Up @@ -874,7 +874,7 @@ def _eject(self, bot: AnyBot) -> None:

finally:
try:
if bot._sync_commands_on_cog_unload:
if bot._command_sync_flags.sync_on_cog_actions:
bot._schedule_delayed_command_sync()
except NotImplementedError:
pass
Expand Down
183 changes: 183 additions & 0 deletions disnake/ext/commands/flags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# SPDX-License-Identifier: MIT

from __future__ import annotations

from typing import TYPE_CHECKING, NoReturn, overload

from disnake.flags import BaseFlags, alias_flag_value, all_flags_value, flag_value
from disnake.utils import _generated

if TYPE_CHECKING:
from typing_extensions import Self

__all__ = ("CommandSyncFlags",)


class CommandSyncFlags(BaseFlags):
"""Controls the library's application command syncing policy.
This allows for finer grained control over what commands are synced automatically and in what cases.
To construct an object you can pass keyword arguments denoting the flags
to enable or disable.
If command sync is disabled (see the docs of :attr:`sync_commands` for more info), other options will have no effect.
.. versionadded:: 2.7
.. container:: operations
.. describe:: x == y
Checks if two CommandSyncFlags instances are equal.
.. describe:: x != y
Checks if two CommandSyncFlags instances are not equal.
.. describe:: x <= y
Checks if an CommandSyncFlags instance is a subset of another CommandSyncFlags instance.
.. describe:: x >= y
Checks if an CommandSyncFlags instance is a superset of another CommandSyncFlags instance.
.. describe:: x < y
Checks if an CommandSyncFlags instance is a strict subset of another CommandSyncFlags instance.
.. describe:: x > y
Checks if an CommandSyncFlags instance is a strict superset of another CommandSyncFlags instance.
.. describe:: x | y, x |= y
Returns a new CommandSyncFlags instance with all enabled flags from both x and y.
(Using ``|=`` will update in place).
.. describe:: x & y, x &= y
Returns a new CommandSyncFlags instance with only flags enabled on both x and y.
(Using ``&=`` will update in place).
.. describe:: x ^ y, x ^= y
Returns a new CommandSyncFlags instance with only flags enabled on one of x or y, but not both.
(Using ``^=`` will update in place).
.. describe:: ~x
Returns a new CommandSyncFlags instance with all flags from x inverted.
.. describe:: hash(x)
Return the flag's hash.
.. describe:: iter(x)
Returns an iterator of ``(name, value)`` pairs. This allows it
to be, for example, constructed as a dict or a list of pairs.
Note that aliases are not shown.
Additionally supported are a few operations on class attributes.
.. describe:: CommandSyncFlags.y | CommandSyncFlags.z, CommandSyncFlags(y=True) | CommandSyncFlags.z
Returns a CommandSyncFlags instance with all provided flags enabled.
.. describe:: ~CommandSyncFlags.y
Returns a CommandSyncFlags instance with all flags except ``y`` inverted from their default value.
Attributes
----------
value: :class:`int`
The raw value. You should query flags via the properties
rather than using this raw value.
"""

__slots__ = ()

@overload
@_generated
def __init__(
self,
*,
allow_command_deletion: bool = ...,
sync_commands: bool = ...,
sync_commands_debug: bool = ...,
sync_global_commands: bool = ...,
sync_guild_commands: bool = ...,
sync_on_cog_actions: bool = ...,
):
...

@overload
@_generated
def __init__(self: NoReturn):
...

def __init__(self, **kwargs: bool):
self.value = all_flags_value(self.VALID_FLAGS)
for key, value in kwargs.items():
if key not in self.VALID_FLAGS:
raise TypeError(f"{key!r} is not a valid flag name.")
setattr(self, key, value)

@classmethod
def all(cls) -> Self:
"""A factory method that creates a :class:`CommandSyncFlags` with everything enabled."""
self = cls.__new__(cls)
self.value = all_flags_value(cls.VALID_FLAGS)
return self

@classmethod
def none(cls) -> Self:
"""A factory method that creates a :class:`CommandSyncFlags` with everything disabled."""
self = cls.__new__(cls)
self.value = self.DEFAULT_VALUE
return self

@classmethod
def default(cls) -> Self:
"""A factory method that creates a :class:`CommandSyncFlags` with the default settings.
The default is all flags enabled except for :attr:`sync_commands_debug`.
"""
self = cls.all()
self.sync_commands_debug = False
return self

@property
def _sync_enabled(self):
return self.sync_global_commands or self.sync_guild_commands

@alias_flag_value
def sync_commands(self):
""":class:`bool`: Whether to sync global and guild app commands.
This controls the :attr:`sync_global_commands` and :attr:`sync_guild_commands` attributes.
Note that it is possible for sync to be enabled for guild *or* global commands yet this will return ``False``.
"""
return 1 << 3 | 1 << 4

@flag_value
def sync_commands_debug(self):
""":class:`bool`: Whether or not to show app command sync debug messages."""
return 1 << 0

@flag_value
def sync_on_cog_actions(self):
""":class:`bool`: Whether or not to sync app commands on cog load, unload, or reload."""
return 1 << 1

@flag_value
def allow_command_deletion(self):
""":class:`bool`: Whether to allow commands to be deleted by automatic command sync.
Current implementation of commands sync of renamed commands means that a rename of a command *will* result
in the old one being deleted and a new command being created.
"""
return 1 << 2

@flag_value
def sync_global_commands(self):
""":class:`bool`: Whether to sync global commands."""
return 1 << 3

@flag_value
def sync_guild_commands(self):
""":class:`bool`: Whether to sync per-guild commands."""
return 1 << 4
Loading

0 comments on commit 6a9ce72

Please sign in to comment.