Implement a least breaking approach to slash commands (#39)

* Most slash command support completed, needs some debugging (and reindent)

* Implement a ctx.send helper for slash commands

* Add group command support

* Add Option converter, fix default optional, fix help command

* Add client.setup and move readying commands to that

* Implement _FakeSlashMessage.from_interaction

* Rename normmal_command to message_command

* Add docs for added params

* Add slash_command_guilds to bot and decos

* Fix merge conflict

* Remove name from commands.Option, wasn't used

* Move slash command processing to BotBase.process_slash_commands

* Create slash_only.py

Basic example for slash commands

* Create slash_and_message.py

Basic example for mixed commands

* Fix slash_command and normal_command bools

* Add some basic error handling for registration

* Fixed converter upload errors

* Fix some logic and make an actual example

* Thanks Safety Jim

* docstrings, *args, and error changes

* Add proper literal support

* Add basic documentation on slash commands

* Fix non-slash command interactions

* Fix ctx.reply in slash command context

* Fix typing on Context.reply

* Fix multiple optional argument sorting

* Update ctx.message docs to mention error instead of warning

* Move slash command creation to BotBase

* Fix code style issues with Black

* Rearrange some stuff and add flag support

* Change some errors and fix interaction.channel fixing

* Fix slash command quoting for *args

Co-authored-by: iDutchy <42503862+iDutchy@users.noreply.github.com>
Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
This commit is contained in:
Gnome!
2021-09-19 00:28:11 +01:00
committed by GitHub
parent 75a23351c4
commit 1957fa6011
14 changed files with 662 additions and 39 deletions

View File

@ -47,6 +47,8 @@ __all__ = (
)
if TYPE_CHECKING:
from datetime import datetime
from .types.interactions import (
Interaction as InteractionPayload,
InteractionData,
@ -58,12 +60,10 @@ if TYPE_CHECKING:
from aiohttp import ClientSession
from .embeds import Embed
from .ui.view import View
from .channel import VoiceChannel, StageChannel, TextChannel, CategoryChannel, StoreChannel, PartialMessageable
from .channel import TextChannel, CategoryChannel, StoreChannel, PartialMessageable
from .threads import Thread
InteractionChannel = Union[
VoiceChannel, StageChannel, TextChannel, CategoryChannel, StoreChannel, Thread, PartialMessageable
]
InteractionChannel = Union[TextChannel, CategoryChannel, StoreChannel, Thread, PartialMessageable]
MISSING: Any = utils.MISSING
@ -179,7 +179,7 @@ class Interaction:
type = ChannelType.text if self.guild_id is not None else ChannelType.private
return PartialMessageable(state=self._state, id=self.channel_id, type=type)
return None
return channel
return channel # type: ignore
@property
def permissions(self) -> Permissions:
@ -369,20 +369,20 @@ class InteractionResponse:
"""
__slots__: Tuple[str, ...] = (
"_responded",
"responded_at",
"_parent",
)
def __init__(self, parent: Interaction):
self.responded_at: Optional[datetime] = None
self._parent: Interaction = parent
self._responded: bool = False
def is_done(self) -> bool:
""":class:`bool`: Indicates whether an interaction response has been done before.
An interaction can only be responded to once.
"""
return self._responded
return self.responded_at is not None
async def defer(self, *, ephemeral: bool = False) -> None:
"""|coro|
@ -405,7 +405,7 @@ class InteractionResponse:
InteractionResponded
This interaction has already been responded to before.
"""
if self._responded:
if self.is_done():
raise InteractionResponded(self._parent)
defer_type: int = 0
@ -423,7 +423,8 @@ class InteractionResponse:
await adapter.create_interaction_response(
parent.id, parent.token, session=parent._session, type=defer_type, data=data
)
self._responded = True
self.responded_at = utils.utcnow()
async def pong(self) -> None:
"""|coro|
@ -439,7 +440,7 @@ class InteractionResponse:
InteractionResponded
This interaction has already been responded to before.
"""
if self._responded:
if self.is_done():
raise InteractionResponded(self._parent)
parent = self._parent
@ -448,7 +449,7 @@ class InteractionResponse:
await adapter.create_interaction_response(
parent.id, parent.token, session=parent._session, type=InteractionResponseType.pong.value
)
self._responded = True
self.responded_at = utils.utcnow()
async def send_message(
self,
@ -494,7 +495,7 @@ class InteractionResponse:
InteractionResponded
This interaction has already been responded to before.
"""
if self._responded:
if self.is_done():
raise InteractionResponded(self._parent)
payload: Dict[str, Any] = {
@ -537,7 +538,7 @@ class InteractionResponse:
self._parent._state.store_view(view)
self._responded = True
self.responded_at = utils.utcnow()
async def edit_message(
self,
@ -578,7 +579,7 @@ class InteractionResponse:
InteractionResponded
This interaction has already been responded to before.
"""
if self._responded:
if self.is_done():
raise InteractionResponded(self._parent)
parent = self._parent
@ -629,7 +630,7 @@ class InteractionResponse:
if view and not view.is_finished():
state.store_view(view, message_id)
self._responded = True
self.responded_at = utils.utcnow()
class _InteractionMessageState: