scurrypy 0.5__tar.gz → 0.5.3__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.

Files changed (61) hide show
  1. {scurrypy-0.5 → scurrypy-0.5.3}/PKG-INFO +14 -13
  2. {scurrypy-0.5 → scurrypy-0.5.3}/README.md +13 -12
  3. {scurrypy-0.5 → scurrypy-0.5.3}/pyproject.toml +7 -7
  4. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/__init__.py +92 -92
  5. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/client_like.py +1 -1
  6. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/dispatch/command_dispatcher.py +3 -3
  7. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/dispatch/event_dispatcher.py +15 -15
  8. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/events/interaction_events.py +2 -2
  9. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/events/message_events.py +4 -4
  10. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/intents.py +1 -1
  11. scurrypy-0.5.3/scurrypy/model.py +71 -0
  12. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/models/emoji.py +16 -0
  13. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/parts/channel.py +1 -1
  14. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/parts/command.py +4 -4
  15. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/parts/components.py +12 -12
  16. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/parts/components_v2.py +10 -10
  17. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/parts/message.py +4 -4
  18. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/resources/channel.py +2 -2
  19. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/resources/guild.py +3 -3
  20. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/resources/interaction.py +4 -4
  21. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/resources/message.py +3 -3
  22. {scurrypy-0.5 → scurrypy-0.5.3}/scurrypy.egg-info/PKG-INFO +14 -13
  23. scurrypy-0.5.3/scurrypy.egg-info/SOURCES.txt +56 -0
  24. scurrypy-0.5.3/scurrypy.egg-info/top_level.txt +1 -0
  25. scurrypy-0.5/discord/model.py +0 -90
  26. scurrypy-0.5/scurrypy.egg-info/SOURCES.txt +0 -56
  27. scurrypy-0.5/scurrypy.egg-info/top_level.txt +0 -1
  28. {scurrypy-0.5 → scurrypy-0.5.3}/LICENSE +0 -0
  29. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/client.py +0 -0
  30. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/config.py +0 -0
  31. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/dispatch/__init__.py +0 -0
  32. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/dispatch/prefix_dispatcher.py +0 -0
  33. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/error.py +0 -0
  34. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/events/__init__.py +0 -0
  35. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/events/channel_events.py +0 -0
  36. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/events/guild_events.py +0 -0
  37. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/events/hello_event.py +0 -0
  38. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/events/reaction_events.py +0 -0
  39. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/events/ready_event.py +0 -0
  40. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/gateway.py +0 -0
  41. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/http.py +0 -0
  42. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/logger.py +0 -0
  43. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/models/__init__.py +0 -0
  44. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/models/application.py +0 -0
  45. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/models/guild.py +0 -0
  46. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/models/integration.py +0 -0
  47. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/models/interaction.py +0 -0
  48. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/models/member.py +0 -0
  49. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/models/role.py +0 -0
  50. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/models/user.py +0 -0
  51. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/parts/__init__.py +0 -0
  52. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/parts/component_types.py +0 -0
  53. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/parts/embed.py +0 -0
  54. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/parts/modal.py +0 -0
  55. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/parts/role.py +0 -0
  56. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/resources/__init__.py +0 -0
  57. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/resources/application.py +0 -0
  58. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/resources/bot_emojis.py +0 -0
  59. {scurrypy-0.5/discord → scurrypy-0.5.3/scurrypy}/resources/user.py +0 -0
  60. {scurrypy-0.5 → scurrypy-0.5.3}/scurrypy.egg-info/dependency_links.txt +0 -0
  61. {scurrypy-0.5 → scurrypy-0.5.3}/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.3
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
- * Declarative style using decorators
26
- * Supports both legacy and new features
27
- * Respects Discord’s rate limits
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.
@@ -45,24 +46,24 @@ The following demonstrates building and responding to a slash command.
45
46
  *Note: Adjust `dotenv_path` if your `.env` file is not in the same directory as this script.*
46
47
 
