loopbot-discord-sdk 1.0.6__tar.gz → 1.0.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/PKG-INFO +1 -1
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/bot.py +32 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/context/base.py +49 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot_discord_sdk.egg-info/PKG-INFO +1 -1
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/pyproject.toml +1 -1
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/README.md +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/__init__.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/__init__.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/action_row.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/button.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/container.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/embed.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/file.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/media_gallery.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/modal.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/section.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/select_menu.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/separator.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/builders/text_display.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/client.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/context/__init__.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/context/button.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/context/command.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/context/modal.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/context/select.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/database.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot/types.py +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot_discord_sdk.egg-info/SOURCES.txt +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot_discord_sdk.egg-info/dependency_links.txt +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot_discord_sdk.egg-info/requires.txt +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot_discord_sdk.egg-info/top_level.txt +0 -0
- {loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/setup.cfg +0 -0
|
@@ -14,6 +14,10 @@ from .context.modal import ModalContext
|
|
|
14
14
|
from .context.select import SelectContext
|
|
15
15
|
from .types import InteractionType
|
|
16
16
|
|
|
17
|
+
# ANSI color codes for warnings
|
|
18
|
+
YELLOW = '\033[93m'
|
|
19
|
+
RESET = '\033[0m'
|
|
20
|
+
|
|
17
21
|
|
|
18
22
|
CommandHandler = Callable[[CommandContext], None]
|
|
19
23
|
ButtonHandler = Callable[[ButtonContext], None]
|
|
@@ -111,6 +115,13 @@ class Bot:
|
|
|
111
115
|
ctx = CommandContext(interaction, self._client, self._application_id)
|
|
112
116
|
command.handler(ctx)
|
|
113
117
|
response = ctx.response
|
|
118
|
+
if not response:
|
|
119
|
+
print(
|
|
120
|
+
f"{YELLOW}[Loop SDK] ⚠️ O handler do comando '{command_name}' não definiu uma resposta! "
|
|
121
|
+
f"Use ctx.reply(), ctx.reply_with_components(), ctx.defer() ou ctx.show_modal().{RESET}"
|
|
122
|
+
)
|
|
123
|
+
else:
|
|
124
|
+
print(f"[Loop SDK] No handler for command: {command_name}")
|
|
114
125
|
|
|
115
126
|
elif interaction_type == InteractionType.MESSAGE_COMPONENT:
|
|
116
127
|
custom_id = data.get("custom_id", "")
|
|
@@ -123,6 +134,13 @@ class Bot:
|
|
|
123
134
|
ctx = ButtonContext(interaction, self._client, self._application_id)
|
|
124
135
|
handler(ctx)
|
|
125
136
|
response = ctx.response
|
|
137
|
+
if not response:
|
|
138
|
+
print(
|
|
139
|
+
f"{YELLOW}[Loop SDK] ⚠️ O handler do botão '{custom_id}' não definiu uma resposta! "
|
|
140
|
+
f"Use ctx.reply(), ctx.update(), ctx.defer_update() ou ctx.show_modal().{RESET}"
|
|
141
|
+
)
|
|
142
|
+
else:
|
|
143
|
+
print(f"[Loop SDK] No handler for button: {custom_id}")
|
|
126
144
|
|
|
127
145
|
# Select Menu (type 3)
|
|
128
146
|
elif component_type == 3:
|
|
@@ -131,6 +149,13 @@ class Bot:
|
|
|
131
149
|
ctx = SelectContext(interaction, self._client, self._application_id)
|
|
132
150
|
handler(ctx)
|
|
133
151
|
response = ctx.response
|
|
152
|
+
if not response:
|
|
153
|
+
print(
|
|
154
|
+
f"{YELLOW}[Loop SDK] ⚠️ O handler do select '{custom_id}' não definiu uma resposta! "
|
|
155
|
+
f"Use ctx.reply(), ctx.update() ou ctx.defer_update().{RESET}"
|
|
156
|
+
)
|
|
157
|
+
else:
|
|
158
|
+
print(f"[Loop SDK] No handler for select: {custom_id}")
|
|
134
159
|
|
|
135
160
|
elif interaction_type == InteractionType.MODAL_SUBMIT:
|
|
136
161
|
custom_id = data.get("custom_id", "")
|
|
@@ -140,6 +165,13 @@ class Bot:
|
|
|
140
165
|
ctx = ModalContext(interaction, self._client, self._application_id)
|
|
141
166
|
handler(ctx)
|
|
142
167
|
response = ctx.response
|
|
168
|
+
if not response:
|
|
169
|
+
print(
|
|
170
|
+
f"{YELLOW}[Loop SDK] ⚠️ O handler do modal '{custom_id}' não definiu uma resposta! "
|
|
171
|
+
f"Use ctx.reply(), ctx.reply_with_components() ou ctx.defer_update().{RESET}"
|
|
172
|
+
)
|
|
173
|
+
else:
|
|
174
|
+
print(f"[Loop SDK] No handler for modal: {custom_id}")
|
|
143
175
|
|
|
144
176
|
# Send response
|
|
145
177
|
if response:
|
|
@@ -3,6 +3,7 @@ Base Context for all interaction types
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from typing import Any, Dict, List, Optional, Union
|
|
6
|
+
import warnings
|
|
6
7
|
|
|
7
8
|
from ..types import Interaction, InteractionResponseType, DiscordUser, DiscordMember
|
|
8
9
|
from ..database import Database
|
|
@@ -10,6 +11,10 @@ from ..builders.embed import EmbedBuilder
|
|
|
10
11
|
from ..builders.action_row import ActionRowBuilder
|
|
11
12
|
from ..builders.modal import ModalBuilder
|
|
12
13
|
|
|
14
|
+
# ANSI color codes for warnings
|
|
15
|
+
YELLOW = '\033[93m'
|
|
16
|
+
RESET = '\033[0m'
|
|
17
|
+
|
|
13
18
|
|
|
14
19
|
class BaseContext:
|
|
15
20
|
"""Base context for handling Discord interactions"""
|
|
@@ -25,8 +30,20 @@ class BaseContext:
|
|
|
25
30
|
self._application_id = application_id
|
|
26
31
|
self._response: Optional[Dict[str, Any]] = None
|
|
27
32
|
self._deferred = False
|
|
33
|
+
self._has_responded = False
|
|
28
34
|
self.db = Database(client)
|
|
29
35
|
|
|
36
|
+
def _check_duplicate_response(self, method_name: str) -> bool:
|
|
37
|
+
"""Check if already responded and warn if so"""
|
|
38
|
+
if self._has_responded:
|
|
39
|
+
print(
|
|
40
|
+
f"{YELLOW}[Loop SDK] ⚠️ Você já respondeu a esta interação! "
|
|
41
|
+
f"Chamada duplicada de {method_name}() será ignorada.{RESET}"
|
|
42
|
+
)
|
|
43
|
+
return True
|
|
44
|
+
self._has_responded = True
|
|
45
|
+
return False
|
|
46
|
+
|
|
30
47
|
@property
|
|
31
48
|
def interaction_id(self) -> str:
|
|
32
49
|
return self._interaction.get("id", "")
|
|
@@ -85,6 +102,20 @@ class BaseContext:
|
|
|
85
102
|
ephemeral: bool = False,
|
|
86
103
|
) -> None:
|
|
87
104
|
"""Reply to the interaction"""
|
|
105
|
+
if self._check_duplicate_response("reply"):
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
# Check if any component is a Container (type 17) and warn
|
|
109
|
+
if components:
|
|
110
|
+
for c in components:
|
|
111
|
+
comp_dict = c.to_dict() if hasattr(c, "to_dict") else c
|
|
112
|
+
if comp_dict.get("type") == 17:
|
|
113
|
+
print(
|
|
114
|
+
f"{YELLOW}[Loop SDK] ⚠️ Você está usando reply() com um Container. "
|
|
115
|
+
f"Use reply_with_components() para que Components V2 funcionem corretamente!{RESET}"
|
|
116
|
+
)
|
|
117
|
+
break
|
|
118
|
+
|
|
88
119
|
data: Dict[str, Any] = {}
|
|
89
120
|
|
|
90
121
|
if content:
|
|
@@ -120,6 +151,9 @@ class BaseContext:
|
|
|
120
151
|
ephemeral: bool = False,
|
|
121
152
|
) -> None:
|
|
122
153
|
"""Reply with Components V2 (Container, MediaGallery, etc.)"""
|
|
154
|
+
if self._check_duplicate_response("reply_with_components"):
|
|
155
|
+
return
|
|
156
|
+
|
|
123
157
|
data: Dict[str, Any] = {
|
|
124
158
|
"components": [
|
|
125
159
|
c.to_dict() if hasattr(c, "to_dict") else c
|
|
@@ -143,6 +177,9 @@ class BaseContext:
|
|
|
143
177
|
components: Optional[List[Union[Dict[str, Any], ActionRowBuilder]]] = None,
|
|
144
178
|
) -> None:
|
|
145
179
|
"""Update the original message"""
|
|
180
|
+
if self._check_duplicate_response("update"):
|
|
181
|
+
return
|
|
182
|
+
|
|
146
183
|
data: Dict[str, Any] = {}
|
|
147
184
|
|
|
148
185
|
if content is not None:
|
|
@@ -167,6 +204,9 @@ class BaseContext:
|
|
|
167
204
|
|
|
168
205
|
def update_with_components(self, components: List[Any]) -> None:
|
|
169
206
|
"""Update the original message with Components V2"""
|
|
207
|
+
if self._check_duplicate_response("update_with_components"):
|
|
208
|
+
return
|
|
209
|
+
|
|
170
210
|
self._response = {
|
|
171
211
|
"type": InteractionResponseType.UPDATE_MESSAGE,
|
|
172
212
|
"data": {
|
|
@@ -180,6 +220,9 @@ class BaseContext:
|
|
|
180
220
|
|
|
181
221
|
def defer(self, ephemeral: bool = False) -> None:
|
|
182
222
|
"""Defer the response (show 'thinking...')"""
|
|
223
|
+
if self._check_duplicate_response("defer"):
|
|
224
|
+
return
|
|
225
|
+
|
|
183
226
|
self._deferred = True
|
|
184
227
|
self._response = {
|
|
185
228
|
"type": InteractionResponseType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE,
|
|
@@ -188,6 +231,9 @@ class BaseContext:
|
|
|
188
231
|
|
|
189
232
|
def defer_update(self) -> None:
|
|
190
233
|
"""Defer the update (acknowledge without visible loading)"""
|
|
234
|
+
if self._check_duplicate_response("defer_update"):
|
|
235
|
+
return
|
|
236
|
+
|
|
191
237
|
self._deferred = True
|
|
192
238
|
self._response = {
|
|
193
239
|
"type": InteractionResponseType.DEFERRED_UPDATE_MESSAGE,
|
|
@@ -195,6 +241,9 @@ class BaseContext:
|
|
|
195
241
|
|
|
196
242
|
def show_modal(self, modal: ModalBuilder) -> None:
|
|
197
243
|
"""Show a modal to the user"""
|
|
244
|
+
if self._check_duplicate_response("show_modal"):
|
|
245
|
+
return
|
|
246
|
+
|
|
198
247
|
self._response = {
|
|
199
248
|
"type": InteractionResponseType.MODAL,
|
|
200
249
|
"data": modal.to_dict(),
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "loopbot-discord-sdk"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.7"
|
|
8
8
|
description = "Official Loop Discord SDK for Python - Build Discord bots without websockets"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot_discord_sdk.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot_discord_sdk.egg-info/requires.txt
RENAMED
|
File without changes
|
{loopbot_discord_sdk-1.0.6 → loopbot_discord_sdk-1.0.7}/loopbot_discord_sdk.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|