scurrypy 0.1.0__tar.gz → 0.2.1__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.2.1/PKG-INFO +85 -0
  2. scurrypy-0.2.1/README.md +75 -0
  3. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/__init__.py +1 -0
  4. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/client.py +36 -6
  5. scurrypy-0.2.1/discord/config.py +6 -0
  6. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/dispatch/command_dispatcher.py +5 -2
  7. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/dispatch/event_dispatcher.py +6 -1
  8. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/dispatch/prefix_dispatcher.py +6 -1
  9. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/events/channel_events.py +4 -3
  10. scurrypy-0.2.1/discord/events/event_model.py +10 -0
  11. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/events/guild_events.py +2 -6
  12. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/events/interaction_events.py +4 -0
  13. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/events/message_events.py +4 -4
  14. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/events/reaction_events.py +5 -5
  15. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/events/ready_event.py +5 -0
  16. {scurrypy-0.1.0 → scurrypy-0.2.1}/pyproject.toml +2 -1
  17. scurrypy-0.2.1/scurrypy.egg-info/PKG-INFO +85 -0
  18. {scurrypy-0.1.0 → scurrypy-0.2.1}/scurrypy.egg-info/SOURCES.txt +2 -0
  19. scurrypy-0.1.0/PKG-INFO +0 -8
  20. scurrypy-0.1.0/README.md +0 -12
  21. scurrypy-0.1.0/scurrypy.egg-info/PKG-INFO +0 -8
  22. {scurrypy-0.1.0 → scurrypy-0.2.1}/LICENSE +0 -0
  23. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/dispatch/__init__.py +0 -0
  24. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/error.py +0 -0
  25. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/events/__init__.py +0 -0
  26. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/events/hello_event.py +0 -0
  27. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/gateway.py +0 -0
  28. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/http.py +0 -0
  29. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/intents.py +0 -0
  30. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/logger.py +0 -0
  31. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/model.py +0 -0
  32. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/models/__init__.py +0 -0
  33. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/models/application.py +0 -0
  34. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/models/emoji.py +0 -0
  35. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/models/guild.py +0 -0
  36. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/models/integration.py +0 -0
  37. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/models/member.py +0 -0
  38. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/models/role.py +0 -0
  39. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/models/user.py +0 -0
  40. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/parts/__init__.py +0 -0
  41. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/parts/action_row.py +0 -0
  42. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/parts/attachment.py +0 -0
  43. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/parts/channel.py +0 -0
  44. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/parts/command.py +0 -0
  45. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/parts/component_types.py +0 -0
  46. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/parts/components_v2.py +0 -0
  47. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/parts/embed.py +0 -0
  48. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/parts/message.py +0 -0
  49. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/parts/modal.py +0 -0
  50. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/parts/role.py +0 -0
  51. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/resources/__init__.py +0 -0
  52. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/resources/application.py +0 -0
  53. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/resources/bot_emojis.py +0 -0
  54. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/resources/channel.py +0 -0
  55. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/resources/guild.py +0 -0
  56. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/resources/interaction.py +0 -0
  57. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/resources/message.py +0 -0
  58. {scurrypy-0.1.0 → scurrypy-0.2.1}/discord/resources/user.py +0 -0
  59. {scurrypy-0.1.0 → scurrypy-0.2.1}/scurrypy.egg-info/dependency_links.txt +0 -0
  60. {scurrypy-0.1.0 → scurrypy-0.2.1}/scurrypy.egg-info/top_level.txt +0 -0
  61. {scurrypy-0.1.0 → scurrypy-0.2.1}/setup.cfg +0 -0