47
48
  ```py
48
- import discord, os
49
+ import scurrypy, os
49
50
  from dotenv import load_dotenv
50
51
 
51
52
  load_dotenv(dotenv_path='./path/to/env')
52
53
 
53
- client = discord.Client(
54
+ client = scurrypy.Client(
54
55
  token=os.getenv("DISCORD_TOKEN"),
55
56
  application_id=APPLICATION_ID # your bot’s application ID
56
57
  )
57
58
 
58
59
  @client.command(
59
- command=discord.SlashCommand(
60
+ command=scurrypy.SlashCommand(
60
61
  name='example',
61
62
  description='Demonstrate the minimal slash command!'
62
63
  ),
63
64
  guild_ids=GUILD_ID # must be a guild ID your bot is in
64
65
  )
65
- async def example(bot: discord.Client, event: discord.InteractionEvent):
66
+ async def example(bot: scurrypy.Client, event: scurrypy.InteractionEvent):
66
67
  await event.interaction.respond(f'Hello, {event.interaction.member.user.username}!')
67
68
 
68
69
  client.run()
@@ -71,20 +72,20 @@ client.run()
71
72
  ## Minimal Prefix Command (Legacy)
72
73
  The following demonstrates building and responding to a message prefix command.
73
74
  ```py
74
- import discord, os
75
+ import scurrypy, os
75
76
  from dotenv import load_dotenv
76
77
 
77
78
  load_dotenv(dotenv_path='./path/to/env')
78
79
 
