Skip to content

Commit 097a60f

Browse files
authored
Interaction and view error convenience
1 parent 4c3d816 commit 097a60f

File tree

6 files changed

+74
-17
lines changed

6 files changed

+74
-17
lines changed

discord/bot.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -879,15 +879,15 @@ async def process_application_commands(
879879

880880
ctx = await self.get_application_context(interaction)
881881
if command:
882-
ctx.command = command
882+
interaction.command = command
883883
await self.invoke_application_command(ctx)
884884

885885
async def on_application_command_auto_complete(
886886
self, interaction: Interaction, command: ApplicationCommand
887887
) -> None:
888888
async def callback() -> None:
889889
ctx = await self.get_autocomplete_context(interaction)
890-
ctx.command = command
890+
interaction.command = command
891891
return await command.invoke_autocomplete_callback(ctx)
892892

893893
autocomplete_task = self._bot.loop.create_task(callback())

discord/client.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@
6868
if TYPE_CHECKING:
6969
from .abc import GuildChannel, PrivateChannel, Snowflake, SnowflakeTime
7070
from .channel import DMChannel
71+
from .interaction import Interaction
7172
from .member import Member
7273
from .message import Message
7374
from .poll import Poll
75+
from .ui.item import Item
7476
from .voice_client import VoiceProtocol
7577

7678
__all__ = ("Client",)
@@ -541,6 +543,37 @@ async def on_error(self, event_method: str, *args: Any, **kwargs: Any) -> None:
541543
print(f"Ignoring exception in {event_method}", file=sys.stderr)
542544
traceback.print_exc()
543545

546+
async def on_view_error(
547+
self, error: Exception, item: Item, interaction: Interaction
548+
) -> None:
549+
"""|coro|
550+
551+
The default view error handler provided by the client.
552+
553+
This only fires for a view if you did not define its :func:`~discord.ui.View.on_error`.
554+
"""
555+
556+
print(f"Ignoring exception in view {self} for item {item}:", file=sys.stderr)
557+
traceback.print_exception(
558+
error.__class__, error, error.__traceback__, file=sys.stderr
559+
)
560+
561+
async def on_modal_error(
562+
self, error: Exception, interaction: Interaction
563+
) -> None:
564+
"""|coro|
565+
566+
The default modal error handler provided by the client.
567+
The default implementation prints the traceback to stderr.
568+
569+
This only fires for a modal if you did not define its :func:`~discord.ui.Modal.on_error`.
570+
"""
571+
572+
print(f"Ignoring exception in modal {self}:", file=sys.stderr)
573+
traceback.print_exception(
574+
error.__class__, error, error.__traceback__, file=sys.stderr
575+
)
576+
544577
# hooks
545578

546579
async def _call_before_identify_hook(

discord/commands/context.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,13 @@ class ApplicationContext(discord.abc.Messageable):
8080
The bot that the command belongs to.
8181
interaction: :class:`.Interaction`
8282
The interaction object that invoked the command.
83-
command: :class:`.ApplicationCommand`
84-
The command that this context belongs to.
8583
"""
8684

8785
def __init__(self, bot: Bot, interaction: Interaction):
8886
self.bot = bot
8987
self.interaction = interaction
9088

9189
# below attributes will be set after initialization
92-
self.command: ApplicationCommand = None # type: ignore
9390
self.focused: Option = None # type: ignore
9491
self.value: str = None # type: ignore
9592
self.options: dict = None # type: ignore
@@ -136,6 +133,15 @@ async def invoke(
136133
"""
137134
return await command(self, *args, **kwargs)
138135

136+
@property
137+
def command(self) -> ApplicationCommand | None:
138+
"""The command that this context belongs to."""
139+
return self.interaction.command
140+
141+
@command.setter
142+
def command(self, value: ApplicationCommand | None) -> None:
143+
self.interaction.command = value
144+
139145
@cached_property
140146
def channel(self) -> InteractionChannel | None:
141147
"""Union[:class:`abc.GuildChannel`, :class:`PartialMessageable`, :class:`Thread`]:
@@ -393,8 +399,6 @@ class AutocompleteContext:
393399
The bot that the command belongs to.
394400
interaction: :class:`.Interaction`
395401
The interaction object that invoked the autocomplete.
396-
command: :class:`.ApplicationCommand`
397-
The command that this context belongs to.
398402
focused: :class:`.Option`
399403
The option the user is currently typing.
400404
value: :class:`.str`
@@ -409,7 +413,6 @@ def __init__(self, bot: Bot, interaction: Interaction):
409413
self.bot = bot
410414
self.interaction = interaction
411415

412-
self.command: ApplicationCommand = None # type: ignore
413416
self.focused: Option = None # type: ignore
414417
self.value: str = None # type: ignore
415418
self.options: dict = None # type: ignore
@@ -423,3 +426,12 @@ def cog(self) -> Cog | None:
423426
return None
424427

425428
return self.command.cog
429+
430+
@property
431+
def command(self) -> ApplicationCommand | None:
432+
"""The command that this context belongs to."""
433+
return self.interaction.command
434+
435+
@command.setter
436+
def command(self, value: ApplicationCommand | None) -> None:
437+
self.interaction.command = value

discord/interactions.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
VoiceChannel,
7676
)
7777
from .client import Client
78-
from .commands import OptionChoice
78+
from .commands import OptionChoice, ApplicationCommand
7979
from .embeds import Embed
8080
from .mentions import AllowedMentions
8181
from .poll import Poll
@@ -152,6 +152,18 @@ class Interaction:
152152
The context in which this command was executed.
153153
154154
.. versionadded:: 2.6
155+
command: Optional[:class:`ApplicationCommand`]
156+
The command that this interaction belongs to.
157+
158+
.. versionadded:: 2.7
159+
view: Optional[:class:`View`]
160+
The view that this interaction belongs to.
161+
162+
.. versionadded:: 2.7
163+
modal: Optional[:class:`Modal`]
164+
The modal that this interaction belongs to.
165+
166+
.. versionadded:: 2.7
155167
"""
156168

157169
__slots__: tuple[str, ...] = (
@@ -224,6 +236,10 @@ def _from_data(self, data: InteractionPayload):
224236
else None
225237
)
226238

239+
self.command: ApplicationCommand | None = None
240+
self.view: View | None = None
241+
self.modal: Modal | None = None
242+
227243
self.message: Message | None = None
228244
self.channel = None
229245

discord/ui/modal.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,7 @@ async def on_error(self, error: Exception, interaction: Interaction) -> None:
255255
interaction: :class:`~discord.Interaction`
256256
The interaction that led to the failure.
257257
"""
258-
print(f"Ignoring exception in modal {self}:", file=sys.stderr)
259-
traceback.print_exception(
260-
error.__class__, error, error.__traceback__, file=sys.stderr
261-
)
258+
interaction.client.dispatch("modal_error", error, interaction)
262259

263260
async def on_timeout(self) -> None:
264261
"""|coro|
@@ -328,6 +325,7 @@ async def dispatch(self, user_id: int, custom_id: str, interaction: Interaction)
328325
value = self._modals.get(key)
329326
if value is None:
330327
return
328+
interaction.modal = value
331329

332330
try:
333331
components = [

discord/ui/view.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -486,10 +486,7 @@ async def on_error(
486486
interaction: :class:`~discord.Interaction`
487487
The interaction that led to the failure.
488488
"""
489-
print(f"Ignoring exception in view {self} for item {item}:", file=sys.stderr)
490-
traceback.print_exception(
491-
error.__class__, error, error.__traceback__, file=sys.stderr
492-
)
489+
interaction.client.dispatch("view_error", error, item, interaction)
493490

494491
async def _scheduled_task(self, item: Item, interaction: Interaction):
495492
try:
@@ -753,6 +750,7 @@ def dispatch(self, component_type: int, custom_id: str, interaction: Interaction
753750
return
754751

755752
view, item = value
753+
interaction.view = view
756754
item.refresh_state(interaction)
757755
view._dispatch_item(item, interaction)
758756

0 commit comments

Comments
 (0)