@@ -0,0 +1,85 @@
1
+ Metadata-Version: 2.4
2
+ Name: scurrypy
3
+ Version: 0.2.1
4
+ Summary: Discord API Wrapper in Python
5
+ Author: Furmissile
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Dynamic: license-file
10
+
11
+ # __Welcome to ScurryPy__
12
+
13
+ [![PyPI version](https://badge.fury.io/py/scurrypy.svg)](https://badge.fury.io/py/scurrypy)
14
+
15
+ Yet another Discord API wrapper in Python!
16
+
17
+ While this wrapper is mainly used for various squirrel-related shenanigans, it can also be used for more generic bot purposes.
18
+
19
+ ## Features
20
+ * Command and event handling
21
+ * Declarative style using decorators
22
+ * Supports both legacy and new features
23
+ * Respects Discord's rate limits
24
+
25
+ ## Something things to consider...
26
+ * This is an early version — feedback, ideas, and contributions are welcome! With that said, there will be bumps in the road so expect bugs and other flaws!
27
+ * Some features are not yet supported, such as sharding and automod, while others, like voice, will never be supported. While this library can handle many of your basic needs, common features such as sharding or auto-mod actions are not yet implemented. See the [license](LICENSE) for details on usage.
28
+
29
+
30
+ ## Getting Started
31
+ While this tab shows up in the docs, here are some complete examples where all you need to do is pop in your bot's credentials!
32
+
33
+ ## Installation
34
+ To install the ScurryPy package, run:
35
+ ```bash
36
+ pip install scurrypy
37
+ ```
38
+
39
+ ## Minimal Slash Command
40
+ The following demonstrates building and responding to a slash command.
41
+ ```python
42
+ import discord, os
43
+ from dotenv import load_dotenv
44
+
45
+ load_dotenv(dotenv_path='./path/to/env') # omit argument if your env file is on the same level
46
+
47
+ bot = discord.Client(
48
+ token=os.getenv("DISCORD_TOKEN"),
49
+ application_id=1234567890 # replace with your bot's user ID
50
+ )
51
+
52
+ @bot.command(
53
+ command=discord.SlashCommand(name='example', description='Demonstrate the minimal slash command!'),
54
+ guild_id=GUILD_ID # must be a guild ID your bot is in!
55
+ )
56
+ async def example(event: discord.InteractionEvent):
57
+ await event.interaction.respond(f'Hello, {event.interaction.member.user.username}!')
58
+
59
+ bot.run()
60
+ ```
61
+
62
+ ## Minimal Prefix Command (Legacy)
63
+ The following demonstrates building and responding to a message prefix command.
64
+ ```python
65
+ import discord, os
66
+ from dotenv import load_dotenv
67
+
68
+ load_dotenv(dotenv_path='./path/to/env') # omit argument if your env file is on the same level
69
+
70
+ bot = discord.Client(
71
+ token=os.getenv("DISCORD_TOKEN"),
72
+ application_id=1234567890, # replace with your bot's user ID
73
+ intents=discord.set_intents(message_content=True),
74
+ prefix='!' # your custom prefix
75
+ )
76
+
77
+ @bot.prefix_command
78
+ async def ping(event: discord.MessageCreateEvent): # the function name is the name of the command!
79
+ await event.message.send(f"Pong!")
80
+
81
+ bot.run()
82
+ ```
83
+
84
+ ## Like what you see?
85
+ See the docs for more!
@@ -0,0 +1,75 @@
1
+ # __Welcome to ScurryPy__
2
+
3
+ [![PyPI version](https://badge.fury.io/py/scurrypy.svg)](https://badge.fury.io/py/scurrypy)
4
+
5
+ Yet another Discord API wrapper in Python!
6
+
7
+ While this wrapper is mainly used for various squirrel-related shenanigans, it can also be used for more generic bot purposes.
8
+
9
+ ## Features
10
+ * Command and event handling
11
+ * Declarative style using decorators
12
+ * Supports both legacy and new features
13
+ * Respects Discord's rate limits
14
+
15
+ ## Something things to consider...
16
+ * This is an early version — feedback, ideas, and contributions are welcome! With that said, there will be bumps in the road so expect bugs and other flaws!
17
+ * Some features are not yet supported, such as sharding and automod, while others, like voice, will never be supported. While this library can handle many of your basic needs, common features such as sharding or auto-mod actions are not yet implemented. See the [license](LICENSE) for details on usage.
18
+
19
+
20
+ ## Getting Started
21
+ While this tab shows up in the docs, here are some complete examples where all you need to do is pop in your bot's credentials!
22
+
23
+ ## Installation
24
+ To install the ScurryPy package, run:
25
+ ```bash
26
+ pip install scurrypy
27
+ ```
28
+
29
+ ## Minimal Slash Command
30
+ The following demonstrates building and responding to a slash command.
31
+ ```python
32
+ import discord, os
33
+ from dotenv import load_dotenv
34
+
35
+ load_dotenv(dotenv_path='./path/to/env') # omit argument if your env file is on the same level
36
+
37
+ bot = discord.Client(
38
+ token=os.getenv("DISCORD_TOKEN"),
39
+ application_id=1234567890 # replace with your bot's user ID
40
+ )
41
+
42
+ @bot.command(
43
+ command=discord.SlashCommand(name='example', description='Demonstrate the minimal slash command!'),
44
+ guild_id=GUILD_ID # must be a guild ID your bot is in!
45
+ )
46
+ async def example(event: discord.InteractionEvent):
47
+ await event.interaction.respond(f'Hello, {event.interaction.member.user.username}!')
48
+
49
+ bot.run()
50
+ ```
51
+
52
+ ## Minimal Prefix Command (Legacy)
53
+ The following demonstrates building and responding to a message prefix command.
54
+ ```python
55
+ import discord, os
56
+ from dotenv import load_dotenv
57
+
58
+ load_dotenv(dotenv_path='./path/to/env') # omit argument if your env file is on the same level
59
+
60
+ bot = discord.Client(
61
+ token=os.getenv("DISCORD_TOKEN"),
62
+ application_id=1234567890, # replace with your bot's user ID
63
+ intents=discord.set_intents(message_content=True),
64
+ prefix='!' # your custom prefix
65
+ )
66
+
67
+ @bot.prefix_command
68
+ async def ping(event: discord.MessageCreateEvent): # the function name is the name of the command!
69
+ await event.message.send(f"Pong!")
70
+
71
+ bot.run()
72
+ ```
73
+
74
+ ## Like what you see?
75
+ See the docs for more!
@@ -3,6 +3,7 @@
3
3
  from .logger import Logger
4
4
  from .client import Client
5
5
  from .intents import Intents, set_intents
6
+ from .config import BaseConfig
6
7
 
7
8
  from .events import *
8
9
  from .resources import *
@@ -5,6 +5,7 @@ from .gateway import GatewayClient
5
5
  from .http import HTTPClient
6
6
  from .intents import Intents
7
7
  from .error import DiscordError
8
+ from .config import BaseConfig
8
9
 
9
10
  from .resources.guild import Guild
10
11
  from .resources.channel import Channel
@@ -28,6 +29,7 @@ class Client:
28
29
  token: str,
29
30
  application_id: int,
30
31
  intents: int = Intents.DEFAULT,
32
+ config: BaseConfig = None,
31
33
  debug_mode: bool = False,
32
34
  prefix = None,
33
35
  quiet: bool = False
@@ -43,6 +45,7 @@ class Client:
43
45
  """
44
46
  self.token = token
45
47
  self.application_id = application_id
48
+ self.config = config
46
49
 
47
50
  self._logger = Logger(debug_mode, quiet)
48
51
  self._ws = GatewayClient(token, intents, self._logger)
@@ -51,15 +54,16 @@ class Client:
51
54
  if prefix and (intents & Intents.MESSAGE_CONTENT == 0):
52
55
  self._logger.log_warn('Prefix set without message content enabled.')
53
56
 
54
- self.dispatcher = EventDispatcher(self.application_id, self._http, self._logger)
55
- self.prefix_dispatcher = PrefixDispatcher(self._http, self._logger, prefix)
56
- self.command_dispatcher = CommandDispatcher(self.application_id, self._http, self._logger)
57
+ self.dispatcher = EventDispatcher(self.application_id, self._http, self._logger, config)
58
+ self.prefix_dispatcher = PrefixDispatcher(self._http, self._logger, prefix, config)
59
+ self.command_dispatcher = CommandDispatcher(self.application_id, self._http, self._logger, config)
57
60
 
58
61
  self._global_commands = [] # SlashCommand
59
62
  self._guild_commands = {} # {guild_id : [commands], ...}
60
63
 
61
64
  self._is_set_up = False
62
65
  self._setup_hooks = []
66
+ self._shutdown_hooks = []
63
67
 
64
68
  self.emojis = BotEmojis(self._http, self.application_id)
65
69
 
@@ -125,6 +129,15 @@ class Client:
125
129
  """
126
130
  self._setup_hooks.append(func)
127
131
 
132
+ def shutdown_hook(self, func):
133
+ """Decorator registers a shutdown hook.
134
+ (Runs once before the bot exits the loop)
135
+
136
+ Args:
137
+ func (callable): callback to the shutdown function
138
+ """
139
+ self._shutdown_hooks.append(func)
140
+
128
141
  def application_from_id(self, application_id: int):
129
142
  """Creates an interactable application resource.
130
143
 
@@ -265,7 +278,7 @@ class Client:
265
278
  if self._setup_hooks:
266
279
  for hook in self._setup_hooks:
267
280
  self._logger.log_info(f"Setting hook {hook.__name__}")
268
- await hook()
281
+ await hook(self)
269
282
  self._logger.log_high_priority("Hooks set up.")
270
283
 
271
284
  # register GUILD commands
@@ -293,8 +306,25 @@ class Client:
293
306
  self._logger.log_error(f"Unspecified Error Type {type(e).__name__} - {e}")
294
307
  break
295
308
  finally:
296
- await self._ws.close()
297
- await self._http.close_session()
309
+ # Run hooks (with safe catching)
310
+ for hook in self._shutdown_hooks:
311
+ try:
312
+ self._logger.log_info(f"Executing shutdown hook {hook.__name__}")
313
+ await hook(self)
314
+ except Exception as e:
315
+ self._logger.log_error(f"{type(e).__name__}: {e}")
316
+
317
+ # Always close resources
318
+ try:
319
+ await self._ws.close()
320
+ except Exception as e:
321
+ self._logger.log_warn(f"WebSocket close failed: {e}")
322
+
323
+ try:
324
+ await self._http.close_session()
325
+ except Exception as e:
326
+ self._logger.log_warn(f"HTTP session close failed: {e}")
327
+
298
328
 
299
329
  def run(self):
300
330
  """Starts the bot.
@@ -0,0 +1,6 @@
1
+ from dataclasses import dataclass
2
+
3
+ @dataclass
4
+ class BaseConfig:
5
+ """Config class that lives inside Client and can be extended by the dev to add persistent data (like a database)."""
6
+ pass
@@ -2,6 +2,7 @@ import asyncio
2
2
 
3
3
  from ..http import HTTPClient
4
4
  from ..logger import Logger
5
+ from ..config import BaseConfig
5
6
 
6
7
  from ..events.interaction_events import ApplicationCommandData, MessageComponentData, ModalData, InteractionEvent
7
8
  from ..resources.interaction import Interaction, InteractionDataTypes
@@ -28,7 +29,7 @@ class CommandDispatcher:
28
29
  }
29
30
  """Maps [`InteractionTypes`][discord.dispatch.command_dispatcher.InteractionTypes] to their respective dataclass."""
30
31
 
31
- def __init__(self, application_id: int, http: HTTPClient, logger: Logger):
32
+ def __init__(self, application_id: int, http: HTTPClient, logger: Logger, config: BaseConfig):
32
33
  self.application_id = application_id
33
34
  """Bot's application ID."""
34
35
 
@@ -38,6 +39,8 @@ class CommandDispatcher:
38
39
  self._logger = logger
39
40
  """Logger instance to log events."""
40
41
 
42
+ self.config = config
43
+
41
44
  self._component_handlers = {}
42
45
  """Mapping of component custom IDs to handler."""
43
46
 
@@ -114,7 +117,7 @@ class CommandDispatcher:
114
117
  Args:
115
118
  data (dict): interaction data
116
119
  """
117
- event = InteractionEvent(interaction=Interaction.from_dict(data, self._http))
120
+ event = InteractionEvent(config=self.config, interaction=Interaction.from_dict(data, self._http))
118
121
 
119
122
  event_data_obj = self.RESOURCE_MAP.get(event.interaction.type)
120
123
 
@@ -1,5 +1,6 @@
1
1
  from ..http import HTTPClient
2
2
  from ..logger import Logger
3
+ from ..config import BaseConfig
3
4
 
4
5
  from ..events.ready_event import *
5
6
  from ..events.reaction_events import *
@@ -40,7 +41,7 @@ class EventDispatcher:
40
41
  }
41
42
  """Mapping of event names to respective dataclass."""
42
43
 
43
- def __init__(self, application_id: int, http: HTTPClient, logger: Logger):
44
+ def __init__(self, application_id: int, http: HTTPClient, logger: Logger, config: BaseConfig):
44
45
  self.application_id = application_id
45
46
  """Bot's ID."""
46
47
 
@@ -50,6 +51,9 @@ class EventDispatcher:
50
51
  self._logger = logger
51
52
  """HTTP session for requests"""
52
53
 
54
+ self.config = config
55
+ """User-defined bot config for persistent data."""
56
+
53
57
  self._handlers = {}
54
58
  """Mapping of event names to handler."""
55
59
 
@@ -81,5 +85,6 @@ class EventDispatcher:
81
85
  handler = self._handlers.get(event_name, None)
82
86
  if handler:
83
87
  obj = cls.from_dict(data, self._http)
88
+ obj.config = self.config
84
89
  await handler(obj)
85
90
  self._logger.log_info(f"Event {event_name} Acknowledged.")
@@ -1,5 +1,6 @@
1
1
  from ..http import HTTPClient
2
2
  from ..logger import Logger
3
+ from ..config import BaseConfig
3
4
 
4
5
  from ..events.message_events import MessageCreateEvent
5
6
 
@@ -8,7 +9,7 @@ from ..models.member import MemberModel
8
9
 
9
10
  class PrefixDispatcher:
10
11
  """Handles text-based command messages that start with a specific prefix."""
11
- def __init__(self, http: HTTPClient, logger: Logger, prefix: str):
12
+ def __init__(self, http: HTTPClient, logger: Logger, prefix: str, config: BaseConfig):
12
13
  self._http = http
13
14
  """HTTP session for requests."""
14
15
 
@@ -18,6 +19,9 @@ class PrefixDispatcher:
18
19
  self.prefix = prefix
19
20
  """User-defined command prefix."""
20
21
 
22
+ self.config = config
23
+ """User-defined bot config for persistent data."""
24
+
21
25
  self._handlers = {}
22
26
  """Mapping of command prefix names to handler"""
23
27
 
@@ -37,6 +41,7 @@ class PrefixDispatcher:
37
41
  data (dict): Discord's raw event payload
38
42
  """
39
43
  event = MessageCreateEvent(
44
+ config=self.config,
40
45
  guild_id=data.get('guild_id'),
41
46
  message=Message.from_dict(data, self._http),
42
47
  member=MemberModel.from_dict(data.get('member'))
@@ -1,10 +1,11 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Optional
3
- from ..model import DataModel
3
+ from .event_model import EventModel
4
4
 
5
5
  @dataclass
6
- class GuildChannelEvent(DataModel):
6
+ class GuildChannelEvent(EventModel):
7
7
  """Base guild channel event."""
8
+
8
9
  id: int
9
10
  """ID of the guild channel."""
10
11
 
@@ -45,7 +46,7 @@ class GuildChannelDeleteEvent(GuildChannelEvent):
45
46
  pass
46
47
 
47
48
  @dataclass
48
- class ChannelPinsUpdateEvent(DataModel):
49
+ class ChannelPinsUpdateEvent(EventModel):
49
50
  """Pin update event."""
50
51
  channel_id: int
51
52
  guild_id: Optional[int]
@@ -0,0 +1,10 @@
1
+ from dataclasses import dataclass
2
+ from ..model import DataModel
3
+ from ..config import BaseConfig
4
+
5
+ @dataclass
6
+ class EventModel(DataModel):
7
+ """Event Model for event-driven fields common among all events."""
8
+
9
+ config: BaseConfig
10
+ """User-defined bot config for persistent data."""
@@ -1,11 +1,10 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
3
- from ..model import DataModel
2
+ from .event_model import EventModel
4
3
  from ..models import MemberModel
5
4
  from ..resources.channel import Channel
6
5
 
7
6
  @dataclass
8
- class GuildEvent(DataModel):
7
+ class GuildEvent(EventModel):
9
8
  """Base guild event."""
10
9
  joined_at: str
11
10
  """ISO8601 timestamp of when app joined the guild."""
@@ -22,9 +21,6 @@ class GuildEvent(DataModel):
22
21
  channels: list[Channel]
23
22
  """Channels in the guild."""
24
23
 
25
- unavailable: Optional[bool]
26
- """If the guild is unavailable due to an outage."""
27
-
28
24
  class GuildCreateEvent(GuildEvent):
29
25
  """Received when the bot has joined a guild."""
30
26
  pass
@@ -1,6 +1,7 @@
1
1
  from dataclasses import dataclass, field
2
2
  from typing import Optional
3
3
  from ..model import DataModel
4
+ from ..config import BaseConfig
4
5
 
5
6
  from ..resources.interaction import Interaction
6
7
 
@@ -141,5 +142,8 @@ class InteractionEvent(DataModel):
141
142
  interaction: Interaction
142
143
  """Interaction resource object. See [`Interaction`][discord.resources.interaction.Interaction]."""
143
144
 
145
+ config: BaseConfig
146
+ """User-defined bot config for persistent data."""
147
+
144
148
  data: Optional[ApplicationCommandData | MessageComponentData | ModalData] = None
145
149
  """Interaction response data."""
@@ -1,12 +1,12 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Optional
3
- from ..model import DataModel
3
+ from .event_model import EventModel
4
4
 
5
5
  from ..resources.message import Message
6
6
  from ..models.member import MemberModel
7
7
 
8
8
  @dataclass
9
- class MessageCreateEvent(DataModel):
9
+ class MessageCreateEvent(EventModel):
10
10
  """Received when a message is created."""
11
11
  message: Message
12
12
  """Message resource object. See [`Resource.Message`][discord.resources.message.Message]."""
@@ -18,7 +18,7 @@ class MessageCreateEvent(DataModel):
18
18
  """Partial Member object of the author of the message. See [`MemberModel`][discord.models.member.MemberModel]."""
19
19
 
20
20
  @dataclass
21
- class MessageUpdateEvent(DataModel):
21
+ class MessageUpdateEvent(EventModel):
22
22
  """Received when a message is updated."""
23
23
  message: Message
24
24
  """Message resource object. See [`Resource.Message`][discord.resources.message.Message]."""
@@ -30,7 +30,7 @@ class MessageUpdateEvent(DataModel):
30
30
  """Partial Member object of the author of the message. See [`MemberModel`][discord.models.member.MemberModel]."""
31
31
 
32
32
  @dataclass
33
- class MessageDeleteEvent(DataModel):
33
+ class MessageDeleteEvent(EventModel):
34
34
  """Received when a message is deleted."""
35
35
 
36
36
  id: int
@@ -1,6 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Optional
3
- from ..model import DataModel
3
+ from .event_model import EventModel
4
4
 
5
5
  from ..models.member import MemberModel
6
6
  from ..models.emoji import EmojiModel
@@ -15,7 +15,7 @@ class ReactionType:
15
15
  """A super emoji."""
16
16
 
17
17
  @dataclass
18
- class ReactionAddEvent(DataModel):
18
+ class ReactionAddEvent(EventModel):
19
19
  """Reaction added event."""
20
20
 
21
21
  type: int
@@ -46,7 +46,7 @@ class ReactionAddEvent(DataModel):
46
46
  """ID of the user who sent the message where the reaction was added."""
47
47
 
48
48
  @dataclass
49
- class ReactionRemoveEvent(DataModel):
49
+ class ReactionRemoveEvent(EventModel):
50
50
  """Reaction removed event."""
51
51
 
52
52
  type: int
@@ -70,7 +70,7 @@ class ReactionRemoveEvent(DataModel):
70
70
  burst: bool
71
71
  """If the emoji of the removed reaction is super."""
72
72
 
73
- class ReactionRemoveAllEvent(DataModel):
73
+ class ReactionRemoveAllEvent(EventModel):
74
74
  """Remove all reactions event."""
75
75
 
76
76
  channel_id: int
@@ -83,7 +83,7 @@ class ReactionRemoveAllEvent(DataModel):
83
83
  """ID of the guild where all reaction were removed (if in a guild)."""
84
84
 
85
85
  @dataclass
86
- class ReactionRemoveEmojiEvent(DataModel):
86
+ class ReactionRemoveEmojiEvent(EventModel):
87
87
  """All reactions of a specific emoji removed."""
88
88
 
89
89
  emoji: EmojiModel
@@ -1,5 +1,7 @@
1
1
  from dataclasses import dataclass
2
2
  from ..model import DataModel
3
+ from ..config import BaseConfig
4
+
3
5
  from ..models.user import UserModel
4
6
  from ..models.guild import ReadyGuildModel
5
7
  from ..models.application import ApplicationModel
@@ -28,3 +30,6 @@ class ReadyEvent(DataModel):
28
30
 
29
31
  application: ApplicationModel
30
32
  """Partial application object. Contains ID and flags."""
33
+
34
+ config: BaseConfig
35
+ """User-defined bot config for persistent data."""
@@ -4,9 +4,10 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "scurrypy"
7
- version = "0.1.0"
7
+ version = "0.2.1"
8
8
 
9
9
  description = "Discord API Wrapper in Python"
10
+ readme = "README.md"
10
11
  authors = [{ name = "Furmissile" }]
11
12
  requires-python = ">=3.10"
12
13
  dependencies = []
@@ -0,0 +1,85 @@
1
+ Metadata-Version: 2.4
2
+ Name: scurrypy
3
+ Version: 0.2.1
4
+ Summary: Discord API Wrapper in Python
5
+ Author: Furmissile
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Dynamic: license-file
10
+
11
+ # __Welcome to ScurryPy__
12
+
13
+ [![PyPI version](https://badge.fury.io/py/scurrypy.svg)](https://badge.fury.io/py/scurrypy)
14
+
15
+ Yet another Discord API wrapper in Python!
16
+
17
+ While this wrapper is mainly used for various squirrel-related shenanigans, it can also be used for more generic bot purposes.
18
+
19
+ ## Features
20
+ * Command and event handling
21
+ * Declarative style using decorators
22
+ * Supports both legacy and new features
23
+ * Respects Discord's rate limits
24
+
25
+ ## Something things to consider...
26
+ * This is an early version — feedback, ideas, and contributions are welcome! With that said, there will be bumps in the road so expect bugs and other flaws!
27
+ * Some features are not yet supported, such as sharding and automod, while others, like voice, will never be supported. While this library can handle many of your basic needs, common features such as sharding or auto-mod actions are not yet implemented. See the [license](LICENSE) for details on usage.
28
+
29
+
30
+ ## Getting Started
31
+ While this tab shows up in the docs, here are some complete examples where all you need to do is pop in your bot's credentials!
32
+
33
+ ## Installation
34
+ To install the ScurryPy package, run:
35
+ ```bash
36
+ pip install scurrypy
37
+ ```
38
+
39
+ ## Minimal Slash Command
40
+ The following demonstrates building and responding to a slash command.
41
+ ```python
42
+ import discord, os
43
+ from dotenv import load_dotenv
44
+
45
+ load_dotenv(dotenv_path='./path/to/env') # omit argument if your env file is on the same level
46
+
47
+ bot = discord.Client(
48
+ token=os.getenv("DISCORD_TOKEN"),
49
+ application_id=1234567890 # replace with your bot's user ID
50
+ )
51
+
52
+ @bot.command(
53
+ command=discord.SlashCommand(name='example', description='Demonstrate the minimal slash command!'),
54
+ guild_id=GUILD_ID # must be a guild ID your bot is in!
55
+ )
56
+ async def example(event: discord.InteractionEvent):
57
+ await event.interaction.respond(f'Hello, {event.interaction.member.user.username}!')
58
+
59
+ bot.run()
60
+ ```
61
+
62
+ ## Minimal Prefix Command (Legacy)
63
+ The following demonstrates building and responding to a message prefix command.
64
+ ```python
65
+ import discord, os
66
+ from dotenv import load_dotenv
67
+
68
+ load_dotenv(dotenv_path='./path/to/env') # omit argument if your env file is on the same level
69
+
70
+ bot = discord.Client(
71
+ token=os.getenv("DISCORD_TOKEN"),
72
+ application_id=1234567890, # replace with your bot's user ID
73
+ intents=discord.set_intents(message_content=True),
74
+ prefix='!' # your custom prefix
75
+ )
76
+
77
+ @bot.prefix_command
78
+ async def ping(event: discord.MessageCreateEvent): # the function name is the name of the command!
79
+ await event.message.send(f"Pong!")
80
+
81
+ bot.run()
82
+ ```
83
+
84
+ ## Like what you see?
85
+ See the docs for more!
@@ -3,6 +3,7 @@ README.md
3
3
  pyproject.toml
4
4
  discord/__init__.py
5
5
  discord/client.py
6
+ discord/config.py
6
7
  discord/error.py
7
8
  discord/gateway.py
8
9
  discord/http.py
@@ -15,6 +16,7 @@ discord/dispatch/event_dispatcher.py
15
16
  discord/dispatch/prefix_dispatcher.py
16
17
  discord/events/__init__.py
17
18
  discord/events/channel_events.py
19
+ discord/events/event_model.py
18
20
  discord/events/guild_events.py
19
21
  discord/events/hello_event.py
20
22
  discord/events/interaction_events.py
scurrypy-0.1.0/PKG-INFO DELETED
@@ -1,8 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: scurrypy
3
- Version: 0.1.0
4
- Summary: Discord API Wrapper in Python
5
- Author: Furmissile
6
- Requires-Python: >=3.10
7
- License-File: LICENSE
8
- Dynamic: license-file
scurrypy-0.1.0/README.md DELETED
@@ -1,12 +0,0 @@
1
- # __Welcome to ScurryPy__
2
- Yet another Discord API wrapper in Python!
3
-
4
- While this wrapper is mainly used for various squirrel-related shenanigans, it can also be used for more generic bot purposes.
5
-
6
- ## Features
7
- * Command and event handling
8
- * Declarative style using decorators
9
- * Supports both legacy and new features
10
- * Respects Discord's rate limits
11
-
12
- See the docs for more!
@@ -1,8 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: scurrypy
3
- Version: 0.1.0
4
- Summary: Discord API Wrapper in Python
5
- Author: Furmissile
6
- Requires-Python: >=3.10
7
- License-File: LICENSE
8
- Dynamic: license-file
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