79
- client = discord.Client(
80
+ client = scurrypy.Client(
80
81
  token=os.getenv("DISCORD_TOKEN"),
81
82
  application_id=APPLICATION_ID # your bot’s application ID
82
- intents=discord.set_intents(message_content=True),
83
+ intents=scurrypy.set_intents(message_content=True),
83
84
  prefix='!' # your custom prefix
84
85
  )
85
86
 
86
87
  @client.prefix_command
87
- async def ping(bot: discord.Client, event: discord.MessageCreateEvent):
88
+ async def ping(bot: scurrypy.Client, event: scurrypy.MessageCreateEvent):
88
89
  # The function name is the name of the command
89
90
  await event.message.send("Pong!")
90
91
 
@@ -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
- * Declarative style using decorators
16
- * Supports both legacy and new features
17
- * Respects Discord’s rate limits
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.
@@ -35,24 +36,24 @@ The following demonstrates building and responding to a slash command.
35
36
  *Note: Adjust `dotenv_path` if your `.env` file is not in the same directory as this script.*
36
37
 
37
38
  ```py
38
- import discord, os
39
+ import scurrypy, os
39
40
  from dotenv import load_dotenv
40
41
 
41
42
  load_dotenv(dotenv_path='./path/to/env')
42
43
 
43
- client = discord.Client(
44
+ client = scurrypy.Client(
44
45
  token=os.getenv("DISCORD_TOKEN"),
45
46
  application_id=APPLICATION_ID # your bot’s application ID
46
47
  )
47
48
 
48
49
  @client.command(
49
- command=discord.SlashCommand(
50
+ command=scurrypy.SlashCommand(
50
51
  name='example',
51
52
  description='Demonstrate the minimal slash command!'
52
53
  ),
53
54
  guild_ids=GUILD_ID # must be a guild ID your bot is in
54
55
  )
55
- async def example(bot: discord.Client, event: discord.InteractionEvent):
56
+ async def example(bot: scurrypy.Client, event: scurrypy.InteractionEvent):
56
57
  await event.interaction.respond(f'Hello, {event.interaction.member.user.username}!')
57
58
 
58
59
  client.run()
@@ -61,20 +62,20 @@ client.run()
61
62
  ## Minimal Prefix Command (Legacy)
62
63
  The following demonstrates building and responding to a message prefix command.
63
64
  ```py
64
- import discord, os
65
+ import scurrypy, os
65
66
  from dotenv import load_dotenv
66
67
 
67
68
  load_dotenv(dotenv_path='./path/to/env')
68
69
 
69
- client = discord.Client(
70
+ client = scurrypy.Client(
70
71
  token=os.getenv("DISCORD_TOKEN"),
71
72
  application_id=APPLICATION_ID # your bot’s application ID
72
- intents=discord.set_intents(message_content=True),
73
+ intents=scurrypy.set_intents(message_content=True),
73
74
  prefix='!' # your custom prefix
74
75
  )
75
76
 
76
77
  @client.prefix_command
77
- async def ping(bot: discord.Client, event: discord.MessageCreateEvent):
78
+ async def ping(bot: scurrypy.Client, event: scurrypy.MessageCreateEvent):
78
79
  # The function name is the name of the command
79
80
  await event.message.send("Pong!")
80
81
 
@@ -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.3"
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
- "discord",
18
- "discord.dispatch",
19
- "discord.events",
20
- "discord.models",
21
- "discord.resources",
22
- "discord.parts"
17
+ "scurrypy",
18
+ "scurrypy.dispatch",
19
+ "scurrypy.events",
20
+ "scurrypy.models",
21
+ "scurrypy.resources",
22
+ "scurrypy.parts"
23
23
  ]
@@ -1,4 +1,4 @@
1
- # discord
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": "discord.logger",
265
- "Client": "discord.client",
266
- "Intents": "discord.intents",
267
- "set_intents": "discord.intents",
268
- "BaseConfig": "discord.config",
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': "discord.dispatch.command_dispatcher",
270
+ 'InteractionTypes': "scurrypy.dispatch.command_dispatcher",
271
271
 
272
- "ReadyEvent": "discord.events.ready_event",
272
+ "ReadyEvent": "scurrypy.events.ready_event",
273
273
 
274
- "ReactionAddEvent": "discord.events.reaction_events",
275
- "ReactionRemoveEvent": "discord.events.reaction_events",
276
- "ReactionRemoveEmojiEvent": "discord.events.reaction_events",
277
- "ReactionRemoveAllEvent": "discord.events.reaction_events",
278
-
279
- "GuildCreateEvent": "discord.events.guild_events",
280
- "GuildUpdateEvent": "discord.events.guild_events",
281
- "GuildDeleteEvent": "discord.events.guild_events",
282
-
283
- "MessageCreateEvent": "discord.events.message_events",
284
- "MessageUpdateEvent": "discord.events.message_events",
285
- "MessageDeleteEvent": "discord.events.message_events",
286
-
287
- "GuildChannelCreateEvent": "discord.events.channel_events",
288
- "GuildChannelUpdateEvent": "discord.events.channel_events",
289
- "GuildChannelDeleteEvent": "discord.events.channel_events",
290
- "ChannelPinsUpdateEvent": "discord.events.channel_events",
291
-
292
- "InteractionEvent": "discord.events.interaction_events",
293
-
294
- 'ApplicationModel': "discord.models.application",
295
- 'EmojiModel': "discord.models.emoji",
296
- 'GuildModel': "discord.models.guild",
297
- 'MemberModel': "discord.models.member",
298
- 'UserModel': "discord.models.user",
299
- 'RoleModel': "discord.models.role",
300
-
301
- 'ChannelTypes': "discord.parts.channel",
302
- 'GuildChannel': "discord.parts.channel",
303
-
304
- 'CommandTypes': "discord.parts.command",
305
- 'CommandOptionTypes': "discord.parts.command",
306
- 'SlashCommand': "discord.parts.command",
307
- 'UserCommand': "discord.parts.command",
308
- 'MessageCommand': "discord.parts.command",
309
-
310
- 'ComponentV2Types': "discord.parts.components_v2",
311
- 'SectionPart': "discord.parts.components_v2",
312
- 'TextDisplay': "discord.parts.components_v2",
313
- 'Thumbnail': "discord.parts.components_v2",
314
- 'MediaGalleryItem': "discord.parts.components_v2",
315
- 'MediaGallery': "discord.parts.components_v2",
316
- 'File': "discord.parts.components_v2",
317
- 'SeparatorTypes': "discord.parts.components_v2",
318
- 'Separator': "discord.parts.components_v2",
319
- 'ContainerPart': "discord.parts.components_v2",
320
- 'Label': "discord.parts.components_v2",
321
-
322
- 'ComponentTypes': "discord.parts.components",
323
- 'ActionRowPart': "discord.parts.components",
324
- 'ButtonStyles': "discord.parts.components",
325
- 'Button': "discord.parts.components",
326
- 'SelectOption': "discord.parts.components",
327
- 'StringSelect': "discord.parts.components",
328
- 'TextInputStyles': 'discord.parts.components',
329
- 'TextInput': "discord.parts.components",
330
- 'DefaultValue': "discord.parts.components",
331
- 'UserSelect': "discord.parts.components",
332
- 'RoleSelect': "discord.parts.components",
333
- 'MentionableSelect': "discord.parts.components",
334
- 'ChannelSelect': "discord.parts.components",
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': "discord.parts.embed",
337
- 'EmbedThumbnail': "discord.parts.embed",
338
- 'EmbedField': "discord.parts.embed",
339
- 'EmbedImage': "discord.parts.embed",
340
- 'EmbedFooter': "discord.parts.embed",
341
- 'EmbedPart': "discord.parts.embed",
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': "discord.parts.message",
344
- 'MessageReferenceTypes': "discord.parts.message",
345
- 'MessageReference': "discord.parts.message",
346
- 'Attachment': "discord.parts.message",
347
- 'MessagePart': "discord.parts.message",
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': "discord.parts.modal",
350
- 'Role': "discord.parts.role",
349
+ 'ModalPart': "scurrypy.parts.modal",
350
+ 'Role': "scurrypy.parts.role",
351
351
 
352
- 'ApplicationFlags': "discord.resources.application",
353
- 'Application': "discord.resources.application",
352
+ 'ApplicationFlags': "scurrypy.resources.application",
353
+ 'Application': "scurrypy.resources.application",
354
354
 
355
- 'BotEmojis': "discord.resources.bot_emojis",
355
+ 'BotEmojis': "scurrypy.resources.bot_emojis",
356
356
 
357
- 'PinnedMessage': "discord.resources.channel",
358
- 'Channel': "discord.resources.channel",
357
+ 'PinnedMessage': "scurrypy.resources.channel",
358
+ 'Channel': "scurrypy.resources.channel",
359
359
 
360
- 'Guild': "discord.resources.guild",
360
+ 'Guild': "scurrypy.resources.guild",
361
361
 
362
- 'InteractionCallbackTypes': "discord.resources.interaction",
363
- 'Interaction': "discord.resources.interaction",
362
+ 'InteractionCallbackTypes': "scurrypy.resources.interaction",
363
+ 'Interaction': "scurrypy.resources.interaction",
364
364
 
365
- 'Message': "discord.resources.message",
365
+ 'Message': "scurrypy.resources.message",
366
366
 
367
- 'User': "discord.resources.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`][discord.client.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`][discord.dispatch.command_dispatcher.InteractionTypes] to their respective dataclass."""
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._to_dict() for command in cmds]
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._to_dict() for command in commands]
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': ('discord.events.ready_event', 'ReadyEvent'),
10
+ 'READY': ('scurrypy.events.ready_event', 'ReadyEvent'),
11
11
 
