scurrypy 0.3.4.3__py3-none-any.whl → 0.4__py3-none-any.whl

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.
discord/client.py CHANGED
@@ -281,6 +281,9 @@ class Client(ClientLike):
281
281
  except ConnectionError as e:
282
282
  self._logger.log_warn(f"Connection lost: {e}")
283
283
  raise
284
+ except Exception as e:
285
+ self._logger.log_error(f"{type(e).__name__} - {e}")
286
+ continue
284
287
 
285
288
  async def start(self):
286
289
  """Runs the main lifecycle of the bot.
@@ -126,11 +126,13 @@ class ModalData(DataModel):
126
126
  if custom_id != component.component.custom_id:
127
127
  continue
128
128
 
129
- match component.component.type:
130
- case 3: # string select -> values
131
- return component.component.values
132
- case 4: # text input -> value
133
- return component.component.value
129
+ t = component.component.type
130
+
131
+ if t in [3,5,6,7,8]: # select menus (w. possibly many option selects!)
132
+ return component.component.values
133
+
134
+ # text input
135
+ return component.component.value
134
136
 
135
137
  raise ValueError(f"Component custom id '{custom_id}' not found.")
136
138
 
@@ -83,12 +83,11 @@ class StringSelect(DataModel, ActionRowChild, LabelChild):
83
83
  @dataclass
84
84
  class _DefaultValue(DataModel):
85
85
  """Represents the Default Value for Select components."""
86
-
87
86
  id: int # ID of role, user, or channel
88
87
  type: Literal["role", "user", "channel"]
89
88
 
90
89
  @dataclass
91
- class UserSelect(DataModel, ActionRowChild):
90
+ class UserSelect(DataModel, ActionRowChild, LabelChild):
92
91
  """Represents the User Select component."""
93
92
  custom_id: str
94
93
  placeholder: Optional[str] = None
@@ -103,7 +102,7 @@ class UserSelect(DataModel, ActionRowChild):
103
102
  return self
104
103
 
105
104
  @dataclass
106
- class RoleSelect(DataModel, ActionRowChild):
105
+ class RoleSelect(DataModel, ActionRowChild, LabelChild):
107
106
  """Represents the Role Select component."""
108
107
  custom_id: str
109
108
  placeholder: Optional[str] = None
@@ -118,7 +117,7 @@ class RoleSelect(DataModel, ActionRowChild):
118
117
  return self
119
118
 
120
119
  @dataclass
121
- class MentionableSelect(DataModel, ActionRowChild):
120
+ class MentionableSelect(DataModel, ActionRowChild, LabelChild):
122
121
  """Represents the Mentionable Select component."""
123
122
  custom_id: str
124
123
  placeholder: Optional[str] = None
@@ -133,7 +132,7 @@ class MentionableSelect(DataModel, ActionRowChild):
133
132
  return self
134
133
 
135
134
  @dataclass
136
- class ChannelSelect(DataModel, ActionRowChild):
135
+ class ChannelSelect(DataModel, ActionRowChild, LabelChild):
137
136
  """Represents the Channel Select component."""
138
137
  custom_id: str
139
138
  placeholder: Optional[str] = None
@@ -196,59 +195,11 @@ class ActionRow(DataModel, ContainerChild):
196
195
  )
197
196
  return self
198
197
 
199
- def string_select(self, select: StringSelect):
200
- """Add a string select to this action row. (1 per row)
201
-
202
- Args:
203
- select (StringSelect): the StringSelect option object
204
-
205
- Returns:
206
- (ActionRow): self
207
- """
208
- self.components.append(select)
209
- return self
210
-
211
- def user_select(self, select: UserSelect):
212
- """Add a user select to this action row. (1 per row)
213
-
214
- Args:
215
- select (UserSelect): the UserSelect option object
216
-
217
- Returns:
218
- (ActionRow): self
219
- """
220
- self.components.append(select)
221
- return self
222
-
223
- def role_select(self, select: RoleSelect):
224
- """Add a role select to this action row. (1 per row)
225
-
226
- Args:
227
- select (RoleSelect): the RoleSelect option object
228
-
229
- Returns:
230
- (ActionRow): self
231
- """
232
- self.components.append(select)
233
- return self
234
-
235
- def channel_select(self, select: ChannelSelect):
236
- """Add a channel select to this action row. (1 per row)
237
-
238
- Args:
239
- select (ChannelSelect): the ChannelSelect option object
240
-
241
- Returns:
242
- (ActionRow): self
243
- """
244
- self.components.append(select)
245
- return self
246
-
247
- def mentionable_select(self, select: MentionableSelect):
248
- """Add a mentionable select to this action row. (1 per row)
198
+ def set_select_menu(self, select: StringSelect | UserSelect | RoleSelect | ChannelSelect | MentionableSelect):
199
+ """Add a select menu component to this action row. (1 per row)
249
200
 
250
201
  Args:
251
- select (MentionableSelect): the MentionableSelect option object
202
+ select (StringSelect | UserSelect | RoleSelect | ChannelSelect | MentionableSelect): the select menu component
252
203
 
253
204
  Returns:
254
205
  (ActionRow): self
@@ -3,7 +3,18 @@ from typing import Literal, Optional
3
3
  from ..model import DataModel
4
4
 
5
5
  from .component_types import *
6
- from .action_row import StringSelect, ActionRow
6
+ from ..models.emoji import EmojiModel
7
+
8
+ from .action_row import (
9
+ StringSelect,
10
+ ActionRow,
11
+ ChannelSelect,
12
+ MentionableSelect,
13
+ RoleSelect,
14
+ UserSelect,
15
+ _Button,
16
+ _ButtonStyles
17
+ )
7
18
 
8
19
  class _TextInputStyles:
9
20
  """Represents the types of Text Inputs."""
@@ -26,8 +37,79 @@ class _TextInput(DataModel, LabelChild):
26
37
  class Section(DataModel, ContainerChild):
27
38
  """Represents the Section component."""
28
39
  type: Literal[9] = field(init=False, default=9)
40
+
29
41
  accessory: Optional[SectionAccessory] = None
42
+ """A component that is contextually associated to the content of the section."""
43
+
30
44
  components: list[SectionChild] = field(default_factory=list)
45
+ """Component(s) representing the content of the section that is contextually associated to the accessory"""
46
+
47
+ def set_thumbnail(self, media: str, description: str = None, has_spoiler: bool = False):
48
+ """Set the thumbnail for this section.
49
+
50
+ Args:
51
+ media (str): Image data. http or attachment://<filename> scheme.
52
+ description (str, optional): Alt text for the media
53
+ has_spoiler (bool, optional): If the media should be blurred out. Defaults to False.
54
+
55
+ Returns:
56
+ (Section): self
57
+ """
58
+ self.accessory = _Thumbnail(media, description, has_spoiler)
59
+ return self
60
+
61
+ def add_text_display(self, content: str):
62
+ """Add a text display to this section.
63
+
64
+ Args:
65
+ content (str): the content to display
66
+
67
+ Returns:
68
+ (Section): self
69
+ """
70
+ self.components.append(_TextDisplay(content))
71
+ return self
72
+
73
+ def set_button(self,
74
+ *,
75
+ style: Literal['Primary', 'Secondary', 'Success', 'Danger', 'Link'],
76
+ label: str,
77
+ custom_id: str,
78
+ emoji: str | EmojiModel = None,
79
+ disable: bool = False
80
+ ):
81
+ """Set this section's accessory as a button.
82
+
83
+ Args:
84
+ style (Literal['Primary', 'Secondary', 'Success', 'Danger', 'Link']):
85
+ button style as a string
86
+ label (str): button text
87
+ custom_id (str): developer-defined button ID
88
+ emoji (str | EmojiModel, Optional): str if unicode emoji, EmojiModal if custom
89
+ disable (bool, Optional): if this button should be pressable. Defaults to False.
90
+
91
+ Returns:
92
+ (Section): self
93
+ """
94
+ _styles = {
95
+ 'PRIMARY': _ButtonStyles.PRIMARY,
96
+ 'SECONDARY': _ButtonStyles.SECONDARY,
97
+ 'SUCCESS': _ButtonStyles.SUCCESS,
98
+ 'DANGER': _ButtonStyles.DANGER,
99
+ 'LINK': _ButtonStyles.LINK
100
+ }
101
+
102
+ if isinstance(emoji, str):
103
+ emoji = EmojiModel(name=emoji)
104
+
105
+ self.accessory = _Button(
106
+ style=_styles.get(style.upper()),
107
+ label=label,
108
+ custom_id=custom_id,
109
+ emoji=emoji,
110
+ disabled=disable
111
+ )
112
+ return self
31
113
 
32
114
  @dataclass
33
115
  class _TextDisplay(DataModel, ContainerChild, SectionChild):
@@ -87,6 +169,7 @@ class _Separator(DataModel, ContainerChild):
87
169
  @dataclass
88
170
  class Label(DataModel):
89
171
  """Represents the Discord Label component."""
172
+
90
173
  label: str
91
174
  """Label text."""
92
175
 
@@ -98,11 +181,11 @@ class Label(DataModel):
98
181
 
99
182
  type: Literal[18] = field(init=False, default=18)
100
183
 
101
- def string_select(self, select: StringSelect):
102
- """Set this label to be a string select component.
184
+ def set_select_menu(self, select: StringSelect | UserSelect | RoleSelect | ChannelSelect | MentionableSelect):
185
+ """Set this label to be a select menu component.
103
186
 
104
187
  Args:
105
- select (StringSelect): the string select component
188
+ select (StringSelect | UserSelect | RoleSelect | ChannelSelect | MentionableSelect): the select menu component
106
189
 
107
190
  Returns:
108
191
  (Label): self
@@ -110,7 +193,7 @@ class Label(DataModel):
110
193
  self.component = select
111
194
  return self
112
195
 
113
- def text_input(self,
196
+ def set_text_input(self,
114
197
  *,
115
198
  custom_id: str,
116
199
  min_length: int,
discord/parts/message.py CHANGED
@@ -4,7 +4,6 @@ from discord.model import DataModel
4
4
  from .embed import EmbedBuilder
5
5
  from .action_row import ActionRow
6
6
  from .components_v2 import Container
7
- from .attachment import _Attachment
8
7
 
9
8
  class MessageFlags:
10
9
  """Flags that can be applied to a message."""
@@ -41,6 +40,21 @@ class _MessageReference(DataModel):
41
40
  channel_id: int
42
41
  type: int = 0
43
42
 
43
+ @dataclass
44
+ class _Attachment(DataModel):
45
+ """Represents an attachment."""
46
+ id: int
47
+ path: str
48
+ filename: str
49
+ description: str
50
+
51
+ def _to_dict(self):
52
+ return {
53
+ 'id': self.id,
54
+ 'filename': self.filename,
55
+ 'description': self.description
56
+ }
57
+
44
58
  @dataclass
45
59
  class MessageBuilder(DataModel):
46
60
  """Describes expected params when editing/creating a message."""
@@ -103,9 +103,14 @@ class Interaction(DataModel):
103
103
  Args:
104
104
  message (str | MessageBuilder): content as a string or from MessageBuilder
105
105
  with_response (bool, optional): if the interaction data should be returned. Defaults to False.
106
+
107
+ Raises:
108
+ TypeError: invalid type
106
109
  """
