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 +3 -0
- discord/events/interaction_events.py +7 -5
- discord/parts/action_row.py +7 -56
- discord/parts/components_v2.py +88 -5
- discord/parts/message.py +15 -1
- discord/resources/interaction.py +16 -0
- scurrypy-0.4.dist-info/METADATA +130 -0
- {scurrypy-0.3.4.3.dist-info → scurrypy-0.4.dist-info}/RECORD +11 -12
- scurrypy-0.4.dist-info/licenses/LICENSE +16 -0
- discord/parts/attachment.py +0 -18
- scurrypy-0.3.4.3.dist-info/METADATA +0 -92
- scurrypy-0.3.4.3.dist-info/licenses/LICENSE +0 -5
- {scurrypy-0.3.4.3.dist-info → scurrypy-0.4.dist-info}/WHEEL +0 -0
- {scurrypy-0.3.4.3.dist-info → scurrypy-0.4.dist-info}/top_level.txt +0 -0
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
|
discord/parts/action_row.py
CHANGED
|
@@ -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
|
|
200
|
-
"""Add a
|
|
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
|
|
202
|
+
select (StringSelect | UserSelect | RoleSelect | ChannelSelect | MentionableSelect): the select menu component
|
|
252
203
|
|
|
253
204
|
Returns:
|
|
254
205
|
(ActionRow): self
|
discord/parts/components_v2.py
CHANGED
|
@@ -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 .
|
|
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
|
|
102
|
-
"""Set this label to be a
|
|
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
|
|
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
|
|
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."""
|
discord/resources/interaction.py
CHANGED
|
@@ -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
|
+
[](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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
52
|
-
scurrypy-0.
|
|
53
|
-
scurrypy-0.
|
|
54
|
-
scurrypy-0.
|
|
55
|
-
scurrypy-0.
|
|
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.
|
discord/parts/attachment.py
DELETED
|
@@ -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
|
-
[](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.
|
|
File without changes
|
|
File without changes
|