12
- 'GUILD_CREATE': ('discord.events.guild_events', 'GuildCreateEvent'),
13
- 'GUILD_UPDATE': ('discord.events.guild_events', 'GuildUpdateEvent'),
14
- 'GUILD_DELETE': ('discord.events.guild_events', 'GuildDeleteEvent'),
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': ('discord.events.channel_events', 'GuildChannelCreateEvent'),
17
- 'CHANNEL_UPDATE': ('discord.events.channel_events', 'GuildChannelUpdateEvent'),
18
- 'CHANNEL_DELETE': ('discord.events.channel_events', 'GuildChannelDeleteEvent'),
19
- 'CHANNEL_PINS_UPDATE': ('discord.events.channel_events', 'ChannelPinsUpdateEvent'),
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': ('discord.events.message_events', 'MessageCreateEvent'),
22
- 'MESSAGE_UPDATE': ('discord.events.message_events', 'MessageUpdateEvent'),
23
- 'MESSAGE_DELETE': ('discord.events.message_events', 'MessageDeleteEvent'),
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': ('discord.events.reaction_events', 'ReactionAddEvent'),
26
- 'MESSAGE_REACTION_REMOVE': ('discord.events.reaction_events', 'ReactionRemoveEvent'),
27
- 'MESSAGE_REACTION_REMOVE_ALL': ('discord.events.reaction_events', 'ReactionRemoveAllEvent'),
28
- 'MESSAGE_REACTION_REMOVE_EMOJI': ('discord.events.reaction_events', 'ReactionRemoveEmojiEvent'),
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`][discord.parts.command.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`][discord.resources.interaction.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`][discord.resources.message.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`][discord.models.member.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`][discord.resources.message.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`][discord.models.member.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`][discord.intents.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
@@ -32,3 +32,19 @@ class EmojiModel(DataModel):
32
32
  return quote(f"a:{self.name}:{self.id}")
33
33
 
34
34
  return quote(f"{self.name}:{self.id}")
35
+
36
+ @property
37
+ def url(self) -> str:
38
+ """
39
+ Return the full qualifying link for this emoji.
40
+
41
+ !!! important
42
+ This only works for custom Discord emojis (those with an ID).
43
+ Unicode emojis will return `None`.
44
+ """
45
+ if not self.id:
46
+ return None
47
+
48
+ ext = 'gif' if self.animated else 'png'
49
+
50
+ return f"https://cdn.discordapp.com/emojis/{self.id}.{ext}"
@@ -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`][discord.parts.channel.ChannelTypes]."""
30
+ """Type of channel. See [`ChannelTypes`][scurrypy.parts.channel.ChannelTypes]."""
31
31
 
32
32
  topic: Optional[str] = None
33
33
  """Topic of channel."""