61
61
"MessageInteraction" ,
62
62
"InteractionMetadata" ,
63
63
"AuthorizingIntegrationOwners" ,
64
+ "InteractionCallback" ,
64
65
)
65
66
66
67
if TYPE_CHECKING :
83
84
from .state import ConnectionState
84
85
from .threads import Thread
85
86
from .types .interactions import Interaction as InteractionPayload
86
- from .types .interactions import InteractionData
87
+ from .types .interactions import InteractionCallback as InteractionCallbackPayload
88
+ from .types .interactions import InteractionCallbackResponse , InteractionData
87
89
from .types .interactions import InteractionMetadata as InteractionMetadataPayload
88
90
from .types .interactions import MessageInteraction as MessageInteractionPayload
89
91
from .ui .modal import Modal
@@ -153,6 +155,11 @@ class Interaction:
153
155
The context in which this command was executed.
154
156
155
157
.. versionadded:: 2.6
158
+ callback: Optional[:class:`InteractionCallback`]
159
+ The callback of the interaction. Contains information about the status of the interaction response.
160
+ Will be `None` until the interaction is responded to.
161
+
162
+ .. versionadded:: 2.7
156
163
command: Optional[:class:`ApplicationCommand`]
157
164
The command that this interaction belongs to.
158
165
@@ -189,6 +196,7 @@ class Interaction:
189
196
"entitlements" ,
190
197
"context" ,
191
198
"authorizing_integration_owners" ,
199
+ "callback" ,
192
200
"command" ,
193
201
"view" ,
194
202
"modal" ,
@@ -213,6 +221,7 @@ def __init__(self, *, data: InteractionPayload, state: ConnectionState):
213
221
self ._state : ConnectionState = state
214
222
self ._session : ClientSession = state .http ._HTTPClient__session
215
223
self ._original_response : InteractionMessage | None = None
224
+ self .callback : InteractionCallback | None = None
216
225
self ._from_data (data )
217
226
218
227
def _from_data (self , data : InteractionPayload ):
@@ -468,7 +477,9 @@ async def original_response(self) -> InteractionMessage:
468
477
# TODO: fix later to not raise?
469
478
channel = self .channel
470
479
if channel is None :
471
- raise ClientException ("Channel for message could not be resolved" )
480
+ raise ClientException (
481
+ "Channel for message could not be resolved. Please open a issue on GitHub if you encounter this error."
482
+ )
472
483
473
484
adapter = async_context .get ()
474
485
http = self ._state .http
@@ -860,18 +871,21 @@ async def defer(self, *, ephemeral: bool = False, invisible: bool = True) -> Non
860
871
if defer_type :
861
872
adapter = async_context .get ()
862
873
http = parent ._state .http
863
- await self ._locked_response (
864
- adapter .create_interaction_response (
865
- parent .id ,
866
- parent .token ,
867
- session = parent ._session ,
868
- type = defer_type ,
869
- data = data ,
870
- proxy = http .proxy ,
871
- proxy_auth = http .proxy_auth ,
874
+ callback_response : InteractionCallbackResponse = (
875
+ await self ._locked_response (
876
+ adapter .create_interaction_response (
877
+ parent .id ,
878
+ parent .token ,
879
+ session = parent ._session ,
880
+ type = defer_type ,
881
+ data = data ,
882
+ proxy = http .proxy ,
883
+ proxy_auth = http .proxy_auth ,
884
+ )
872
885
)
873
886
)
874
887
self ._responded = True
888
+ await self ._process_callback_response (callback_response )
875
889
876
890
async def pong (self ) -> None :
877
891
"""|coro|
@@ -894,17 +908,36 @@ async def pong(self) -> None:
894
908
if parent .type is InteractionType .ping :
895
909
adapter = async_context .get ()
896
910
http = parent ._state .http
897
- await self ._locked_response (
898
- adapter .create_interaction_response (
899
- parent .id ,
900
- parent .token ,
901
- session = parent ._session ,
902
- proxy = http .proxy ,
903
- proxy_auth = http .proxy_auth ,
904
- type = InteractionResponseType .pong .value ,
911
+ callback_response : InteractionCallbackResponse = (
912
+ await self ._locked_response (
913
+ adapter .create_interaction_response (
914
+ parent .id ,
915
+ parent .token ,
916
+ session = parent ._session ,
917
+ proxy = http .proxy ,
918
+ proxy_auth = http .proxy_auth ,
919
+ type = InteractionResponseType .pong .value ,
920
+ )
905
921
)
906
922
)
907
923
self ._responded = True
924
+ await self ._process_callback_response (callback_response )
925
+
926
+ async def _process_callback_response (
927
+ self , callback_response : InteractionCallbackResponse
928
+ ):
929
+ if callback_response .get ("resource" , {}).get ("message" ):
930
+ # TODO: fix later to not raise?
931
+ channel = self ._parent .channel
932
+ if channel is None :
933
+ raise ClientException (
934
+ "Channel for message could not be resolved. Please open a issue on GitHub if you encounter this error."
935
+ )
936
+ state = _InteractionMessageState (self ._parent , self ._parent ._state )
937
+ message = InteractionMessage (state = state , channel = channel , data = callback_response ["resource" ]["message" ]) # type: ignore
938
+ self ._parent ._original_response = message
939
+
940
+ self ._parent .callback = InteractionCallback (callback_response ["interaction" ])
908
941
909
942
async def send_message (
910
943
self ,
@@ -1048,16 +1081,18 @@ async def send_message(
1048
1081
adapter = async_context .get ()
1049
1082
http = parent ._state .http
1050
1083
try :
1051
- await self ._locked_response (
1052
- adapter .create_interaction_response (
1053
- parent .id ,
1054
- parent .token ,
1055
- session = parent ._session ,
1056
- type = InteractionResponseType .channel_message .value ,
1057
- proxy = http .proxy ,
1058
- proxy_auth = http .proxy_auth ,
1059
- data = payload ,
1060
- files = files ,
1084
+ callback_response : InteractionCallbackResponse = (
1085
+ await self ._locked_response (
1086
+ adapter .create_interaction_response (
1087
+ parent .id ,
1088
+ parent .token ,
1089
+ session = parent ._session ,
1090
+ type = InteractionResponseType .channel_message .value ,
1091
+ proxy = http .proxy ,
1092
+ proxy_auth = http .proxy_auth ,
1093
+ data = payload ,
1094
+ files = files ,
1095
+ )
1061
1096
)
1062
1097
)
1063
1098
finally :
@@ -1074,6 +1109,7 @@ async def send_message(
1074
1109
self ._parent ._state .store_view (view )
1075
1110
1076
1111
self ._responded = True
1112
+ await self ._process_callback_response (callback_response )
1077
1113
if delete_after is not None :
1078
1114
await self ._parent .delete_original_response (delay = delete_after )
1079
1115
return self ._parent
@@ -1213,16 +1249,18 @@ async def edit_message(
1213
1249
adapter = async_context .get ()
1214
1250
http = parent ._state .http
1215
1251
try :
1216
- await self ._locked_response (
1217
- adapter .create_interaction_response (
1218
- parent .id ,
1219
- parent .token ,
1220
- session = parent ._session ,
1221
- type = InteractionResponseType .message_update .value ,
1222
- proxy = http .proxy ,
1223
- proxy_auth = http .proxy_auth ,
1224
- data = payload ,
1225
- files = files ,
1252
+ callback_response : InteractionCallbackResponse = (
1253
+ await self ._locked_response (
1254
+ adapter .create_interaction_response (
1255
+ parent .id ,
1256
+ parent .token ,
1257
+ session = parent ._session ,
1258
+ type = InteractionResponseType .message_update .value ,
1259
+ proxy = http .proxy ,
1260
+ proxy_auth = http .proxy_auth ,
1261
+ data = payload ,
1262
+ files = files ,
1263
+ )
1226
1264
)
1227
1265
)
1228
1266
finally :
@@ -1235,6 +1273,7 @@ async def edit_message(
1235
1273
state .store_view (view , message_id )
1236
1274
1237
1275
self ._responded = True
1276
+ await self ._process_callback_response (callback_response )
1238
1277
if delete_after is not None :
1239
1278
await self ._parent .delete_original_response (delay = delete_after )
1240
1279
@@ -1270,7 +1309,7 @@ async def send_autocomplete_result(
1270
1309
1271
1310
adapter = async_context .get ()
1272
1311
http = parent ._state .http
1273
- await self ._locked_response (
1312
+ callback_response : InteractionCallbackResponse = await self ._locked_response (
1274
1313
adapter .create_interaction_response (
1275
1314
parent .id ,
1276
1315
parent .token ,
@@ -1283,6 +1322,7 @@ async def send_autocomplete_result(
1283
1322
)
1284
1323
1285
1324
self ._responded = True
1325
+ await self ._process_callback_response (callback_response )
1286
1326
1287
1327
async def send_modal (self , modal : Modal ) -> Interaction :
1288
1328
"""|coro|
@@ -1309,7 +1349,7 @@ async def send_modal(self, modal: Modal) -> Interaction:
1309
1349
payload = modal .to_dict ()
1310
1350
adapter = async_context .get ()
1311
1351
http = parent ._state .http
1312
- await self ._locked_response (
1352
+ callback_response : InteractionCallbackResponse = await self ._locked_response (
1313
1353
adapter .create_interaction_response (
1314
1354
parent .id ,
1315
1355
parent .token ,
@@ -1321,6 +1361,7 @@ async def send_modal(self, modal: Modal) -> Interaction:
1321
1361
)
1322
1362
)
1323
1363
self ._responded = True
1364
+ await self ._process_callback_response (callback_response )
1324
1365
self ._parent ._state .store_modal (modal , self ._parent .user .id )
1325
1366
return self ._parent
1326
1367
@@ -1348,7 +1389,7 @@ async def premium_required(self) -> Interaction:
1348
1389
1349
1390
adapter = async_context .get ()
1350
1391
http = parent ._state .http
1351
- await self ._locked_response (
1392
+ callback_response : InteractionCallbackResponse = await self ._locked_response (
1352
1393
adapter .create_interaction_response (
1353
1394
parent .id ,
1354
1395
parent .token ,
@@ -1359,9 +1400,10 @@ async def premium_required(self) -> Interaction:
1359
1400
)
1360
1401
)
1361
1402
self ._responded = True
1403
+ await self ._process_callback_response (callback_response )
1362
1404
return self ._parent
1363
1405
1364
- async def _locked_response (self , coro : Coroutine [Any , Any , Any ]) -> None :
1406
+ async def _locked_response (self , coro : Coroutine [Any , Any , Any ]) -> Any :
1365
1407
"""|coro|
1366
1408
1367
1409
Wraps a response and makes sure that it's locked while executing.
@@ -1371,16 +1413,24 @@ async def _locked_response(self, coro: Coroutine[Any, Any, Any]) -> None:
1371
1413
coro: Coroutine[Any]
1372
1414
The coroutine to wrap.
1373
1415
1416
+ Returns
1417
+ -------
1418
+ Any
1419
+ The result of the coroutine.
1420
+
1374
1421
Raises
1375
1422
------
1376
1423
InteractionResponded
1377
1424
This interaction has already been responded to before.
1425
+
1426
+ .. versionchanged:: 2.7
1427
+ Return the result of the coroutine
1378
1428
"""
1379
1429
async with self ._response_lock :
1380
1430
if self .is_done ():
1381
1431
coro .close () # cleanup un-awaited coroutine
1382
1432
raise InteractionResponded (self ._parent )
1383
- await coro
1433
+ return await coro
1384
1434
1385
1435
1386
1436
class _InteractionMessageState :
@@ -1704,3 +1754,36 @@ def guild(self) -> Guild | None:
1704
1754
if not self .guild_id :
1705
1755
return None
1706
1756
return self ._state ._get_guild (self .guild_id )
1757
+
1758
+
1759
+ class InteractionCallback :
1760
+ """Information about the status of the interaction response.
1761
+
1762
+ .. versionadded:: 2.7
1763
+ """
1764
+
1765
+ def __init__ (self , data : InteractionCallbackPayload ):
1766
+ self ._response_message_loading : bool = data .get (
1767
+ "response_message_loading" , False
1768
+ )
1769
+ self ._response_message_ephemeral : bool = data .get (
1770
+ "response_message_ephemeral" , False
1771
+ )
1772
+
1773
+ def __repr__ (self ):
1774
+ return (
1775
+ f"<InteractionCallback "
1776
+ f"_response_message_loading={ self ._response_message_loading } "
1777
+ f"_response_message_ephemeral={ self ._response_message_ephemeral } >"
1778
+ )
1779
+
1780
+ def is_loading (self ) -> bool :
1781
+ """Indicates whether the response message is in a loading state."""
1782
+ return self ._response_message_loading
1783
+
1784
+ def is_ephemeral (self ) -> bool :
1785
+ """Indicates whether the response message is ephemeral.
1786
+
1787
+ This might be useful for determining if the message was forced to be ephemeral.
1788
+ """
1789
+ return self ._response_message_ephemeral
0 commit comments