diff --git a/changelog/626.misc.rst b/changelog/626.misc.rst new file mode 100644 index 0000000000..917b57057a --- /dev/null +++ b/changelog/626.misc.rst @@ -0,0 +1 @@ +Improve type annotations for :attr:`Interaction.followup`\'s ``.send`` method. diff --git a/disnake/interactions/base.py b/disnake/interactions/base.py index ce3b5cc89b..fd268923bf 100644 --- a/disnake/interactions/base.py +++ b/disnake/interactions/base.py @@ -19,6 +19,8 @@ overload, ) +from disnake.webhook.interaction import InteractionFollowupWebhook + from .. import utils from ..app_commands import OptionChoice from ..channel import PartialMessageable, _threaded_guild_channel_factory @@ -52,7 +54,7 @@ from ..role import Role from ..ui.action_row import components_to_dict from ..user import ClientUser, User -from ..webhook.async_ import Webhook, async_context, handle_message_parameters +from ..webhook.async_ import async_context, handle_message_parameters __all__ = ( "Interaction", @@ -310,14 +312,14 @@ def response(self) -> InteractionResponse: return InteractionResponse(self) @utils.cached_slot_property("_cs_followup") - def followup(self) -> Webhook: + def followup(self) -> InteractionFollowupWebhook: """:class:`Webhook`: Returns the follow up webhook for follow up interactions.""" payload = { "id": self.application_id, "type": WebhookType.application.value, "token": self.token, } - return Webhook.from_state(data=payload, state=self._state) + return InteractionFollowupWebhook.from_state(data=payload, state=self._state) @utils.cached_slot_property("_cs_expires_at") def expires_at(self) -> datetime: diff --git a/disnake/webhook/__init__.py b/disnake/webhook/__init__.py index 42e0a37918..bbbd48a2ff 100644 --- a/disnake/webhook/__init__.py +++ b/disnake/webhook/__init__.py @@ -9,10 +9,13 @@ :license: MIT, see LICENSE for more details. """ -from . import async_, sync + +from . import async_, interaction, sync from .async_ import * +from .interaction import * from .sync import * __all__ = [] __all__.extend(async_.__all__) +__all__.extend(interaction.__all__) __all__.extend(sync.__all__) diff --git a/disnake/webhook/async_.py b/disnake/webhook/async_.py index 7e1228a529..a3763e628b 100644 --- a/disnake/webhook/async_.py +++ b/disnake/webhook/async_.py @@ -54,6 +54,8 @@ import datetime from types import TracebackType + from typing_extensions import Self + from ..abc import Snowflake from ..asset import AssetBytes from ..channel import ForumChannel, MediaChannel, StageChannel, TextChannel, VoiceChannel @@ -1255,7 +1257,7 @@ def _as_follower(cls, data, *, channel, user) -> Webhook: return cls(feed, session=session, state=state, token=state.http.token) @classmethod - def from_state(cls, data, state) -> Webhook: + def from_state(cls, data, state) -> Self: session = state.http._HTTPClient__session return cls(data, session=session, state=state, token=state.http.token) diff --git a/disnake/webhook/interaction.py b/disnake/webhook/interaction.py new file mode 100644 index 0000000000..5d8e4399fd --- /dev/null +++ b/disnake/webhook/interaction.py @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +from collections.abc import Sequence +from typing import TYPE_CHECKING + +from ..utils import MISSING +from .async_ import Webhook + +if TYPE_CHECKING: + from typing import List, Optional + + from ..abc import Snowflake + from ..embeds import Embed + from ..file import File + from ..flags import MessageFlags + from ..mentions import AllowedMentions + from ..ui.action_row import Components, MessageUIComponent + from ..ui.view import View + from ..webhook.async_ import WebhookMessage + +__all__ = ("InteractionFollowupWebhook",) + + +class InteractionFollowupWebhook(Webhook): + """A 1:1 copy of :class:`Webhook` meant for :attr:`Interaction.followup`\\'s annotations.""" + + if TYPE_CHECKING: + + async def send( + self, + content: Optional[str] = MISSING, + *, + tts: bool = MISSING, + ephemeral: bool = MISSING, + suppress_embeds: bool = MISSING, + flags: MessageFlags = MISSING, + file: File = MISSING, + files: List[File] = MISSING, + embed: Embed = MISSING, + embeds: List[Embed] = MISSING, + allowed_mentions: AllowedMentions = MISSING, + view: View = MISSING, + components: Components[MessageUIComponent] = MISSING, + thread: Snowflake = MISSING, + thread_name: str = MISSING, + applied_tags: Sequence[Snowflake] = MISSING, + delete_after: float = MISSING, + ) -> WebhookMessage: + """|coro| + + Sends a message using the webhook. + + This is the same as :meth:`Webhook.send` but with type hints changed. Namely, + this method always returns a :class:`WebhookMessage` because ``wait=True`` for + interaction webhooks, and ``username`` and ``avatar_url`` are not supported. + + Returns + ------- + :class:`WebhookMessage` + The message that was sent. + """ + return await super().send( + content=content, + tts=tts, + ephemeral=ephemeral, + embeds=embeds, + embed=embed, + file=file, + files=files, + view=view, + components=components, + allowed_mentions=allowed_mentions, + thread=thread, + thread_name=thread_name, + applied_tags=applied_tags, + delete_after=delete_after, + suppress_embeds=suppress_embeds, + flags=flags, + wait=True, + )