Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: new command sync options #806

Merged
merged 46 commits into from Oct 26, 2022
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
12c2a70
feat: implement new command sync behavior
onerandomusername Oct 18, 2022
fc36d51
docs: update the documentation on command sync
onerandomusername Oct 17, 2022
6359147
chore: enable codemodding on new flags file
onerandomusername Oct 17, 2022
ca970cf
chore: add property for command sync
onerandomusername Oct 17, 2022
311dcfd
chore: copy command sync before setting it
onerandomusername Oct 17, 2022
de8b449
docs: fix references to ApplicationCommandSyncFlags
onerandomusername Oct 18, 2022
07535d3
fix: don't delete guild commands if delete is disabled
onerandomusername Oct 18, 2022
4199ab1
docs: better explain lazy command sync for guild commands
onerandomusername Oct 18, 2022
1ac09ea
chore: update debug diff shown when commands are not deleted
onerandomusername Oct 18, 2022
40720b4
fix: check for the key in the diff
onerandomusername Oct 18, 2022
9d5c268
chore: remove unused flag value
onerandomusername Oct 18, 2022
0ba7728
docs: update default value
onerandomusername Oct 19, 2022
e8554dc
docs: add preliminary changelogs
onerandomusername Oct 19, 2022
9511e55
fix: actually allow syncing just global or guild commands
onerandomusername Oct 19, 2022
e25f9c4
docs: add other changelogs
onerandomusername Oct 19, 2022
9a6d775
docs: add missing command_sync documentation
onerandomusername Oct 21, 2022
34095b5
fix: correct comments
onerandomusername Oct 21, 2022
334b191
docs: varients -> variants
onerandomusername Oct 21, 2022
b6df491
fix: remove unused class
onerandomusername Oct 21, 2022
4fd2b7f
fix: copy to delete_ignored
onerandomusername Oct 21, 2022
e931725
Merge branch 'master' into feat/command-sync
onerandomusername Oct 21, 2022
90909cc
chore: rename ApplicationCommandSyncFlags to CommandSyncFlags
onerandomusername Oct 22, 2022
16cf03f
remove unused import
onerandomusername Oct 24, 2022
f699422
docs: add |commands| prefix to changelog
onerandomusername Oct 24, 2022
c7dfaea
docs: address all doc comments
onerandomusername Oct 24, 2022
003da6c
chore: rename command_sync to command_sync_flags
onerandomusername Oct 24, 2022
3924c95
chore: change deprecations to not explicity state v2.8
onerandomusername Oct 24, 2022
04639b9
clean up sync
onerandomusername Oct 24, 2022
18de61d
chore: clean up the flag code
onerandomusername Oct 24, 2022
8884f97
rename on_cog_unload to sync_on_cog_unload
onerandomusername Oct 24, 2022
981057f
readd sync_commands and others to overloads
onerandomusername Oct 24, 2022
43161f2
remove duplicated section
onerandomusername Oct 24, 2022
4433b16
add suggestion documentation changes
onerandomusername Oct 24, 2022
c69ada2
chore: rename command_sync to command_sync_flags
onerandomusername Oct 24, 2022
856efd2
consistency
onerandomusername Oct 24, 2022
7667389
expand on sync_commands shortcut
onerandomusername Oct 24, 2022
fbf1df9
nit: fix typo
shiftinv Oct 25, 2022
740aecd
fix: actually send the delete_ignored commands instead of deleting them
onerandomusername Oct 26, 2022
9030d09
chore: rename sync_on_cog_unload to sync_on_cog_actions
onerandomusername Oct 26, 2022
8d102dc
doc: update allow_command_deletion to explain how renames work
onerandomusername Oct 26, 2022
4d3c7e4
fix: require sync guild commands to be enabled as well
onerandomusername Oct 26, 2022
bd6e394
refactor interaction handling
onerandomusername Oct 26, 2022
5b1326f
fix: catch interaction timed out errors
onerandomusername Oct 26, 2022
2baf2b7
refactor: clean up unknown command handling
shiftinv Oct 26, 2022
5a063e5
Merge branch 'master' into feat/command-sync
onerandomusername Oct 26, 2022
7f54110
nit: add dot
shiftinv Oct 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/265.feature.rst
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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
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``.

onerandomusername marked this conversation as resolved.
Show resolved Hide resolved
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,
onerandomusername marked this conversation as resolved.
Show resolved Hide resolved
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
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_unload:
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_unload:
bot._schedule_delayed_command_sync()
except NotImplementedError:
pass
Expand Down
179 changes: 179 additions & 0 deletions disnake/ext/commands/flags.py
@@ -0,0 +1,179 @@
# 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_unload: 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_unload(self):
""":class:`bool`: Whether or not to sync app commands on cog unload or reload."""
onerandomusername marked this conversation as resolved.
Show resolved Hide resolved
return 1 << 1

@flag_value
def allow_command_deletion(self):
""":class:`bool`: Whether to allow commands to be deleted by automatic command sync."""
onerandomusername marked this conversation as resolved.
Show resolved Hide resolved
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