107
110
  if isinstance(message, str):
108
111
  message = MessageBuilder(content=message).set_flags(**flags)
112
+ elif not isinstance(message, MessageBuilder):
113
+ raise TypeError(f"Interaction.respond expects type str or MessageBuilder, got {type(message).__name__}")
109
114
 
110
115
  content = {
111
116
  'type': InteractionCallbackTypes.CHANNEL_MESSAGE_WITH_SOURCE,
@@ -129,9 +134,14 @@ class Interaction(DataModel):
129
134
 
130
135
  Args:
131
136
  message (str | MessageBuilder): content as a string or from MessageBuilder
137
+
138
+ Raises:
139
+ TypeError: invalid type
132
140
  """
133
141
  if isinstance(message, str):
134
142
  message = MessageBuilder(content=message).set_flags(**flags)
143
+ elif not isinstance(message, MessageBuilder):
144
+ raise TypeError(f"Interaction.update expects type str or MessageBuilder, got {type(message).__name__}")
135
145
 
136
146
  content = {
137
147
  'type': InteractionCallbackTypes.UPDATE_MESSAGE,
@@ -149,7 +159,13 @@ class Interaction(DataModel):
149
159
 
150
160
  Args:
151
161
  modal (ModalBuilder): modal data
162
+
163
+ Raises:
164
+ TypeError: invalid type
152
165
  """
166
+ if not isinstance(modal, ModalBuilder):
167
+ raise TypeError(f"Interaction.respond_modal expects type ModalBuilder, got {type(modal).__name__}")
168
+
153
169
  content = {
154
170
  'type': InteractionCallbackTypes.MODAL,
155
171
  'data': modal._to_dict()
@@ -0,0 +1,130 @@
1
+ Metadata-Version: 2.4
2
+ Name: scurrypy
3
+ Version: 0.4
4
+ Summary: Dataclass-driven 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
+ > **Official Repository**
16
+ > This is the original and official repository of **ScurryPy**, maintained by [Furmissile](https://github.com/Furmissile).
17
+ > Forks and community extensions are welcome under the project’s license and attribution guidelines.
18
+
19
+ A dataclass-driven Discord API wrapper in Python!
20
+
21
+ While this wrapper is mainly used for various squirrel-related shenanigans, it can also be used for more generic bot purposes.
22
+
23
+ ---
24
+
25
+ ## Features
26
+ * Command and event handling
27
+ * Declarative style using decorators
28
+ * Supports both legacy and new features
29
+ * Respects Discord’s rate limits
30
+
31
+ ---
32
+
33
+ ## Some Things to Consider...
34
+ * 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
+ * Certain features are not yet supported, while others are intentionally omitted. See the [docs](https://furmissile.github.io/scurrypy) for full details.
36
+
37
+ ---
38
+
39
+ ## Getting Started
40
+ *Note: This section also appears in the documentation, but here are complete examples ready to use with your bot credentials.*
41
+
42
+ ### Installation
43
+ To install the ScurryPy package, run:
44
+ ```bash
45
+ pip install scurrypy
46
+ ```
47
+
48
+ ## Minimal Slash Command
49
+ The following demonstrates building and responding to a slash command.
50
+
51
+ *Note: Adjust `dotenv_path` if your `.env` file is not in the same directory as this script.*
52
+
53
+ ```py
54
+ import discord, os
55
+ from dotenv import load_dotenv
56
+
57
+ load_dotenv(dotenv_path='./path/to/env')
58
+
59
+ client = discord.Client(
60
+ token=os.getenv("DISCORD_TOKEN"),
61
+ application_id=APPLICATION_ID # replace with your bot's user ID
62
+ )
63
+
64
+ @client.command(
65
+ command=discord.SlashCommand(
66
+ name='example',
67
+ description='Demonstrate the minimal slash command!'
68
+ ),
69
+ guild_ids=GUILD_ID # must be a guild ID your bot is in
70
+ )
71
+ async def example(bot: discord.Client, event: discord.InteractionEvent):
72
+ await event.interaction.respond(f'Hello, {event.interaction.member.user.username}!')
73
+
74
+ client.run()
75
+ ```
76
+
77
+ ## Minimal Prefix Command (Legacy)
78
+ The following demonstrates building and responding to a message prefix command.
79
+ ```py
80
+ import discord, os
81
+ from dotenv import load_dotenv
82
+
83
+ load_dotenv(dotenv_path='./path/to/env')
84
+
85
+ client = discord.Client(
86
+ token=os.getenv("DISCORD_TOKEN"),
87
+ application_id=APPLICATION_ID, # replace with your bot's user ID
88
+ intents=discord.set_intents(message_content=True),
89
+ prefix='!' # your custom prefix
90
+ )
91
+
92
+ @client.prefix_command
93
+ async def ping(bot: discord.Client, event: discord.MessageCreateEvent):
94
+ # The function name is the name of the command
95
+ await event.message.send("Pong!")
96
+
97
+ client.run()
98
+ ```
99
+
100
+ ## Contribution and Fork Policy
101
+ ScurryPy follows a simple philosophy: **clarity, simplicity, and direct interaction with the Discord API**.
102
+ It favors explicit, dataclass-driven design over heavy abstraction — and contributions should stay true to that style.
103
+
104
+ This is a community-supported project guided by the design and principles of **Furmissile**.
105
+ You are welcome to explore, modify, and extend the codebase under the terms of its license — but please follow these guidelines to ensure proper attribution and clarity.
106
+
107
+ ### You May
108
+ * Fork this repository for personal or collaborative development.
109
+ * Submit pull requests for bug fixes or new features that align with ScurryPy’s goals.
110
+ * Reuse parts of the code in your own projects, provided attribution is preserved.
111
+
112
+ ### You May NOT
113
+ * Remove or alter existing copyright notices or attributions.
114
+ * Present a fork as the official ScurryPy project.
115
+ * Use the name “ScurryPy” or its documentation to promote a fork without permission.
116
+
117
+ If you plan to make substantial changes or release your own variant:
118
+ * Rename the fork to avoid confusion (e.g., `scurrypy-plus` or `scurrypy-extended`).
119
+ * Add a note in your README acknowledging the original project:
120
+ > "This project is a fork of [ScurryPy](https://github.com/Furmissile/scurrypy)
121
+ by Furmissile."
122
+
123
+ ## License
124
+ This project is licensed under the Furmissile License, which allows viewing, modification, and redistribution with proper attribution.
125
+
126
+ See the [License](./LICENSE) for details.
127
+
128
+ ## Like What You See?
129
+ Check out the full [documentation](https://furmissile.github.io/scurrypy)
130
+ for more examples, guides, and API reference!
@@ -1,5 +1,5 @@
1
1
  discord/__init__.py,sha256=cETkxHmm0s9YkSJgn-1daQhnbL96fuD7L9SIg2t5vBg,6823
2
- discord/client.py,sha256=JvGKlEgtwIeYAKZEYRB_0nkOdJFTLsQCb-Dz3MQ_Gx8,14013
2
+ discord/client.py,sha256=9DcgF8Tb-K7t781GILBIh4LcU_Q1aYrNW_mHU-TA0bw,14144
3
3
  discord/client_like.py,sha256=JyJq0XBq0vKuPBJ_ZnYf5yAAuX1zz_2B1TZBQE-BYbQ,473
4
4
  discord/config.py,sha256=OH1A2mNKhDlGvQYASEsVUx2pNxP1YQ2a7a7z-IM5xFg,200
5
5
  discord/error.py,sha256=AlislRTna554cM6KC0KrwKugzYDYtx_9C8_3QFe4XDc,2070
@@ -16,7 +16,7 @@ discord/events/__init__.py,sha256=xE8YtJ7NKZkm7MLnohDQIbezh3ColmLR-3BMiZabt3k,18
16
16
  discord/events/channel_events.py,sha256=t9UL4JjDqulAP_XepQ8MRMW54pNRqCbIK3M8tauzf9I,1556
17
17
  discord/events/guild_events.py,sha256=Ok9tW3tjcwtbiqJgbe-42d9-R3-2RzqmIgBHEP-2Pcc,896
18
18
  discord/events/hello_event.py,sha256=O8Ketu_N943cnGaFkGsAHfWhgKXFQCYCqSD3EqdsXjA,225
19
- discord/events/interaction_events.py,sha256=5hlYOsV1ROiRXISAGCKcZo8vfk6oqiZcNzzZjSteiag,4361
19
+ discord/events/interaction_events.py,sha256=p5jb_KXrbE84773flwvbbS6yeh4f1w5Z-y93nQZJbEk,4374
20
20
  discord/events/message_events.py,sha256=M5xdaJH1zRzdZk0oN0Jykaeu9k09EjgZjeiIT_EkL1A,1475
21
21
  discord/events/reaction_events.py,sha256=xx7GD-fqakhJmS-X-HbuAUg9pg6Gqo_KRtLTdPJu7UE,2643
22
22
  discord/events/ready_event.py,sha256=c3Pf4ndNYV2byuliADi8pUxpuvKXa9FLKNz_uzIWGso,794
@@ -30,14 +30,13 @@ discord/models/member.py,sha256=pkI-NVRMb3hUBkxI26FSYZxzx2mRNGXOeWWCw3BGGsY,705
30
30
  discord/models/role.py,sha256=erlERmK-IZz4YzSNY-XLNvCc-Z5PoVlClxPOX67dQJg,1169
31
31
  discord/models/user.py,sha256=lgG6GoU_7L68oHt6PGTzTkU1vrbsclRQzGjKzsLBeKA,298
32
32
  discord/parts/__init__.py,sha256=yROb-BqEw-FKXqq_-0WbP33U-Arm_9NpJuEamXpvjeA,19
33
- discord/parts/action_row.py,sha256=PQ24Rr02QR4Sz1mypjM0C2gxYLH4Tsx7GvTorF4wsfQ,8264
34
- discord/parts/attachment.py,sha256=fhWpb5e0JKfbibcEc0EOiNrzqSSAUEL87NEhRmB1H34,388
33
+ discord/parts/action_row.py,sha256=QVi5-ZtVRBKbG0n0L53cj4bu2ZEMUnJ9y3TlqFxaHlg,7105
35
34
  discord/parts/channel.py,sha256=2wmEjmRqUpORzL3CFp2rugMxrpSm_LxxvlcrmWIH4r4,584
36
35
  discord/parts/command.py,sha256=CPyPO_T5ULp7j7syF9z2LztP3SF6KyX89sodz2c40Aw,2924
37
36
  discord/parts/component_types.py,sha256=qr1R0jzXpE_h9Xv4P5DyYRSuhxS0Qnm9aag-JKrJvBA,131
38
- discord/parts/components_v2.py,sha256=53cQm4FmxXHAA7PmDcDIO4bergX-BaUB3bZVWej-U9s,8660
37
+ discord/parts/components_v2.py,sha256=R2ihx8st12oHUFxJ-H_-qPR-4aSlSPslNfKOCBNiwTw,11403
39
38
  discord/parts/embed.py,sha256=_PV-lEAKn-MiXyyLa2s8JKHEplA8J9dDO80NPdZtmLk,3986
40
- discord/parts/message.py,sha256=XSRGYQjmbVyS9YG6VVw19chU1CUUljrFpUy6NY2HRJ0,5517
39
+ discord/parts/message.py,sha256=xfzVuDafx9kXsY4Mfk3urMj1HbJXTEVdHvyTZKRwCt0,5800
41
40
  discord/parts/modal.py,sha256=EX6J9Mh5dAQBOZqYKzSE7SFsKLfM_B1BhcJamjBNkZw,554
42
41
  discord/parts/role.py,sha256=cK96UdgT-kU0gY5C_1LZXPrYg144x2RDmGjT28so57A,920
43
42
  discord/resources/__init__.py,sha256=EdzYKftSLqqr3Bpzc0_90kfozJXOtp9jNTIHhCTt_-0,21
@@ -45,11 +44,11 @@ discord/resources/application.py,sha256=vYMTli_FSbC7venMepsJ9bkzdEQVkKYpnxCJ9K2X
45
44
  discord/resources/bot_emojis.py,sha256=RvGCSOBkjS39P2aab0FzYUOTzBOiHX99RLrJZzAYNiU,1701
46
45
  discord/resources/channel.py,sha256=fe2JUp943VnXa-BKyRMtNP-JyNd_Mp516sWBKHKn_GI,6915
47
46
  discord/resources/guild.py,sha256=Unld1lWY3XynmRHU2FCi3-LA9VNp2thMI2BlILUTTxk,8183
48
- discord/resources/interaction.py,sha256=mr4kLecQpl3AtgnNeqnj3eZIwQ73Clutdi-gnoSMWVU,5237
47
+ discord/resources/interaction.py,sha256=esbkN8r7c1GhAvRqldrua_a6PSuIVPJLw3OQAZ0zy1c,5922
49
48
  discord/resources/message.py,sha256=RtvcCRx0lwW-mHPl3aNYoEvGffrvtpLsQ2fVWckywVI,7527
50
49
  discord/resources/user.py,sha256=vk89TnCVi-6ZgbDs_TZTCXrx_NfFS5Q9Wi_itYoaoyg,3085
51
- scurrypy-0.3.4.3.dist-info/licenses/LICENSE,sha256=NtspfRMAlryd1Eev4BYi9EFbKhvdmlCJJ2-ADUoEBoI,426
52
- scurrypy-0.3.4.3.dist-info/METADATA,sha256=GshbnJ8_Xw7Xw3BEBlvldCs-n6cyAOHJGQSo8p4S9tQ,2956
53
- scurrypy-0.3.4.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
54
- scurrypy-0.3.4.3.dist-info/top_level.txt,sha256=fJkrNbR-_8ubMBUcDEJBcfkpECrvSEmMrNKgvLlQFoM,8
55
- scurrypy-0.3.4.3.dist-info/RECORD,,
50
+ scurrypy-0.4.dist-info/licenses/LICENSE,sha256=qIlBETYpSEU8glbiwiJbuDxVl-2WIuf1PDqJemMjKkc,792
51
+ scurrypy-0.4.dist-info/METADATA,sha256=J9enmBVZsPDNbClN0t9p5_SAksFXso23AIjtgBREbNE,4795
52
+ scurrypy-0.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
53
+ scurrypy-0.4.dist-info/top_level.txt,sha256=fJkrNbR-_8ubMBUcDEJBcfkpECrvSEmMrNKgvLlQFoM,8
54
+ scurrypy-0.4.dist-info/RECORD,,
@@ -0,0 +1,16 @@
1
+ Copyright (c) 2025 Furmissile. All rights reserved.
2
+
3
+ Permission is granted to view, use, modify, and distribute copies of this software
4
+ and its source code, provided that:
5
+
6
+ 1. Attribution to the original author, Furmissile, is preserved in all copies and
7
+ derivative works.
8
+ 2. The name "ScurryPy" and associated branding may not be used to promote derived
9
+ projects without explicit permission.
10
+ 3. This license and copyright notice must be included in all copies or substantial
11
+ portions of the software.
12
+ 4. This software is provided "as is", without warranty of any kind, express or
13
+ implied. The author assumes no liability for any damages arising from its use.
14
+
15
+ 5. This software may not be used for commercial purposes without written consent
16
+ from the author.
@@ -1,18 +0,0 @@
1
- from dataclasses import dataclass
2
-
3
- from ..model import DataModel
4
-
5
- @dataclass
6
- class _Attachment(DataModel):
7
- """Represents an attachment."""
8
- id: int
9
- path: str
10
- filename: str
11
- description: str
12
-
13
- def _to_dict(self):
14
- return {
15
- 'id': self.id,
16
- 'filename': self.filename,
17
- 'description': self.description
18
- }
@@ -1,92 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: scurrypy
3
- Version: 0.3.4.3
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
- ## Some things to consider...
26
- * 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.
27
- * Certain features are not yet supported, while others are intentionally omitted. See the [docs](https://furmissile.github.io/scurrypy) for full details.
28
-
29
- ## Getting Started
30
- *Note: This section also appears in the documentation, but here are complete examples ready to use with your bot credentials.*
31
-
32
- ### Installation
33
- To install the ScurryPy package, run:
34
- ```bash
35
- pip install scurrypy
36
- ```
37
-
38
- ### Minimal Slash Command
39
- The following demonstrates building and responding to a slash command.
40
-
41
- *Note: Adjust `dotenv_path` if your `.env` file is not in the same directory as this script.*
42
-
43
- ```python
44
- import discord, os
45
- from dotenv import load_dotenv
46
-
47
- load_dotenv(dotenv_path='./path/to/env')
48
-
49
- client = discord.Client(
50
- token=os.getenv("DISCORD_TOKEN"),
51
- application_id=APPLICATION_ID # replace with your bot's user ID
52
- )
53
-
54
- @client.command(
55
- command=discord.SlashCommand(
56
- name='example',
57
- description='Demonstrate the minimal slash command!'
58
- ),
59
- guild_id=GUILD_ID # must be a guild ID your bot is in
60
- )
61
- async def example(bot: discord.Client, event: discord.InteractionEvent):
62
- await event.interaction.respond(f'Hello, {event.interaction.member.user.username}!')
63
-
64
- client.run()
65
- ```
66
-
67
- ### Minimal Prefix Command (Legacy)
68
- The following demonstrates building and responding to a message prefix command.
69
-
70
- ```python
71
- import discord, os
72
- from dotenv import load_dotenv
73
-
74
- load_dotenv(dotenv_path='./path/to/env')
75
-
76
- client = discord.Client(
77
- token=os.getenv("DISCORD_TOKEN"),
78
- application_id=APPLICATION_ID, # replace with your bot's user ID
79
- intents=discord.set_intents(message_content=True),
80
- prefix='!' # your custom prefix
81
- )
82
-
83
- @client.prefix_command
84
- async def ping(bot: discord.Client, event: discord.MessageCreateEvent):
85
- # The function name is the name of the command
86
- await event.message.send("Pong!")
87
-
88
- client.run()
89
- ```
90
-
91
- ## Like what you see?
92
- Check out the full [documentation](https://furmissile.github.io/scurrypy) for more examples, guides, and API reference!
@@ -1,5 +0,0 @@
1
- Copyright (c) 2025 Furmissile. All rights reserved.
2
-
3
- Derivative works are not permitted -- the source code is made available for educational and reference purposes only, and is not exempt from licensing.
4
- This software is provided on an "as-is" basis and the author is not responsible for any liability that may come from misuse.
5
- No commercial profit may be drawn off of derivatives of this software project for any reason.