scurrypy 0.5__tar.gz → 0.5.2__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.
Potentially problematic release.
This version of scurrypy might be problematic. Click here for more details.
- {scurrypy-0.5 → scurrypy-0.5.2}/PKG-INFO +6 -5
- {scurrypy-0.5 → scurrypy-0.5.2}/README.md +5 -4
- {scurrypy-0.5 → scurrypy-0.5.2}/pyproject.toml +7 -7
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/__init__.py +92 -92
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/client_like.py +1 -1
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/dispatch/command_dispatcher.py +3 -3
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/dispatch/event_dispatcher.py +15 -15
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/events/interaction_events.py +2 -2
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/events/message_events.py +4 -4
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/intents.py +1 -1
- scurrypy-0.5.2/scurrypy/model.py +71 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/parts/channel.py +1 -1
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/parts/command.py +4 -4
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/parts/components.py +12 -12
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/parts/components_v2.py +10 -10
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/parts/message.py +4 -4
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/resources/channel.py +2 -2
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/resources/guild.py +3 -3
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/resources/interaction.py +4 -4
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/resources/message.py +3 -3
- {scurrypy-0.5 → scurrypy-0.5.2}/scurrypy.egg-info/PKG-INFO +6 -5
- scurrypy-0.5.2/scurrypy.egg-info/SOURCES.txt +56 -0
- scurrypy-0.5.2/scurrypy.egg-info/top_level.txt +1 -0
- scurrypy-0.5/discord/model.py +0 -90
- scurrypy-0.5/scurrypy.egg-info/SOURCES.txt +0 -56
- scurrypy-0.5/scurrypy.egg-info/top_level.txt +0 -1
- {scurrypy-0.5 → scurrypy-0.5.2}/LICENSE +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/client.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/config.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/dispatch/__init__.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/dispatch/prefix_dispatcher.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/error.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/events/__init__.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/events/channel_events.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/events/guild_events.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/events/hello_event.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/events/reaction_events.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/events/ready_event.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/gateway.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/http.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/logger.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/models/__init__.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/models/application.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/models/emoji.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/models/guild.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/models/integration.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/models/interaction.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/models/member.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/models/role.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/models/user.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/parts/__init__.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/parts/component_types.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/parts/embed.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/parts/modal.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/parts/role.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/resources/__init__.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/resources/application.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/resources/bot_emojis.py +0 -0
- {scurrypy-0.5/discord → scurrypy-0.5.2/scurrypy}/resources/user.py +0 -0
- {scurrypy-0.5 → scurrypy-0.5.2}/scurrypy.egg-info/dependency_links.txt +0 -0
- {scurrypy-0.5 → scurrypy-0.5.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scurrypy
|
|
3
|
-
Version: 0.5
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: Dataclass-driven Discord API Wrapper in Python
|
|
5
5
|
Author: Furmissile
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -21,10 +21,11 @@ A dataclass-driven Discord API wrapper in Python!
|
|
|
21
21
|
While this wrapper is mainly used for various squirrel-related shenanigans, it can also be used for more generic bot purposes.
|
|
22
22
|
|
|
23
23
|
## Features
|
|
24
|
-
* Command and event handling
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* Command, and event handling
|
|
25
|
+
* Unix shell-style wildcards for component routing
|
|
26
|
+
* Declarative style using decorators
|
|
27
|
+
* Supports both legacy and new features
|
|
28
|
+
* Respects Discord’s rate limits
|
|
28
29
|
|
|
29
30
|
## Notes & Early Status
|
|
30
31
|
* This is an early version — feedback, ideas, and contributions are very welcome! That said, there may be bumps along the way, so expect occasional bugs and quirks.
|
|
@@ -11,10 +11,11 @@ A dataclass-driven Discord API wrapper in Python!
|
|
|
11
11
|
While this wrapper is mainly used for various squirrel-related shenanigans, it can also be used for more generic bot purposes.
|
|
12
12
|
|
|
13
13
|
## Features
|
|
14
|
-
* Command and event handling
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* Command, and event handling
|
|
15
|
+
* Unix shell-style wildcards for component routing
|
|
16
|
+
* Declarative style using decorators
|
|
17
|
+
* Supports both legacy and new features
|
|
18
|
+
* Respects Discord’s rate limits
|
|
18
19
|
|
|
19
20
|
## Notes & Early Status
|
|
20
21
|
* This is an early version — feedback, ideas, and contributions are very welcome! That said, there may be bumps along the way, so expect occasional bugs and quirks.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scurrypy"
|
|
7
|
-
version = "0.5"
|
|
7
|
+
version = "0.5.2"
|
|
8
8
|
|
|
9
9
|
description = "Dataclass-driven Discord API Wrapper in Python"
|
|
10
10
|
readme = "README.md"
|
|
@@ -14,10 +14,10 @@ dependencies = []
|
|
|
14
14
|
|
|
15
15
|
[tool.setuptools]
|
|
16
16
|
packages = [
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
17
|
+
"scurrypy",
|
|
18
|
+
"scurrypy.dispatch",
|
|
19
|
+
"scurrypy.events",
|
|
20
|
+
"scurrypy.models",
|
|
21
|
+
"scurrypy.resources",
|
|
22
|
+
"scurrypy.parts"
|
|
23
23
|
]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# scurrypy
|
|
2
2
|
|
|
3
3
|
import importlib
|
|
4
4
|
from typing import TYPE_CHECKING
|
|
@@ -261,110 +261,110 @@ def __getattr__(name: str):
|
|
|
261
261
|
|
|
262
262
|
mapping = {
|
|
263
263
|
# top-level
|
|
264
|
-
"Logger": "
|
|
265
|
-
"Client": "
|
|
266
|
-
"Intents": "
|
|
267
|
-
"set_intents": "
|
|
268
|
-
"BaseConfig": "
|
|
264
|
+
"Logger": "scurrypy.logger",
|
|
265
|
+
"Client": "scurrypy.client",
|
|
266
|
+
"Intents": "scurrypy.intents",
|
|
267
|
+
"set_intents": "scurrypy.intents",
|
|
268
|
+
"BaseConfig": "scurrypy.config",
|
|
269
269
|
|
|
270
|
-
'InteractionTypes': "
|
|
270
|
+
'InteractionTypes': "scurrypy.dispatch.command_dispatcher",
|
|
271
271
|
|
|
272
|
-
"ReadyEvent": "
|
|
272
|
+
"ReadyEvent": "scurrypy.events.ready_event",
|
|
273
273
|
|
|
274
|
-
"ReactionAddEvent": "
|
|
275
|
-
"ReactionRemoveEvent": "
|
|
276
|
-
"ReactionRemoveEmojiEvent": "
|
|
277
|
-
"ReactionRemoveAllEvent": "
|
|
278
|
-
|
|
279
|
-
"GuildCreateEvent": "
|
|
280
|
-
"GuildUpdateEvent": "
|
|
281
|
-
"GuildDeleteEvent": "
|
|
282
|
-
|
|
283
|
-
"MessageCreateEvent": "
|
|
284
|
-
"MessageUpdateEvent": "
|
|
285
|
-
"MessageDeleteEvent": "
|
|
286
|
-
|
|
287
|
-
"GuildChannelCreateEvent": "
|
|
288
|
-
"GuildChannelUpdateEvent": "
|
|
289
|
-
"GuildChannelDeleteEvent": "
|
|
290
|
-
"ChannelPinsUpdateEvent": "
|
|
291
|
-
|
|
292
|
-
"InteractionEvent": "
|
|
293
|
-
|
|
294
|
-
'ApplicationModel': "
|
|
295
|
-
'EmojiModel': "
|
|
296
|
-
'GuildModel': "
|
|
297
|
-
'MemberModel': "
|
|
298
|
-
'UserModel': "
|
|
299
|
-
'RoleModel': "
|
|
300
|
-
|
|
301
|
-
'ChannelTypes': "
|
|
302
|
-
'GuildChannel': "
|
|
303
|
-
|
|
304
|
-
'CommandTypes': "
|
|
305
|
-
'CommandOptionTypes': "
|
|
306
|
-
'SlashCommand': "
|
|
307
|
-
'UserCommand': "
|
|
308
|
-
'MessageCommand': "
|
|
309
|
-
|
|
310
|
-
'ComponentV2Types': "
|
|
311
|
-
'SectionPart': "
|
|
312
|
-
'TextDisplay': "
|
|
313
|
-
'Thumbnail': "
|
|
314
|
-
'MediaGalleryItem': "
|
|
315
|
-
'MediaGallery': "
|
|
316
|
-
'File': "
|
|
317
|
-
'SeparatorTypes': "
|
|
318
|
-
'Separator': "
|
|
319
|
-
'ContainerPart': "
|
|
320
|
-
'Label': "
|
|
321
|
-
|
|
322
|
-
'ComponentTypes': "
|
|
323
|
-
'ActionRowPart': "
|
|
324
|
-
'ButtonStyles': "
|
|
325
|
-
'Button': "
|
|
326
|
-
'SelectOption': "
|
|
327
|
-
'StringSelect': "
|
|
328
|
-
'TextInputStyles': '
|
|
329
|
-
'TextInput': "
|
|
330
|
-
'DefaultValue': "
|
|
331
|
-
'UserSelect': "
|
|
332
|
-
'RoleSelect': "
|
|
333
|
-
'MentionableSelect': "
|
|
334
|
-
'ChannelSelect': "
|
|
274
|
+
"ReactionAddEvent": "scurrypy.events.reaction_events",
|
|
275
|
+
"ReactionRemoveEvent": "scurrypy.events.reaction_events",
|
|
276
|
+
"ReactionRemoveEmojiEvent": "scurrypy.events.reaction_events",
|
|
277
|
+
"ReactionRemoveAllEvent": "scurrypy.events.reaction_events",
|
|
278
|
+
|
|
279
|
+
"GuildCreateEvent": "scurrypy.events.guild_events",
|
|
280
|
+
"GuildUpdateEvent": "scurrypy.events.guild_events",
|
|
281
|
+
"GuildDeleteEvent": "scurrypy.events.guild_events",
|
|
282
|
+
|
|
283
|
+
"MessageCreateEvent": "scurrypy.events.message_events",
|
|
284
|
+
"MessageUpdateEvent": "scurrypy.events.message_events",
|
|
285
|
+
"MessageDeleteEvent": "scurrypy.events.message_events",
|
|
286
|
+
|
|
287
|
+
"GuildChannelCreateEvent": "scurrypy.events.channel_events",
|
|
288
|
+
"GuildChannelUpdateEvent": "scurrypy.events.channel_events",
|
|
289
|
+
"GuildChannelDeleteEvent": "scurrypy.events.channel_events",
|
|
290
|
+
"ChannelPinsUpdateEvent": "scurrypy.events.channel_events",
|
|
291
|
+
|
|
292
|
+
"InteractionEvent": "scurrypy.events.interaction_events",
|
|
293
|
+
|
|
294
|
+
'ApplicationModel': "scurrypy.models.application",
|
|
295
|
+
'EmojiModel': "scurrypy.models.emoji",
|
|
296
|
+
'GuildModel': "scurrypy.models.guild",
|
|
297
|
+
'MemberModel': "scurrypy.models.member",
|
|
298
|
+
'UserModel': "scurrypy.models.user",
|
|
299
|
+
'RoleModel': "scurrypy.models.role",
|
|
300
|
+
|
|
301
|
+
'ChannelTypes': "scurrypy.parts.channel",
|
|
302
|
+
'GuildChannel': "scurrypy.parts.channel",
|
|
303
|
+
|
|
304
|
+
'CommandTypes': "scurrypy.parts.command",
|
|
305
|
+
'CommandOptionTypes': "scurrypy.parts.command",
|
|
306
|
+
'SlashCommand': "scurrypy.parts.command",
|
|
307
|
+
'UserCommand': "scurrypy.parts.command",
|
|
308
|
+
'MessageCommand': "scurrypy.parts.command",
|
|
309
|
+
|
|
310
|
+
'ComponentV2Types': "scurrypy.parts.components_v2",
|
|
311
|
+
'SectionPart': "scurrypy.parts.components_v2",
|
|
312
|
+
'TextDisplay': "scurrypy.parts.components_v2",
|
|
313
|
+
'Thumbnail': "scurrypy.parts.components_v2",
|
|
314
|
+
'MediaGalleryItem': "scurrypy.parts.components_v2",
|
|
315
|
+
'MediaGallery': "scurrypy.parts.components_v2",
|
|
316
|
+
'File': "scurrypy.parts.components_v2",
|
|
317
|
+
'SeparatorTypes': "scurrypy.parts.components_v2",
|
|
318
|
+
'Separator': "scurrypy.parts.components_v2",
|
|
319
|
+
'ContainerPart': "scurrypy.parts.components_v2",
|
|
320
|
+
'Label': "scurrypy.parts.components_v2",
|
|
321
|
+
|
|
322
|
+
'ComponentTypes': "scurrypy.parts.components",
|
|
323
|
+
'ActionRowPart': "scurrypy.parts.components",
|
|
324
|
+
'ButtonStyles': "scurrypy.parts.components",
|
|
325
|
+
'Button': "scurrypy.parts.components",
|
|
326
|
+
'SelectOption': "scurrypy.parts.components",
|
|
327
|
+
'StringSelect': "scurrypy.parts.components",
|
|
328
|
+
'TextInputStyles': 'scurrypy.parts.components',
|
|
329
|
+
'TextInput': "scurrypy.parts.components",
|
|
330
|
+
'DefaultValue': "scurrypy.parts.components",
|
|
331
|
+
'UserSelect': "scurrypy.parts.components",
|
|
332
|
+
'RoleSelect': "scurrypy.parts.components",
|
|
333
|
+
'MentionableSelect': "scurrypy.parts.components",
|
|
334
|
+
'ChannelSelect': "scurrypy.parts.components",
|
|
335
335
|
|
|
336
|
-
'EmbedAuthor': "
|
|
337
|
-
'EmbedThumbnail': "
|
|
338
|
-
'EmbedField': "
|
|
339
|
-
'EmbedImage': "
|
|
340
|
-
'EmbedFooter': "
|
|
341
|
-
'EmbedPart': "
|
|
336
|
+
'EmbedAuthor': "scurrypy.parts.embed",
|
|
337
|
+
'EmbedThumbnail': "scurrypy.parts.embed",
|
|
338
|
+
'EmbedField': "scurrypy.parts.embed",
|
|
339
|
+
'EmbedImage': "scurrypy.parts.embed",
|
|
340
|
+
'EmbedFooter': "scurrypy.parts.embed",
|
|
341
|
+
'EmbedPart': "scurrypy.parts.embed",
|
|
342
342
|
|
|
343
|
-
'MessageFlags': "
|
|
344
|
-
'MessageReferenceTypes': "
|
|
345
|
-
'MessageReference': "
|
|
346
|
-
'Attachment': "
|
|
347
|
-
'MessagePart': "
|
|
343
|
+
'MessageFlags': "scurrypy.parts.message",
|
|
344
|
+
'MessageReferenceTypes': "scurrypy.parts.message",
|
|
345
|
+
'MessageReference': "scurrypy.parts.message",
|
|
346
|
+
'Attachment': "scurrypy.parts.message",
|
|
347
|
+
'MessagePart': "scurrypy.parts.message",
|
|
348
348
|
|
|
349
|
-
'ModalPart': "
|
|
350
|
-
'Role': "
|
|
349
|
+
'ModalPart': "scurrypy.parts.modal",
|
|
350
|
+
'Role': "scurrypy.parts.role",
|
|
351
351
|
|
|
352
|
-
'ApplicationFlags': "
|
|
353
|
-
'Application': "
|
|
352
|
+
'ApplicationFlags': "scurrypy.resources.application",
|
|
353
|
+
'Application': "scurrypy.resources.application",
|
|
354
354
|
|
|
355
|
-
'BotEmojis': "
|
|
355
|
+
'BotEmojis': "scurrypy.resources.bot_emojis",
|
|
356
356
|
|
|
357
|
-
'PinnedMessage': "
|
|
358
|
-
'Channel': "
|
|
357
|
+
'PinnedMessage': "scurrypy.resources.channel",
|
|
358
|
+
'Channel': "scurrypy.resources.channel",
|
|
359
359
|
|
|
360
|
-
'Guild': "
|
|
360
|
+
'Guild': "scurrypy.resources.guild",
|
|
361
361
|
|
|
362
|
-
'InteractionCallbackTypes': "
|
|
363
|
-
'Interaction': "
|
|
362
|
+
'InteractionCallbackTypes': "scurrypy.resources.interaction",
|
|
363
|
+
'Interaction': "scurrypy.resources.interaction",
|
|
364
364
|
|
|
365
|
-
'Message': "
|
|
365
|
+
'Message': "scurrypy.resources.message",
|
|
366
366
|
|
|
367
|
-
'User': "
|
|
367
|
+
'User': "scurrypy.resources.user"
|
|
368
368
|
}
|
|
369
369
|
|
|
370
370
|
module = importlib.import_module(mapping[name])
|
|
@@ -5,7 +5,7 @@ from .http import HTTPClient
|
|
|
5
5
|
from .logger import Logger
|
|
6
6
|
|
|
7
7
|
class ClientLike(Protocol):
|
|
8
|
-
"""Exposes a common interface for [`Client`][
|
|
8
|
+
"""Exposes a common interface for [`Client`][scurrypy.client.Client]."""
|
|
9
9
|
application_id: int
|
|
10
10
|
"""Bot's application ID."""
|
|
11
11
|
|
|
@@ -25,7 +25,7 @@ class CommandDispatcher:
|
|
|
25
25
|
InteractionTypes.MESSAGE_COMPONENT: MessageComponentData,
|
|
26
26
|
InteractionTypes.MODAL_SUBMIT: ModalData
|
|
27
27
|
}
|
|
28
|
-
"""Maps [`InteractionTypes`][
|
|
28
|
+
"""Maps [`InteractionTypes`][scurrypy.dispatch.command_dispatcher.InteractionTypes] to their respective dataclass."""
|
|
29
29
|
|
|
30
30
|
def __init__(self, client: ClientLike):
|
|
31
31
|
self.application_id = client.application_id
|
|
@@ -66,7 +66,7 @@ class CommandDispatcher:
|
|
|
66
66
|
await self._http.request(
|
|
67
67
|
'PUT',
|
|
68
68
|
f"applications/{self.application_id}/guilds/{guild_id}/commands",
|
|
69
|
-
data=[command.
|
|
69
|
+
data=[command.to_dict() for command in cmds]
|
|
70
70
|
)
|
|
71
71
|
|
|
72
72
|
async def _register_global_commands(self, commands: list):
|
|
@@ -76,7 +76,7 @@ class CommandDispatcher:
|
|
|
76
76
|
commands (list): list of serialized commands
|
|
77
77
|
"""
|
|
78
78
|
|
|
79
|
-
global_commands = [command.
|
|
79
|
+
global_commands = [command.to_dict() for command in commands]
|
|
80
80
|
|
|
81
81
|
await self._http.request('PUT', f"applications/{self.application_id}/commands", data=global_commands)
|
|
82
82
|
|
|
@@ -7,25 +7,25 @@ class EventDispatcher:
|
|
|
7
7
|
"""Central hub for handling Discord Gateway events."""
|
|
8
8
|
|
|
9
9
|
RESOURCE_MAP = { # maps discord events to their respective dataclass (lazy loading)
|
|
10
|
-
'READY': ('
|
|
10
|
+
'READY': ('scurrypy.events.ready_event', 'ReadyEvent'),
|
|
11
11
|
|
|
12
|
-
'GUILD_CREATE': ('
|
|
13
|
-
'GUILD_UPDATE': ('
|
|
14
|
-
'GUILD_DELETE': ('
|
|
12
|
+
'GUILD_CREATE': ('scurrypy.events.guild_events', 'GuildCreateEvent'),
|
|
13
|
+
'GUILD_UPDATE': ('scurrypy.events.guild_events', 'GuildUpdateEvent'),
|
|
14
|
+
'GUILD_DELETE': ('scurrypy.events.guild_events', 'GuildDeleteEvent'),
|
|
15
15
|
|
|
16
|
-
'CHANNEL_CREATE': ('
|
|
17
|
-
'CHANNEL_UPDATE': ('
|
|
18
|
-
'CHANNEL_DELETE': ('
|
|
19
|
-
'CHANNEL_PINS_UPDATE': ('
|
|
16
|
+
'CHANNEL_CREATE': ('scurrypy.events.channel_events', 'GuildChannelCreateEvent'),
|
|
17
|
+
'CHANNEL_UPDATE': ('scurrypy.events.channel_events', 'GuildChannelUpdateEvent'),
|
|
18
|
+
'CHANNEL_DELETE': ('scurrypy.events.channel_events', 'GuildChannelDeleteEvent'),
|
|
19
|
+
'CHANNEL_PINS_UPDATE': ('scurrypy.events.channel_events', 'ChannelPinsUpdateEvent'),
|
|
20
20
|
|
|
21
|
-
'MESSAGE_CREATE': ('
|
|
22
|
-
'MESSAGE_UPDATE': ('
|
|
23
|
-
'MESSAGE_DELETE': ('
|
|
21
|
+
'MESSAGE_CREATE': ('scurrypy.events.message_events', 'MessageCreateEvent'),
|
|
22
|
+
'MESSAGE_UPDATE': ('scurrypy.events.message_events', 'MessageUpdateEvent'),
|
|
23
|
+
'MESSAGE_DELETE': ('scurrypy.events.message_events', 'MessageDeleteEvent'),
|
|
24
24
|
|
|
25
|
-
'MESSAGE_REACTION_ADD': ('
|
|
26
|
-
'MESSAGE_REACTION_REMOVE': ('
|
|
27
|
-
'MESSAGE_REACTION_REMOVE_ALL': ('
|
|
28
|
-
'MESSAGE_REACTION_REMOVE_EMOJI': ('
|
|
25
|
+
'MESSAGE_REACTION_ADD': ('scurrypy.events.reaction_events', 'ReactionAddEvent'),
|
|
26
|
+
'MESSAGE_REACTION_REMOVE': ('scurrypy.events.reaction_events', 'ReactionRemoveEvent'),
|
|
27
|
+
'MESSAGE_REACTION_REMOVE_ALL': ('scurrypy.events.reaction_events', 'ReactionRemoveAllEvent'),
|
|
28
|
+
'MESSAGE_REACTION_REMOVE_EMOJI': ('scurrypy.events.reaction_events', 'ReactionRemoveEmojiEvent'),
|
|
29
29
|
|
|
30
30
|
# and other events...
|
|
31
31
|
}
|
|
@@ -15,7 +15,7 @@ class ApplicationCommandOptionData(DataModel):
|
|
|
15
15
|
"""Name of the command option."""
|
|
16
16
|
|
|
17
17
|
type: int
|
|
18
|
-
"""Type of command option. See [`CommandOptionTypes`][
|
|
18
|
+
"""Type of command option. See [`CommandOptionTypes`][scurrypy.parts.command.CommandOptionTypes]."""
|
|
19
19
|
|
|
20
20
|
value: str | int | float | bool
|
|
21
21
|
"""Input value for option."""
|
|
@@ -153,7 +153,7 @@ class InteractionEvent(DataModel):
|
|
|
153
153
|
"""Represents the interaction response."""
|
|
154
154
|
|
|
155
155
|
interaction: Interaction
|
|
156
|
-
"""Interaction resource object. See [`Interaction`][
|
|
156
|
+
"""Interaction resource object. See [`Interaction`][scurrypy.resources.interaction.Interaction]."""
|
|
157
157
|
|
|
158
158
|
data: Optional[ApplicationCommandData | MessageComponentData | ModalData] = None
|
|
159
159
|
"""Interaction response data."""
|
|
@@ -9,25 +9,25 @@ from ..models.member import MemberModel
|
|
|
9
9
|
class MessageCreateEvent(DataModel):
|
|
10
10
|
"""Received when a message is created."""
|
|
11
11
|
message: Message
|
|
12
|
-
"""Message resource object. See [`Resource.Message`][
|
|
12
|
+
"""Message resource object. See [`Resource.Message`][scurrypy.resources.message.Message]."""
|
|
13
13
|
|
|
14
14
|
guild_id: Optional[int]
|
|
15
15
|
"""Guild ID of the updated message (if in a guild channel)."""
|
|
16
16
|
|
|
17
17
|
member: Optional[MemberModel] # guild-only author info
|
|
18
|
-
"""Partial Member object of the author of the message. See [`MemberModel`][
|
|
18
|
+
"""Partial Member object of the author of the message. See [`MemberModel`][scurrypy.models.member.MemberModel]."""
|
|
19
19
|
|
|
20
20
|
@dataclass
|
|
21
21
|
class MessageUpdateEvent(DataModel):
|
|
22
22
|
"""Received when a message is updated."""
|
|
23
23
|
message: Message
|
|
24
|
-
"""Message resource object. See [`Resource.Message`][
|
|
24
|
+
"""Message resource object. See [`Resource.Message`][scurrypy.resources.message.Message]."""
|
|
25
25
|
|
|
26
26
|
guild_id: Optional[int]
|
|
27
27
|
"""Guild ID of the updated message (if in a guild channel)."""
|
|
28
28
|
|
|
29
29
|
member: Optional[MemberModel]
|
|
30
|
-
"""Partial Member object of the author of the message. See [`MemberModel`][
|
|
30
|
+
"""Partial Member object of the author of the message. See [`MemberModel`][scurrypy.models.member.MemberModel]."""
|
|
31
31
|
|
|
32
32
|
@dataclass
|
|
33
33
|
class MessageDeleteEvent(DataModel):
|
|
@@ -54,7 +54,7 @@ class IntentFlagParams(TypedDict, total=False):
|
|
|
54
54
|
message_content: bool
|
|
55
55
|
|
|
56
56
|
def set_intents(**flags: Unpack[IntentFlagParams]):
|
|
57
|
-
"""Set bot intents using [`IntentFlagParams`][
|
|
57
|
+
"""Set bot intents using [`IntentFlagParams`][scurrypy.intents.IntentFlagParams].
|
|
58
58
|
`Intents.DEFAULT` = (GUILDS | GUILD_MESSAGES) will also be set.
|
|
59
59
|
|
|
60
60
|
Args:
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from dataclasses import dataclass, fields, is_dataclass
|
|
2
|
+
from typing import get_args, get_origin, Union
|
|
3
|
+
|
|
4
|
+
from .http import HTTPClient
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class DataModel:
|
|
8
|
+
"""DataModel is a base class for Discord JSONs that provides hydration from raw dicts,
|
|
9
|
+
optional field defaults, and access to HTTP-bound methods.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def from_dict(cls, data: dict, http: 'HTTPClient' = None):
|
|
14
|
+
"""Hydrates the given data into the dataclass child.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
data (dict): JSON data
|
|
18
|
+
http (HTTPClient, optional): HTTP session for requests
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
(dataclass): hydrated dataclass
|
|
22
|
+
"""
|
|
23
|
+
def unwrap_optional(t):
|
|
24
|
+
if get_origin(t) is Union:
|
|
25
|
+
args = tuple(a for a in get_args(t) if a is not type(None))
|
|
26
|
+
return args[0] if len(args) == 1 else Union[args]
|
|
27
|
+
return t
|
|
28
|
+
|
|
29
|
+
kwargs = {}
|
|
30
|
+
for f in fields(cls):
|
|
31
|
+
v = data.get(f.name)
|
|
32
|
+
t = unwrap_optional(f.type)
|
|
33
|
+
|
|
34
|
+
if v is None:
|
|
35
|
+
kwargs[f.name] = None
|
|
36
|
+
elif is_dataclass(t):
|
|
37
|
+
kwargs[f.name] = t.from_dict(v, http)
|
|
38
|
+
elif get_origin(t) is list:
|
|
39
|
+
lt = get_args(t)[0]
|
|
40
|
+
kwargs[f.name] = [lt.from_dict(x, http) if is_dataclass(lt) else x for x in v]
|
|
41
|
+
else:
|
|
42
|
+
try:
|
|
43
|
+
kwargs[f.name] = t(v)
|
|
44
|
+
except Exception:
|
|
45
|
+
kwargs[f.name] = v # fallback to raw
|
|
46
|
+
|
|
47
|
+
inst = cls(**kwargs)
|
|
48
|
+
if http: inst._http = http
|
|
49
|
+
return inst
|
|
50
|
+
|
|
51
|
+
def to_dict(self):
|
|
52
|
+
"""Recursively turns the dataclass into a dictionary and drops empty fields.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
(dict): serialized dataclasss
|
|
56
|
+
"""
|
|
57
|
+
def serialize(val):
|
|
58
|
+
if isinstance(val, list):
|
|
59
|
+
return [serialize(v) for v in val if v is not None]
|
|
60
|
+
if isinstance(val, DataModel):
|
|
61
|
+
return val.to_dict()
|
|
62
|
+
return val
|
|
63
|
+
|
|
64
|
+
result = {}
|
|
65
|
+
for f in fields(self):
|
|
66
|
+
if f.name.startswith('_'):
|
|
67
|
+
continue
|
|
68
|
+
val = getattr(self, f.name)
|
|
69
|
+
# if val not in (None, [], {}, "", 0):
|
|
70
|
+
result[f.name] = serialize(val)
|
|
71
|
+
return result
|
|
@@ -27,7 +27,7 @@ class GuildChannel(DataModel):
|
|
|
27
27
|
"""Name of the channel."""
|
|
28
28
|
|
|
29
29
|
type: Optional[int] = None
|
|
30
|
-
"""Type of channel. See [`ChannelTypes`][
|
|
30
|
+
"""Type of channel. See [`ChannelTypes`][scurrypy.parts.channel.ChannelTypes]."""
|
|
31
31
|
|
|
32
32
|
topic: Optional[str] = None
|
|
33
33
|
"""Topic of channel."""
|
|
@@ -42,7 +42,7 @@ class CommandOption(DataModel):
|
|
|
42
42
|
"""Option for a slash command."""
|
|
43
43
|
|
|
44
44
|
type: int
|
|
45
|
-
"""Type of option. See [`CommandOptionTypes`][
|
|
45
|
+
"""Type of option. See [`CommandOptionTypes`][scurrypy.parts.command.CommandOptionTypes]."""
|
|
46
46
|
|
|
47
47
|
name: str
|
|
48
48
|
"""Name of option."""
|
|
@@ -67,7 +67,7 @@ class SlashCommand(DataModel):
|
|
|
67
67
|
"""Parameters or options for the command."""
|
|
68
68
|
|
|
69
69
|
type: int = field(init=False, default=CommandTypes.CHAT_INPUT)
|
|
70
|
-
"""Command type. Always `CommandTypes.CHAT_INPUT` for this class. See [`CommandTypes`][
|
|
70
|
+
"""Command type. Always `CommandTypes.CHAT_INPUT` for this class. See [`CommandTypes`][scurrypy.parts.command.CommandTypes]."""
|
|
71
71
|
|
|
72
72
|
@dataclass
|
|
73
73
|
class UserCommand(DataModel):
|
|
@@ -77,7 +77,7 @@ class UserCommand(DataModel):
|
|
|
77
77
|
"""Name of the command."""
|
|
78
78
|
|
|
79
79
|
type: int = field(init=False, default=CommandTypes.USER_COMMAND)
|
|
80
|
-
"""Command type. Always `CommandTypes.USER_COMMAND` for this class. See [`CommandTypes`][
|
|
80
|
+
"""Command type. Always `CommandTypes.USER_COMMAND` for this class. See [`CommandTypes`][scurrypy.parts.command.CommandTypes]."""
|
|
81
81
|
|
|
82
82
|
@dataclass
|
|
83
83
|
class MessageCommand(DataModel):
|
|
@@ -87,4 +87,4 @@ class MessageCommand(DataModel):
|
|
|
87
87
|
"""Name of the command."""
|
|
88
88
|
|
|
89
89
|
type: int = field(init=False, default=CommandTypes.MESSAGE_COMMAND)
|
|
90
|
-
"""Command type. Always `CommandTypes.MESSAGE_COMMAND` for this class. See [`CommandTypes`][
|
|
90
|
+
"""Command type. Always `CommandTypes.MESSAGE_COMMAND` for this class. See [`CommandTypes`][scurrypy.parts.command.CommandTypes]."""
|
|
@@ -24,7 +24,7 @@ class ActionRowPart(DataModel, ContainerChild):
|
|
|
24
24
|
"""Up to 5 interactive button components or a single select component."""
|
|
25
25
|
|
|
26
26
|
type: int = field(init=False, default=ComponentTypes.ACTION_ROW)
|
|
27
|
-
"""Component type. Always `ComponentTypes.ACTION_ROW` for this class. See [`ComponentTypes`][
|
|
27
|
+
"""Component type. Always `ComponentTypes.ACTION_ROW` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
|
|
28
28
|
|
|
29
29
|
class ButtonStyles:
|
|
30
30
|
"""Represents button styles for a Button component."""
|
|
@@ -49,7 +49,7 @@ class Button(DataModel, ActionRowChild, SectionAccessory):
|
|
|
49
49
|
"""Represents the Button component."""
|
|
50
50
|
|
|
51
51
|
style: int
|
|
52
|
-
"""A button style. See [`ButtonStyles`][
|
|
52
|
+
"""A button style. See [`ButtonStyles`][scurrypy.parts.components.ButtonStyles]."""
|
|
53
53
|
|
|
54
54
|
custom_id: str
|
|
55
55
|
"""ID for the button."""
|
|
@@ -67,7 +67,7 @@ class Button(DataModel, ActionRowChild, SectionAccessory):
|
|
|
67
67
|
"""Whether the button is disabled. Defaults to False."""
|
|
68
68
|
|
|
69
69
|
type: int = field(init=False, default=ComponentTypes.BUTTON)
|
|
70
|
-
"""Component type. Always `ComponentTypes.BUTTON` for this class. See [`ComponentTypes`][
|
|
70
|
+
"""Component type. Always `ComponentTypes.BUTTON` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
|
|
71
71
|
|
|
72
72
|
@dataclass
|
|
73
73
|
class SelectOption(DataModel):
|
|
@@ -96,7 +96,7 @@ class StringSelect(DataModel, ActionRowChild, LabelChild):
|
|
|
96
96
|
"""ID for the select menu."""
|
|
97
97
|
|
|
98
98
|
options: list[SelectOption] = field(default_factory=list)
|
|
99
|
-
"""Specified choices in a select menu. See [`SelectOption`][
|
|
99
|
+
"""Specified choices in a select menu. See [`SelectOption`][scurrypy.parts.components.SelectOption]."""
|
|
100
100
|
|
|
101
101
|
placeholder: Optional[str] = None
|
|
102
102
|
"""Placeholder text if nothing is selected or default."""
|
|
@@ -114,7 +114,7 @@ class StringSelect(DataModel, ActionRowChild, LabelChild):
|
|
|
114
114
|
"""Whether select menu is disabled in a message. Defaults to False."""
|
|
115
115
|
|
|
116
116
|
type: int = field(init=False, default=ComponentTypes.STRING_SELECT)
|
|
117
|
-
"""Component type. Always `ComponentTypes.STRING_SELECT` for this class. See [`ComponentTypes`][
|
|
117
|
+
"""Component type. Always `ComponentTypes.STRING_SELECT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
|
|
118
118
|
|
|
119
119
|
class TextInputStyles:
|
|
120
120
|
"""Represents the types of Text Inputs."""
|
|
@@ -130,7 +130,7 @@ class TextInput(DataModel, LabelChild):
|
|
|
130
130
|
"""Represents the Text Input component."""
|
|
131
131
|
|
|
132
132
|
style: TextInputStyles = TextInputStyles.SHORT
|
|
133
|
-
"""Text input style. See [`TextInputStyles`][
|
|
133
|
+
"""Text input style. See [`TextInputStyles`][scurrypy.parts.components.TextInputStyles]."""
|
|
134
134
|
|
|
135
135
|
custom_id: str = None
|
|
136
136
|
"""ID for the input."""
|
|
@@ -154,7 +154,7 @@ class TextInput(DataModel, LabelChild):
|
|
|
154
154
|
"""Custom placeholder text if the input is empty."""
|
|
155
155
|
|
|
156
156
|
type: int = field(init=False, default=ComponentTypes.TEXT_INPUT)
|
|
157
|
-
"""Component type. Always `ComponentTypes.TEXT_INPUT` for this class. See [`ComponentTypes`][
|
|
157
|
+
"""Component type. Always `ComponentTypes.TEXT_INPUT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
|
|
158
158
|
|
|
159
159
|
@dataclass
|
|
160
160
|
class DefaultValue(DataModel):
|
|
@@ -178,7 +178,7 @@ class SelectMenu(DataModel):
|
|
|
178
178
|
|
|
179
179
|
default_values: list[DefaultValue] = field(default_factory=list)
|
|
180
180
|
"""
|
|
181
|
-
List of default values for auto-populated select menu components. See [`DefaultValue`][
|
|
181
|
+
List of default values for auto-populated select menu components. See [`DefaultValue`][scurrypy.parts.components.DefaultValue].
|
|
182
182
|
Number of default values must be in the range of `min_values` to `max_values`.
|
|
183
183
|
"""
|
|
184
184
|
|
|
@@ -200,25 +200,25 @@ class UserSelect(SelectMenu, ActionRowChild, LabelChild):
|
|
|
200
200
|
"""Represents the User Select component."""
|
|
201
201
|
|
|
202
202
|
type: int = field(init=False, default=ComponentTypes.USER_SELECT)
|
|
203
|
-
"""Component type. Always `ComponentTypes.USER_SELECT` for this class. See [`ComponentTypes`][
|
|
203
|
+
"""Component type. Always `ComponentTypes.USER_SELECT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
|
|
204
204
|
|
|
205
205
|
@dataclass
|
|
206
206
|
class RoleSelect(SelectMenu, ActionRowChild, LabelChild):
|
|
207
207
|
"""Represents the Role Select component."""
|
|
208
208
|
|
|
209
209
|
type: int = field(init=False, default=ComponentTypes.ROLE_SELECT)
|
|
210
|
-
"""Component type. Always `ComponentTypes.ROLE_SELECT` for this class. See [`ComponentTypes`][
|
|
210
|
+
"""Component type. Always `ComponentTypes.ROLE_SELECT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
|
|
211
211
|
|
|
212
212
|
@dataclass
|
|
213
213
|
class MentionableSelect(SelectMenu, ActionRowChild, LabelChild):
|
|
214
214
|
"""Represents the Mentionable Select component."""
|
|
215
215
|
|
|
216
216
|
type: int = field(init=False, default=ComponentTypes.MENTIONABLE_SELECT)
|
|
217
|
-
"""Component type. Always `ComponentTypes.MENTIONABLE_SELECT` for this class. See [`ComponentTypes`][
|
|
217
|
+
"""Component type. Always `ComponentTypes.MENTIONABLE_SELECT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
|
|
218
218
|
|
|
219
219
|
@dataclass
|
|
220
220
|
class ChannelSelect(SelectMenu, ActionRowChild, LabelChild):
|
|
221
221
|
"""Represents the Channel Select component."""
|
|
222
222
|
|
|
223
223
|
type: int = field(init=False, default=ComponentTypes.CHANNEL_SELECT)
|
|
224
|
-
"""Component type. Always `ComponentTypes.CHANNEL_SELECT` for this class. See [`ComponentTypes`][
|
|
224
|
+
"""Component type. Always `ComponentTypes.CHANNEL_SELECT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
|
|
@@ -25,7 +25,7 @@ class SectionPart(DataModel, ContainerChild):
|
|
|
25
25
|
"""Component(s) representing the content of the section that is contextually associated to the accessory."""
|
|
26
26
|
|
|
27
27
|
type: int = field(init=False, default=ComponentV2Types.SECTION)
|
|
28
|
-
"""Component type. Always `ComponentV2Types.SECTION` for this class. See [`ComponentV2Types`][
|
|
28
|
+
"""Component type. Always `ComponentV2Types.SECTION` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
|
|
29
29
|
|
|
30
30
|
@dataclass
|
|
31
31
|
class TextDisplay(DataModel, ContainerChild, SectionChild):
|
|
@@ -35,7 +35,7 @@ class TextDisplay(DataModel, ContainerChild, SectionChild):
|
|
|
35
35
|
"""Text that will be displayed similar to a message."""
|
|
36
36
|
|
|
37
37
|
type: int = field(init=False, default=ComponentV2Types.TEXT_DISPLAY)
|
|
38
|
-
"""Component type. Always `ComponentV2Types.TEXT_DISPLAY` for this class. See [`ComponentV2Types`][
|
|
38
|
+
"""Component type. Always `ComponentV2Types.TEXT_DISPLAY` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
|
|
39
39
|
|
|
40
40
|
@dataclass
|
|
41
41
|
class Thumbnail(DataModel, SectionAccessory):
|
|
@@ -51,7 +51,7 @@ class Thumbnail(DataModel, SectionAccessory):
|
|
|
51
51
|
"""Whether the thumbnail should be a spoiler (or blurred out)."""
|
|
52
52
|
|
|
53
53
|
type: int = field(init=False, default=ComponentV2Types.THUMBNAIL)
|
|
54
|
-
"""Component type. Always `ComponentV2Types.THUMBNAIL` for this class. See [`ComponentV2Types`][
|
|
54
|
+
"""Component type. Always `ComponentV2Types.THUMBNAIL` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
|
|
55
55
|
|
|
56
56
|
@dataclass
|
|
57
57
|
class MediaGalleryItem(DataModel):
|
|
@@ -71,10 +71,10 @@ class MediaGallery(DataModel, ContainerChild):
|
|
|
71
71
|
"""Represents the Media Gallery component."""
|
|
72
72
|
|
|
73
73
|
items: list[MediaGalleryItem] = field(default_factory=list)
|
|
74
|
-
"""1 to 10 nedia gallery items. See [`MediaGalleryItem`][
|
|
74
|
+
"""1 to 10 nedia gallery items. See [`MediaGalleryItem`][scurrypy.parts.components_v2.MediaGalleryItem]."""
|
|
75
75
|
|
|
76
76
|
type: int = field(init=False, default=ComponentV2Types.MEDIA_GALLERY)
|
|
77
|
-
"""Component type. Always `ComponentV2Types.MEDIA_GALLERY` for this class. See [`ComponentV2Types`][
|
|
77
|
+
"""Component type. Always `ComponentV2Types.MEDIA_GALLERY` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
|
|
78
78
|
|
|
79
79
|
@dataclass
|
|
80
80
|
class File(DataModel, ContainerChild):
|
|
@@ -87,7 +87,7 @@ class File(DataModel, ContainerChild):
|
|
|
87
87
|
"""Whether the thumbnail should be a spoiler (or blurred out)."""
|
|
88
88
|
|
|
89
89
|
type: int = field(init=False, default=ComponentV2Types.FILE)
|
|
90
|
-
"""Component type. Always `ComponentV2Types.File` for this class. See [`ComponentV2Types`][
|
|
90
|
+
"""Component type. Always `ComponentV2Types.File` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
|
|
91
91
|
|
|
92
92
|
class SeparatorTypes:
|
|
93
93
|
"""Represents separator types constants."""
|
|
@@ -106,10 +106,10 @@ class Separator(DataModel, ContainerChild):
|
|
|
106
106
|
"""Whether a visual divider should be displayed in the component. Defaults to True."""
|
|
107
107
|
|
|
108
108
|
spacing: Optional[int] = SeparatorTypes.SMALL_PADDING
|
|
109
|
-
"""Size of separator padding. Defaults to `SMALL_PADDING`. See [`SeparatorTypes`][
|
|
109
|
+
"""Size of separator padding. Defaults to `SMALL_PADDING`. See [`SeparatorTypes`][scurrypy.parts.components_v2.SeparatorTypes]."""
|
|
110
110
|
|
|
111
111
|
type: int = field(init=False, default=ComponentV2Types.SEPARATOR)
|
|
112
|
-
"""Component type. Always `ComponentV2Types.SEPARATOR` for this class. See [`ComponentV2Types`][
|
|
112
|
+
"""Component type. Always `ComponentV2Types.SEPARATOR` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
|
|
113
113
|
|
|
114
114
|
@dataclass
|
|
115
115
|
class ContainerPart(DataModel):
|
|
@@ -125,7 +125,7 @@ class ContainerPart(DataModel):
|
|
|
125
125
|
"""If the container should be blurred out. Defaults to False."""
|
|
126
126
|
|
|
127
127
|
type: int = field(init=False, default=ComponentV2Types.CONTAINER)
|
|
128
|
-
"""Component type. Always `ComponentV2Types.CONTAINER` for this class. See [`ComponentV2Types`][
|
|
128
|
+
"""Component type. Always `ComponentV2Types.CONTAINER` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
|
|
129
129
|
|
|
130
130
|
@dataclass
|
|
131
131
|
class Label(DataModel):
|
|
@@ -141,4 +141,4 @@ class Label(DataModel):
|
|
|
141
141
|
"""An optional description text for the label."""
|
|
142
142
|
|
|
143
143
|
type: int = field(init=False, default=ComponentV2Types.LABEL)
|
|
144
|
-
"""Component type. Always `ComponentV2Types.LABEL` for this class. See [`ComponentV2Types`][
|
|
144
|
+
"""Component type. Always `ComponentV2Types.LABEL` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
|
|
@@ -27,7 +27,7 @@ class MessageFlags:
|
|
|
27
27
|
"""This message includes Discord's V2 Components."""
|
|
28
28
|
|
|
29
29
|
class MessageFlagParams(TypedDict, total=False):
|
|
30
|
-
"""Parameters for setting message flags. See [`MessageFlags`][
|
|
30
|
+
"""Parameters for setting message flags. See [`MessageFlags`][scurrypy.parts.message.MessageFlags]."""
|
|
31
31
|
crossposted: bool
|
|
32
32
|
is_crosspost: bool
|
|
33
33
|
suppress_embeds: bool
|
|
@@ -59,7 +59,7 @@ class MessageReference(DataModel):
|
|
|
59
59
|
"""
|
|
60
60
|
|
|
61
61
|
type: int = MessageReferenceTypes.DEFAULT
|
|
62
|
-
"""Type of reference. Defaults to `DEFAULT`. See [`MessageReferenceTypes`][
|
|
62
|
+
"""Type of reference. Defaults to `DEFAULT`. See [`MessageReferenceTypes`][scurrypy.parts.message.MessageReferenceTypes]."""
|
|
63
63
|
|
|
64
64
|
@dataclass
|
|
65
65
|
class Attachment(DataModel):
|
|
@@ -77,7 +77,7 @@ class Attachment(DataModel):
|
|
|
77
77
|
description: str
|
|
78
78
|
"""Description of the file."""
|
|
79
79
|
|
|
80
|
-
def
|
|
80
|
+
def to_dict(self):
|
|
81
81
|
return {
|
|
82
82
|
'id': self.id,
|
|
83
83
|
'filename': self.filename,
|
|
@@ -92,7 +92,7 @@ class MessagePart(DataModel):
|
|
|
92
92
|
"""Message text content."""
|
|
93
93
|
|
|
94
94
|
flags: Optional[int] = 0
|
|
95
|
-
"""Message flags. See [`MessageFlags`][
|
|
95
|
+
"""Message flags. See [`MessageFlags`][scurrypy.parts.message.MessageFlags]."""
|
|
96
96
|
|
|
97
97
|
components: Optional[list[ActionRowPart | ContainerPart]] = field(default_factory=list)
|
|
98
98
|
"""Components to be attached to this message."""
|
|
@@ -148,7 +148,7 @@ class Channel(DataModel):
|
|
|
148
148
|
if isinstance(message, str):
|
|
149
149
|
message = MessagePart(content=message)
|
|
150
150
|
|
|
151
|
-
data = await self._http.request("POST", f"/channels/{self.id}/messages", data=message.
|
|
151
|
+
data = await self._http.request("POST", f"/channels/{self.id}/messages", data=message.to_dict())
|
|
152
152
|
|
|
153
153
|
return Message.from_dict(data, self._http)
|
|
154
154
|
|
|
@@ -164,7 +164,7 @@ class Channel(DataModel):
|
|
|
164
164
|
Returns:
|
|
165
165
|
(Channel): The updated channel object
|
|
166
166
|
"""
|
|
167
|
-
data = await self._http.request("PATCH", f"/channels/{self.id}", data=channel.
|
|
167
|
+
data = await self._http.request("PATCH", f"/channels/{self.id}", data=channel.to_dict())
|
|
168
168
|
self._update(data)
|
|
169
169
|
|
|
170
170
|
return self
|
|
@@ -136,7 +136,7 @@ class Guild(DataModel):
|
|
|
136
136
|
Returns:
|
|
137
137
|
(Channel): the created channel
|
|
138
138
|
"""
|
|
139
|
-
data = await self._http.request('POST', f'/guilds/{self.id}/channels', data=channel.
|
|
139
|
+
data = await self._http.request('POST', f'/guilds/{self.id}/channels', data=channel.to_dict())
|
|
140
140
|
|
|
141
141
|
return Channel.from_dict(data, self._http)
|
|
142
142
|
|
|
@@ -233,7 +233,7 @@ class Guild(DataModel):
|
|
|
233
233
|
Returns:
|
|
234
234
|
(RoleModel): new role data
|
|
235
235
|
"""
|
|
236
|
-
data = await self._http.request('POST', f'/guilds/{self.id}/roles', data=role.
|
|
236
|
+
data = await self._http.request('POST', f'/guilds/{self.id}/roles', data=role.to_dict())
|
|
237
237
|
|
|
238
238
|
return RoleModel.from_dict(data)
|
|
239
239
|
|
|
@@ -249,7 +249,7 @@ class Guild(DataModel):
|
|
|
249
249
|
Returns:
|
|
250
250
|
(RoleModel): role with changes
|
|
251
251
|
"""
|
|
252
|
-
data = await self._http.request('PATCH', f'/guilds/{self.id}/roles/{role_id}', data=role.
|
|
252
|
+
data = await self._http.request('PATCH', f'/guilds/{self.id}/roles/{role_id}', data=role.to_dict())
|
|
253
253
|
|
|
254
254
|
return RoleModel.from_dict(data)
|
|
255
255
|
|
|
@@ -69,7 +69,7 @@ class Interaction(DataModel):
|
|
|
69
69
|
"""HTTP session for requests."""
|
|
70
70
|
|
|
71
71
|
type: int
|
|
72
|
-
"""Type of interaction. See [`InteractionTypes`][
|
|
72
|
+
"""Type of interaction. See [`InteractionTypes`][scurrypy.dispatch.command_dispatcher.InteractionTypes]."""
|
|
73
73
|
|
|
74
74
|
channel_id: int
|
|
75
75
|
"""ID of the channel where the interaction was sent."""
|
|
@@ -115,7 +115,7 @@ class Interaction(DataModel):
|
|
|
115
115
|
|
|
116
116
|
content = {
|
|
117
117
|
'type': InteractionCallbackTypes.CHANNEL_MESSAGE_WITH_SOURCE,
|
|
118
|
-
'data': message.
|
|
118
|
+
'data': message.to_dict()
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
params = {'with_response': with_response}
|
|
@@ -146,7 +146,7 @@ class Interaction(DataModel):
|
|
|
146
146
|
|
|
147
147
|
content = {
|
|
148
148
|
'type': InteractionCallbackTypes.UPDATE_MESSAGE,
|
|
149
|
-
'data': message.
|
|
149
|
+
'data': message.to_dict()
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
await self._http.request(
|
|
@@ -169,7 +169,7 @@ class Interaction(DataModel):
|
|
|
169
169
|
|
|
170
170
|
content = {
|
|
171
171
|
'type': InteractionCallbackTypes.MODAL,
|
|
172
|
-
'data': modal.
|
|
172
|
+
'data': modal.to_dict()
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
await self._http.request(
|
|
@@ -68,7 +68,7 @@ class Message(DataModel):
|
|
|
68
68
|
data = await self._http.request(
|
|
69
69
|
"POST",
|
|
70
70
|
f"/channels/{self.channel_id}/messages",
|
|
71
|
-
data=message.
|
|
71
|
+
data=message.to_dict(),
|
|
72
72
|
files=[fp.path for fp in message.attachments] if message.attachments else None
|
|
73
73
|
)
|
|
74
74
|
return Message.from_dict(data, self._http)
|
|
@@ -88,7 +88,7 @@ class Message(DataModel):
|
|
|
88
88
|
data = await self._http.request(
|
|
89
89
|
"PATCH",
|
|
90
90
|
f"/channels/{self.channel_id}/messages/{self.id}",
|
|
91
|
-
data=message.
|
|
91
|
+
data=message.to_dict(),
|
|
92
92
|
files=[fp.path for fp in message.attachments] if message.attachments else None)
|
|
93
93
|
|
|
94
94
|
self._update(data)
|
|
@@ -110,7 +110,7 @@ class Message(DataModel):
|
|
|
110
110
|
await self._http.request(
|
|
111
111
|
'POST',
|
|
112
112
|
f"/channels/{self.channel_id}/messages",
|
|
113
|
-
data=message.
|
|
113
|
+
data=message.to_dict(),
|
|
114
114
|
files=[fp.path for fp in message.attachments] if message.attachments else None)
|
|
115
115
|
|
|
116
116
|
async def crosspost(self):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scurrypy
|
|
3
|
-
Version: 0.5
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: Dataclass-driven Discord API Wrapper in Python
|
|
5
5
|
Author: Furmissile
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -21,10 +21,11 @@ A dataclass-driven Discord API wrapper in Python!
|
|
|
21
21
|
While this wrapper is mainly used for various squirrel-related shenanigans, it can also be used for more generic bot purposes.
|
|
22
22
|
|
|
23
23
|
## Features
|
|
24
|
-
* Command and event handling
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* Command, and event handling
|
|
25
|
+
* Unix shell-style wildcards for component routing
|
|
26
|
+
* Declarative style using decorators
|
|
27
|
+
* Supports both legacy and new features
|
|
28
|
+
* Respects Discord’s rate limits
|
|
28
29
|
|
|
29
30
|
## Notes & Early Status
|
|
30
31
|
* This is an early version — feedback, ideas, and contributions are very welcome! That said, there may be bumps along the way, so expect occasional bugs and quirks.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
scurrypy/__init__.py
|
|
5
|
+
scurrypy/client.py
|
|
6
|
+
scurrypy/client_like.py
|
|
7
|
+
scurrypy/config.py
|
|
8
|
+
scurrypy/error.py
|
|
9
|
+
scurrypy/gateway.py
|
|
10
|
+
scurrypy/http.py
|
|
11
|
+
scurrypy/intents.py
|
|
12
|
+
scurrypy/logger.py
|
|
13
|
+
scurrypy/model.py
|
|
14
|
+
scurrypy.egg-info/PKG-INFO
|
|
15
|
+
scurrypy.egg-info/SOURCES.txt
|
|
16
|
+
scurrypy.egg-info/dependency_links.txt
|
|
17
|
+
scurrypy.egg-info/top_level.txt
|
|
18
|
+
scurrypy/dispatch/__init__.py
|
|
19
|
+
scurrypy/dispatch/command_dispatcher.py
|
|
20
|
+
scurrypy/dispatch/event_dispatcher.py
|
|
21
|
+
scurrypy/dispatch/prefix_dispatcher.py
|
|
22
|
+
scurrypy/events/__init__.py
|
|
23
|
+
scurrypy/events/channel_events.py
|
|
24
|
+
scurrypy/events/guild_events.py
|
|
25
|
+
scurrypy/events/hello_event.py
|
|
26
|
+
scurrypy/events/interaction_events.py
|
|
27
|
+
scurrypy/events/message_events.py
|
|
28
|
+
scurrypy/events/reaction_events.py
|
|
29
|
+
scurrypy/events/ready_event.py
|
|
30
|
+
scurrypy/models/__init__.py
|
|
31
|
+
scurrypy/models/application.py
|
|
32
|
+
scurrypy/models/emoji.py
|
|
33
|
+
scurrypy/models/guild.py
|
|
34
|
+
scurrypy/models/integration.py
|
|
35
|
+
scurrypy/models/interaction.py
|
|
36
|
+
scurrypy/models/member.py
|
|
37
|
+
scurrypy/models/role.py
|
|
38
|
+
scurrypy/models/user.py
|
|
39
|
+
scurrypy/parts/__init__.py
|
|
40
|
+
scurrypy/parts/channel.py
|
|
41
|
+
scurrypy/parts/command.py
|
|
42
|
+
scurrypy/parts/component_types.py
|
|
43
|
+
scurrypy/parts/components.py
|
|
44
|
+
scurrypy/parts/components_v2.py
|
|
45
|
+
scurrypy/parts/embed.py
|
|
46
|
+
scurrypy/parts/message.py
|
|
47
|
+
scurrypy/parts/modal.py
|
|
48
|
+
scurrypy/parts/role.py
|
|
49
|
+
scurrypy/resources/__init__.py
|
|
50
|
+
scurrypy/resources/application.py
|
|
51
|
+
scurrypy/resources/bot_emojis.py
|
|
52
|
+
scurrypy/resources/channel.py
|
|
53
|
+
scurrypy/resources/guild.py
|
|
54
|
+
scurrypy/resources/interaction.py
|
|
55
|
+
scurrypy/resources/message.py
|
|
56
|
+
scurrypy/resources/user.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
scurrypy
|
scurrypy-0.5/discord/model.py
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass, fields, is_dataclass
|
|
2
|
-
from typing import get_args, get_origin, Union
|
|
3
|
-
|
|
4
|
-
from .http import HTTPClient
|
|
5
|
-
|
|
6
|
-
@dataclass
|
|
7
|
-
class DataModel:
|
|
8
|
-
"""DataModel is a base class for Discord JSONs that provides hydration from raw dicts,
|
|
9
|
-
optional field defaults, and access to HTTP-bound methods.
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
@classmethod
|
|
13
|
-
def from_dict(cls, data: dict, http: HTTPClient = None):
|
|
14
|
-
"""Hydrates the given data into the dataclass child.
|
|
15
|
-
|
|
16
|
-
Args:
|
|
17
|
-
data (dict): JSON data
|
|
18
|
-
http (HTTPClient, optional): HTTP session for requests
|
|
19
|
-
|
|
20
|
-
Returns:
|
|
21
|
-
(dataclass): hydrated dataclass
|
|
22
|
-
"""
|
|
23
|
-
kwargs = {}
|
|
24
|
-
|
|
25
|
-
def unwrap_optional(typ):
|
|
26
|
-
"""Remove NoneType from Optional or leave Union as-is."""
|
|
27
|
-
if get_origin(typ) is Union:
|
|
28
|
-
args = tuple(a for a in get_args(typ) if a is not type(None))
|
|
29
|
-
if len(args) == 1:
|
|
30
|
-
return args[0] # single type left
|
|
31
|
-
else:
|
|
32
|
-
return Union[args] # multi-type union remains
|
|
33
|
-
return typ
|
|
34
|
-
|
|
35
|
-
for field in fields(cls):
|
|
36
|
-
# property must be in given json!
|
|
37
|
-
value = data.get(field.name)
|
|
38
|
-
|
|
39
|
-
inner_type = unwrap_optional(field.type)
|
|
40
|
-
|
|
41
|
-
# Handle None
|
|
42
|
-
if value is None:
|
|
43
|
-
kwargs[field.name] = None
|
|
44
|
-
# Integers stored as strings
|
|
45
|
-
elif isinstance(value, str) and value.isdigit():
|
|
46
|
-
kwargs[field.name] = int(value)
|
|
47
|
-
# Nested dataclass
|
|
48
|
-
elif is_dataclass(inner_type):
|
|
49
|
-
kwargs[field.name] = inner_type.from_dict(value, http)
|
|
50
|
-
# List type
|
|
51
|
-
elif get_origin(inner_type) is list:
|
|
52
|
-
list_type = get_args(inner_type)[0]
|
|
53
|
-
kwargs[field.name] = [
|
|
54
|
-
list_type.from_dict(v, http) if is_dataclass(list_type) else v
|
|
55
|
-
for v in value
|
|
56
|
-
]
|
|
57
|
-
# Everything else (primitive, Union of primitives)
|
|
58
|
-
else:
|
|
59
|
-
kwargs[field.name] = value
|
|
60
|
-
|
|
61
|
-
instance = cls(**kwargs)
|
|
62
|
-
|
|
63
|
-
# attach HTTP if given
|
|
64
|
-
if http:
|
|
65
|
-
instance._http = http
|
|
66
|
-
|
|
67
|
-
return instance
|
|
68
|
-
|
|
69
|
-
def _to_dict(self):
|
|
70
|
-
"""Recursively turns the dataclass into a dictionary and drops empty fields.
|
|
71
|
-
|
|
72
|
-
Returns:
|
|
73
|
-
(dict): serialized dataclasss
|
|
74
|
-
"""
|
|
75
|
-
def serialize(value):
|
|
76
|
-
if isinstance(value, list):
|
|
77
|
-
return [serialize(v) for v in value]
|
|
78
|
-
if isinstance(value, DataModel):
|
|
79
|
-
return value._to_dict()
|
|
80
|
-
return value
|
|
81
|
-
|
|
82
|
-
result = {}
|
|
83
|
-
for f in fields(self):
|
|
84
|
-
if f.name.startswith('_'): # ignore private fields
|
|
85
|
-
continue
|
|
86
|
-
value = getattr(self, f.name)
|
|
87
|
-
if value not in (None, [], {}, "", 0):
|
|
88
|
-
result[f.name] = serialize(value)
|
|
89
|
-
|
|
90
|
-
return result
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
LICENSE
|
|
2
|
-
README.md
|
|
3
|
-
pyproject.toml
|
|
4
|
-
discord/__init__.py
|
|
5
|
-
discord/client.py
|
|
6
|
-
discord/client_like.py
|
|
7
|
-
discord/config.py
|
|
8
|
-
discord/error.py
|
|
9
|
-
discord/gateway.py
|
|
10
|
-
discord/http.py
|
|
11
|
-
discord/intents.py
|
|
12
|
-
discord/logger.py
|
|
13
|
-
discord/model.py
|
|
14
|
-
discord/dispatch/__init__.py
|
|
15
|
-
discord/dispatch/command_dispatcher.py
|
|
16
|
-
discord/dispatch/event_dispatcher.py
|
|
17
|
-
discord/dispatch/prefix_dispatcher.py
|
|
18
|
-
discord/events/__init__.py
|
|
19
|
-
discord/events/channel_events.py
|
|
20
|
-
discord/events/guild_events.py
|
|
21
|
-
discord/events/hello_event.py
|
|
22
|
-
discord/events/interaction_events.py
|
|
23
|
-
discord/events/message_events.py
|
|
24
|
-
discord/events/reaction_events.py
|
|
25
|
-
discord/events/ready_event.py
|
|
26
|
-
discord/models/__init__.py
|
|
27
|
-
discord/models/application.py
|
|
28
|
-
discord/models/emoji.py
|
|
29
|
-
discord/models/guild.py
|
|
30
|
-
discord/models/integration.py
|
|
31
|
-
discord/models/interaction.py
|
|
32
|
-
discord/models/member.py
|
|
33
|
-
discord/models/role.py
|
|
34
|
-
discord/models/user.py
|
|
35
|
-
discord/parts/__init__.py
|
|
36
|
-
discord/parts/channel.py
|
|
37
|
-
discord/parts/command.py
|
|
38
|
-
discord/parts/component_types.py
|
|
39
|
-
discord/parts/components.py
|
|
40
|
-
discord/parts/components_v2.py
|
|
41
|
-
discord/parts/embed.py
|
|
42
|
-
discord/parts/message.py
|
|
43
|
-
discord/parts/modal.py
|
|
44
|
-
discord/parts/role.py
|
|
45
|
-
discord/resources/__init__.py
|
|
46
|
-
discord/resources/application.py
|
|
47
|
-
discord/resources/bot_emojis.py
|
|
48
|
-
discord/resources/channel.py
|
|
49
|
-
discord/resources/guild.py
|
|
50
|
-
discord/resources/interaction.py
|
|
51
|
-
discord/resources/message.py
|
|
52
|
-
discord/resources/user.py
|
|
53
|
-
scurrypy.egg-info/PKG-INFO
|
|
54
|
-
scurrypy.egg-info/SOURCES.txt
|
|
55
|
-
scurrypy.egg-info/dependency_links.txt
|
|
56
|
-
scurrypy.egg-info/top_level.txt
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
discord
|
|
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
|
|
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
|