aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRapptz <[email protected]>2021-06-05 08:18:45 -0400
committerRapptz <[email protected]>2021-06-05 08:22:44 -0400
commit876b1e0f3eac83b6cf7b965b42f37807ca10f873 (patch)
tree21cc6a21eed8f540ac2e88bbbd6b49a2408c551c
parentFix DM channel permissions not having read_messages (diff)
downloaddiscord.py-876b1e0f3eac83b6cf7b965b42f37807ca10f873.tar.xz
discord.py-876b1e0f3eac83b6cf7b965b42f37807ca10f873.zip
Add View.on_error callback for swallowed exceptions
-rw-r--r--discord/ui/view.py41
1 files changed, 31 insertions, 10 deletions
diff --git a/discord/ui/view.py b/discord/ui/view.py
index 4868196d..38ca9763 100644
--- a/discord/ui/view.py
+++ b/discord/ui/view.py
@@ -27,6 +27,7 @@ from typing import Any, Callable, ClassVar, Dict, Iterator, List, Optional, Sequ
from functools import partial
from itertools import groupby
+import traceback
import asyncio
import sys
import time
@@ -252,7 +253,8 @@ class View:
.. note::
If an exception occurs within the body then the interaction
- check is considered failed.
+ check then :meth:`on_error` is called and it is considered
+ a failure.
Parameters
-----------
@@ -273,18 +275,37 @@ class View:
"""
pass
+ async def on_error(self, error: Exception, item: Item, interaction: Interaction) -> None:
+ """|coro|
+
+ A callback that is called when an item's callback or :meth:`interaction_check`
+ fails with an error.
+
+ The default implementation prints the traceback to stderr.
+
+ Parameters
+ -----------
+ error: :class:`Exception`
+ The exception that was raised.
+ item: :class:`Item`
+ The item that failed the dispatch.
+ interaction: :class:`~discord.Interaction`
+ The interaction that led to the failure.
+ """
+ print(f'Ignoring exception in view {self} for item {item}:', file=sys.stderr)
+ traceback.print_exception(error.__class__, error, error.__traceback__, file=sys.stderr)
+
async def _scheduled_task(self, state: Any, item: Item, interaction: Interaction):
try:
allow = await self.interaction_check(interaction)
- except Exception:
- allow = False
-
- if not allow:
- return
-
- await item.callback(interaction)
- if not interaction.response._responded:
- await interaction.response.defer()
+ if not allow:
+ return
+
+ await item.callback(interaction)
+ if not interaction.response._responded:
+ await interaction.response.defer()
+ except Exception as e:
+ return await self.on_error(e, item, interaction)
def _start_listening(self, store: ViewStore) -> None:
self._cancel_callback = partial(store.remove_view)