scurrypy 0.1.0__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.
Potentially problematic release.
This version of scurrypy might be problematic. Click here for more details.
- discord/__init__.py +9 -0
- discord/client.py +312 -0
- discord/dispatch/__init__.py +1 -0
- discord/dispatch/command_dispatcher.py +156 -0
- discord/dispatch/event_dispatcher.py +85 -0
- discord/dispatch/prefix_dispatcher.py +53 -0
- discord/error.py +63 -0
- discord/events/__init__.py +33 -0
- discord/events/channel_events.py +52 -0
- discord/events/guild_events.py +38 -0
- discord/events/hello_event.py +9 -0
- discord/events/interaction_events.py +145 -0
- discord/events/message_events.py +43 -0
- discord/events/reaction_events.py +99 -0
- discord/events/ready_event.py +30 -0
- discord/gateway.py +175 -0
- discord/http.py +292 -0
- discord/intents.py +87 -0
- discord/logger.py +147 -0
- discord/model.py +88 -0
- discord/models/__init__.py +8 -0
- discord/models/application.py +37 -0
- discord/models/emoji.py +34 -0
- discord/models/guild.py +35 -0
- discord/models/integration.py +23 -0
- discord/models/member.py +27 -0
- discord/models/role.py +53 -0
- discord/models/user.py +15 -0
- discord/parts/__init__.py +28 -0
- discord/parts/action_row.py +258 -0
- discord/parts/attachment.py +18 -0
- discord/parts/channel.py +20 -0
- discord/parts/command.py +102 -0
- discord/parts/component_types.py +5 -0
- discord/parts/components_v2.py +270 -0
- discord/parts/embed.py +154 -0
- discord/parts/message.py +179 -0
- discord/parts/modal.py +21 -0
- discord/parts/role.py +39 -0
- discord/resources/__init__.py +10 -0
- discord/resources/application.py +94 -0
- discord/resources/bot_emojis.py +49 -0
- discord/resources/channel.py +192 -0
- discord/resources/guild.py +265 -0
- discord/resources/interaction.py +155 -0
- discord/resources/message.py +223 -0
- discord/resources/user.py +111 -0
- scurrypy-0.1.0.dist-info/METADATA +8 -0
- scurrypy-0.1.0.dist-info/RECORD +52 -0
- scurrypy-0.1.0.dist-info/WHEEL +5 -0
- scurrypy-0.1.0.dist-info/licenses/LICENSE +5 -0
- scurrypy-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Literal, Optional
|
|
3
|
+
from ..model import DataModel
|
|
4
|
+
|
|
5
|
+
from .component_types import *
|
|
6
|
+
from .action_row import StringSelect, ActionRow
|
|
7
|
+
|
|
8
|
+
class _TextInputStyles:
|
|
9
|
+
"""Represents the types of Text Inputs."""
|
|
10
|
+
SHORT = 1 # one line
|
|
11
|
+
PARAGRAPH = 2 # multiple lines
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class _TextInput(DataModel, LabelChild):
|
|
15
|
+
"""Represents the Text Input component."""
|
|
16
|
+
type: Literal[4] = field(init=False, default=4)
|
|
17
|
+
style: _TextInputStyles = _TextInputStyles.SHORT # refer to _TextInputStyles for details
|
|
18
|
+
custom_id: str = None
|
|
19
|
+
required: Optional[bool] = False
|
|
20
|
+
min_length: Optional[int] = None
|
|
21
|
+
max_length: Optional[int] = None
|
|
22
|
+
value: Optional[str] = None
|
|
23
|
+
placeholder: Optional[str] = None
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class Section(DataModel, ContainerChild):
|
|
27
|
+
"""Represents the Section component."""
|
|
28
|
+
type: Literal[9] = field(init=False, default=9)
|
|
29
|
+
accessory: Optional[SectionAccessory] = None
|
|
30
|
+
components: list[SectionChild] = field(default_factory=list)
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class _TextDisplay(DataModel, ContainerChild, SectionChild):
|
|
34
|
+
"""Represents the Text Display component."""
|
|
35
|
+
type: Literal[10] = field(init=False, default=10)
|
|
36
|
+
content: str
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class _Thumbnail(DataModel, SectionAccessory):
|
|
41
|
+
"""Represents the _Thumbnail component."""
|
|
42
|
+
type: Literal[11] = field(init=False, default=11)
|
|
43
|
+
media: str # http or attachment://<filename>
|
|
44
|
+
description: Optional[str] = None
|
|
45
|
+
spoiler: Optional[bool] = False
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class MediaGalleryItem(DataModel):
|
|
50
|
+
"""Represents the Media Gallery Item component."""
|
|
51
|
+
|
|
52
|
+
media: str
|
|
53
|
+
"""Image data. http or attachment://<filename> scheme."""
|
|
54
|
+
|
|
55
|
+
description: Optional[str] = None
|
|
56
|
+
"""Alt text for the media."""
|
|
57
|
+
|
|
58
|
+
spoiler: Optional[bool] = False
|
|
59
|
+
"""If the media should be blurred out."""
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class _MediaGallery(DataModel, ContainerChild):
|
|
63
|
+
"""Represents the Media Gallery component."""
|
|
64
|
+
type: Literal[12] = field(init=False, default=12)
|
|
65
|
+
items: list[MediaGalleryItem] = field(default_factory=list)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class _File(DataModel, ContainerChild):
|
|
70
|
+
"""Represents the File component."""
|
|
71
|
+
type: Literal[13] = field(init=False, default=13)
|
|
72
|
+
file: str # http or attachment://<filename>
|
|
73
|
+
spoiler: Optional[bool] = False
|
|
74
|
+
|
|
75
|
+
class _SeparatorTypes:
|
|
76
|
+
"""Represents separator types constants."""
|
|
77
|
+
SMALL_PADDING = 1
|
|
78
|
+
LARGE_PADDING = 2
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class _Separator(DataModel, ContainerChild):
|
|
82
|
+
"""Represents the Separator component."""
|
|
83
|
+
type: Literal[14] = field(init=False, default=14)
|
|
84
|
+
divider: bool = True
|
|
85
|
+
spacing: Optional[int] = _SeparatorTypes.SMALL_PADDING # refer to _SeparatorTypes
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class Label(DataModel):
|
|
89
|
+
"""Represents the Discord Label component."""
|
|
90
|
+
label: str
|
|
91
|
+
"""Label text."""
|
|
92
|
+
|
|
93
|
+
component: LabelChild = None
|
|
94
|
+
"""A component within the label."""
|
|
95
|
+
|
|
96
|
+
description: Optional[str] = None
|
|
97
|
+
"""An optional description text for the label."""
|
|
98
|
+
|
|
99
|
+
type: Literal[18] = field(init=False, default=18)
|
|
100
|
+
|
|
101
|
+
def string_select(self, select: StringSelect):
|
|
102
|
+
"""Set this label to be a string select component.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
select (StringSelect): the string select component
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
(Label): self
|
|
109
|
+
"""
|
|
110
|
+
self.component = select
|
|
111
|
+
return self
|
|
112
|
+
|
|
113
|
+
def text_input(self,
|
|
114
|
+
*,
|
|
115
|
+
custom_id: str,
|
|
116
|
+
min_length: int,
|
|
117
|
+
max_length: int,
|
|
118
|
+
value: str = None,
|
|
119
|
+
style: Literal['Short', 'Paragraph'] = 'Short',
|
|
120
|
+
placeholder: str = None,
|
|
121
|
+
require: bool = False
|
|
122
|
+
):
|
|
123
|
+
"""Set this label to be a text input component.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
custom_id (str): developer-defined component ID
|
|
127
|
+
min_length (int): minimum number of characters required
|
|
128
|
+
max_length (int): maximum number of characters required
|
|
129
|
+
value (str, optional): component value
|
|
130
|
+
style (Literal['Short', 'Paragraph'], optional):
|
|
131
|
+
text format. Defaults to 'Short'.
|
|
132
|
+
placeholder (str, optional): custom placeholder text if empty
|
|
133
|
+
require (bool, optional): if input is required. Defaults to False.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
(Label): self
|
|
137
|
+
"""
|
|
138
|
+
_styles = {
|
|
139
|
+
'SHORT': _TextInputStyles.SHORT,
|
|
140
|
+
'PARAGRAPH': _TextInputStyles.PARAGRAPH
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
self.component = _TextInput(
|
|
144
|
+
style = _styles.get(style.upper()),
|
|
145
|
+
placeholder=placeholder,
|
|
146
|
+
custom_id=custom_id,
|
|
147
|
+
min_length=min_length,
|
|
148
|
+
max_length=max_length,
|
|
149
|
+
value=value,
|
|
150
|
+
required=require
|
|
151
|
+
)
|
|
152
|
+
return self
|
|
153
|
+
|
|
154
|
+
@dataclass
|
|
155
|
+
class Container(DataModel):
|
|
156
|
+
"""Represents a container of display and interactable components."""
|
|
157
|
+
type: Literal[17] = field(init=False, default=17)
|
|
158
|
+
|
|
159
|
+
components: list[ContainerChild] = field(default_factory=list)
|
|
160
|
+
"""Child components that are encapsulated within the Container."""
|
|
161
|
+
|
|
162
|
+
accent_color: Optional[int] = None
|
|
163
|
+
"""Color for the accent as an integer."""
|
|
164
|
+
|
|
165
|
+
spoiler: Optional[bool] = False
|
|
166
|
+
"""If the container should be blurred out."""
|
|
167
|
+
|
|
168
|
+
def set_color(self, hex: str):
|
|
169
|
+
"""Set this container's color with a hex. (format: #FFFFFF)
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
hex (str): color as a hex code
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
(Container): self
|
|
176
|
+
"""
|
|
177
|
+
self.accent_color = int(hex.strip('#'), 16)
|
|
178
|
+
return self
|
|
179
|
+
|
|
180
|
+
def add_row(self, row: ActionRow):
|
|
181
|
+
"""Add an action row to this container.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
row (ActionRow): the ActionRow object
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
(Container): self
|
|
188
|
+
"""
|
|
189
|
+
self.components.append(row)
|
|
190
|
+
return self
|
|
191
|
+
|
|
192
|
+
def add_section(self, section: Section):
|
|
193
|
+
"""Add a section to this container.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
section (Section): the Section object
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
(Container): self
|
|
200
|
+
"""
|
|
201
|
+
self.components.append(section)
|
|
202
|
+
return self
|
|
203
|
+
|
|
204
|
+
def add_text_display(self, content: str):
|
|
205
|
+
"""Add a text display to this container.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
content (str): the content to display
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
(Container): self
|
|
212
|
+
"""
|
|
213
|
+
self.components.append(_TextDisplay(content))
|
|
214
|
+
return self
|
|
215
|
+
|
|
216
|
+
def set_thumbnail(self, media: str, description: str = None, has_spoiler: bool = False):
|
|
217
|
+
"""Set the thumbnail for this container
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
media (str): Image data. http or attachment://<filename> scheme.
|
|
221
|
+
description (str, optional): Alt text for the media
|
|
222
|
+
has_spoiler (bool, optional): If the media should be blurred out. Defaults to False.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
(Container): self
|
|
226
|
+
"""
|
|
227
|
+
self.components.append(_Thumbnail(media, description, has_spoiler))
|
|
228
|
+
return self
|
|
229
|
+
|
|
230
|
+
def set_media_gallery(self, items: list[MediaGalleryItem]):
|
|
231
|
+
"""Add a media gallery to this container.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
items (list[MediaGalleryItem]): list of media gallery images
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
(Container): self
|
|
238
|
+
"""
|
|
239
|
+
self.components.append(_MediaGallery(items))
|
|
240
|
+
return self
|
|
241
|
+
|
|
242
|
+
def add_attachment(self, file: str, has_spoiler: bool = False):
|
|
243
|
+
"""Add a single attachment to this container.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
file (str): Image data. http or attachment://<filename> scheme
|
|
247
|
+
has_spoiler (bool, optional): If the media should be blurred out. Defaults to False.
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
(Container): self
|
|
251
|
+
"""
|
|
252
|
+
self.components.append(_File(file, has_spoiler))
|
|
253
|
+
return self
|
|
254
|
+
|
|
255
|
+
def add_separator(self, spacing: Literal['Small', 'Large'] = 'Small', has_divider: bool = True):
|
|
256
|
+
"""Add a separator to this container. Positionally accurate.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
spacing (Literal['Small', 'Large'], optional): size of separator padding. Defaults to 'Small'.
|
|
260
|
+
has_divider (bool, optional): if a visual divider should be shown. Defaults to True.
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
(Container): self
|
|
264
|
+
"""
|
|
265
|
+
_spacing_types = {
|
|
266
|
+
'SMALL': _SeparatorTypes.SMALL_PADDING,
|
|
267
|
+
'LARGE': _SeparatorTypes.LARGE_PADDING
|
|
268
|
+
}
|
|
269
|
+
self.components.append(_Separator(divider=has_divider, spacing=_spacing_types.get(spacing.upper())))
|
|
270
|
+
return self
|
discord/parts/embed.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from discord.model import DataModel
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
from ..models.user import UserModel
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class _EmbedAuthor(DataModel):
|
|
9
|
+
"""Embed author parameters."""
|
|
10
|
+
name: str
|
|
11
|
+
url: Optional[str] = None
|
|
12
|
+
icon_url: Optional[str] = None
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class _EmbedThumbnail(DataModel):
|
|
16
|
+
"""Embed thumbnail."""
|
|
17
|
+
url: str
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class _EmbedImage(DataModel):
|
|
21
|
+
"""Embed image."""
|
|
22
|
+
url: str
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class _EmbedFooter(DataModel):
|
|
26
|
+
"""Embed footer."""
|
|
27
|
+
text: str
|
|
28
|
+
url: Optional[str] = None
|
|
29
|
+
icon_url: Optional[str] = None
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class _EmbedField(DataModel):
|
|
33
|
+
"""Embed field."""
|
|
34
|
+
name: str
|
|
35
|
+
value: str
|
|
36
|
+
inline: Optional[bool] = None
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class EmbedBuilder(DataModel):
|
|
40
|
+
"""Represents the Embed portion of a message."""
|
|
41
|
+
|
|
42
|
+
title: Optional[str] = None
|
|
43
|
+
"""This embed's title."""
|
|
44
|
+
|
|
45
|
+
description: Optional[str] = None
|
|
46
|
+
"""This embed's description."""
|
|
47
|
+
|
|
48
|
+
timestamp: Optional[str] = None
|
|
49
|
+
"""Timestamp of when the embed was sent."""
|
|
50
|
+
|
|
51
|
+
color: Optional[int] = None
|
|
52
|
+
"""Embed's accent color."""
|
|
53
|
+
|
|
54
|
+
author: Optional[_EmbedAuthor] = None
|
|
55
|
+
"""Embed's author."""
|
|
56
|
+
|
|
57
|
+
thumbnail: Optional[_EmbedThumbnail] = None
|
|
58
|
+
"""Embed's thumbnail attachment."""
|
|
59
|
+
|
|
60
|
+
image: Optional[_EmbedImage] = None
|
|
61
|
+
"""Embed's image attachment."""
|
|
62
|
+
|
|
63
|
+
fields: Optional[list[_EmbedField]] = None
|
|
64
|
+
"""List of embed's fields."""
|
|
65
|
+
|
|
66
|
+
footer: Optional[_EmbedFooter] = None
|
|
67
|
+
"""Embed's footer."""
|
|
68
|
+
|
|
69
|
+
def set_color(self, hex: str):
|
|
70
|
+
"""Set this embed's color with a hex.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
hex (str): color as a hex code (format: #FFFFFF)
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
(EmbedBuilder): self
|
|
77
|
+
"""
|
|
78
|
+
self.color=int(hex.strip('#'), 16)
|
|
79
|
+
return self
|
|
80
|
+
|
|
81
|
+
def set_user_author(self, user: UserModel):
|
|
82
|
+
"""Set this embed's author.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
user (UserModel): the user model
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
(EmbedBuilder): self
|
|
89
|
+
"""
|
|
90
|
+
self.author = _EmbedAuthor(
|
|
91
|
+
name=user.username,
|
|
92
|
+
icon_url=f"https://cdn.discordapp.com/avatars/{user.id}/{user.avatar}.png"
|
|
93
|
+
)
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
def set_image(self, url: str):
|
|
97
|
+
"""Set this embed's image.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
url (str): attachment://<file> scheme or http(s) URL
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
(EmbedBuilder): self
|
|
104
|
+
"""
|
|
105
|
+
self.image = _EmbedImage(url=url)
|
|
106
|
+
return self
|
|
107
|
+
|
|
108
|
+
def set_thumbnail(self, url: str):
|
|
109
|
+
"""Set this embed's thumbnail.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
url (str): attachment://<file> scheme or http(s) URL
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
(EmbedBuilder): self
|
|
116
|
+
"""
|
|
117
|
+
self.thumbnail = _EmbedThumbnail(url=url)
|
|
118
|
+
return self
|
|
119
|
+
|
|
120
|
+
def set_footer(self, text: str, icon_url: str = None):
|
|
121
|
+
"""Set this embed's footer.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
text (str): footer's text
|
|
125
|
+
icon_url (str, optional): attachment://<file> scheme or http(s) URL.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
(EmbedBuilder): self
|
|
129
|
+
"""
|
|
130
|
+
self.footer = _EmbedFooter(text=text, icon_url=icon_url)
|
|
131
|
+
return self
|
|
132
|
+
|
|
133
|
+
def add_field(self, name: str, value: str, is_inline: bool = False):
|
|
134
|
+
"""Add a field to this embed.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
name (str): field's title
|
|
138
|
+
value (str): field's text
|
|
139
|
+
is_inline (bool): if this field should be inlined
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
(EmbedBuilder): self
|
|
143
|
+
"""
|
|
144
|
+
self.fields.append(_EmbedField(name=name, value=value, inline=is_inline))
|
|
145
|
+
return self
|
|
146
|
+
|
|
147
|
+
def set_timestamp(self):
|
|
148
|
+
"""Set this embed's timestamp.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
(EmbedBuilder): self
|
|
152
|
+
"""
|
|
153
|
+
self.timestamp = datetime.now(timezone.utc).isoformat()
|
|
154
|
+
return self
|
discord/parts/message.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import Optional, TypedDict, Unpack, Literal
|
|
4
|
+
from discord.model import DataModel
|
|
5
|
+
from .embed import EmbedBuilder
|
|
6
|
+
from .action_row import ActionRow
|
|
7
|
+
from .components_v2 import Container
|
|
8
|
+
from .attachment import _Attachment
|
|
9
|
+
|
|
10
|
+
class MessageFlags:
|
|
11
|
+
"""Flags that can be applied to a message."""
|
|
12
|
+
CROSSPOSTED = 1 << 0
|
|
13
|
+
"""Message has been published."""
|
|
14
|
+
|
|
15
|
+
IS_CROSSPOST = 1 << 1
|
|
16
|
+
"""Message originated from another channel."""
|
|
17
|
+
|
|
18
|
+
SUPPRESS_EMBEDS = 1 << 2
|
|
19
|
+
"""Hide embeds (if any)."""
|
|
20
|
+
|
|
21
|
+
EPHEMERAL = 1 << 6
|
|
22
|
+
"""Only visible to the invoking user."""
|
|
23
|
+
|
|
24
|
+
LOADING = 1 << 7
|
|
25
|
+
"""Thinking response."""
|
|
26
|
+
|
|
27
|
+
IS_COMPONENTS_V2 = 1 << 15
|
|
28
|
+
"""This message includes Discord's V2 Components."""
|
|
29
|
+
|
|
30
|
+
class MessageFlagParams(TypedDict, total=False):
|
|
31
|
+
"""Parameters for setting message flags."""
|
|
32
|
+
crossposted: bool
|
|
33
|
+
is_crosspost: bool
|
|
34
|
+
suppress_embeds: bool
|
|
35
|
+
ephemeral: bool
|
|
36
|
+
loading: bool
|
|
37
|
+
is_components_v2: bool
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class _MessageReference(DataModel):
|
|
41
|
+
message_id: int
|
|
42
|
+
channel_id: int
|
|
43
|
+
type: int = 0
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class MessageBuilder(DataModel):
|
|
47
|
+
"""Describes expected params when editing/creating a message."""
|
|
48
|
+
|
|
49
|
+
content: Optional[str] = None
|
|
50
|
+
"""Message text content."""
|
|
51
|
+
|
|
52
|
+
flags: Optional[int] = 0
|
|
53
|
+
"""Message flags. See [`MessageFlags`][discord.parts.message.MessageFlags] for details."""
|
|
54
|
+
|
|
55
|
+
components: Optional[list[ActionRow | Container]] = field(default_factory=list)
|
|
56
|
+
"""Components to be attached to this message."""
|
|
57
|
+
|
|
58
|
+
attachments: Optional[list[_Attachment]] = field(default_factory=list)
|
|
59
|
+
"""Attachments to be attached to this message."""
|
|
60
|
+
|
|
61
|
+
embeds: Optional[list[EmbedBuilder]] = field(default_factory=list)
|
|
62
|
+
"""Embeds to be attached to this message."""
|
|
63
|
+
|
|
64
|
+
message_reference: Optional[_MessageReference] = None
|
|
65
|
+
"""Message reference if reply."""
|
|
66
|
+
|
|
67
|
+
def add_row(self, row: ActionRow):
|
|
68
|
+
"""Add an action row to this message.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
row (ActionRow): the ActionRow object
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
(MessageBuilder): self
|
|
75
|
+
"""
|
|
76
|
+
self.components.append(row)
|
|
77
|
+
return self
|
|
78
|
+
|
|
79
|
+
def add_container(self, container: Container, *, has_container_boarder: bool = False):
|
|
80
|
+
"""Add a container to this message.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
container (Container): the Container object.
|
|
84
|
+
has_container_boarder (bool, optional): If message should be contained in an Embed-like container. Defaults to False.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
(MessageBuilder): self
|
|
88
|
+
"""
|
|
89
|
+
if has_container_boarder:
|
|
90
|
+
self.components.append(container)
|
|
91
|
+
else:
|
|
92
|
+
self.components.extend(container.components)
|
|
93
|
+
return self
|
|
94
|
+
|
|
95
|
+
def add_embed(self, embed: EmbedBuilder):
|
|
96
|
+
"""Add an embed to this message.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
embed (EmbedBuilder): The EmbedBuilder object.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
(MessageBuilder): self
|
|
103
|
+
"""
|
|
104
|
+
self.embeds.append(embed)
|
|
105
|
+
return self
|
|
106
|
+
|
|
107
|
+
def add_attachment(self, file_path: str, description: str = None):
|
|
108
|
+
"""Add an attachment to this message
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
file_path (str): full qualifying path to file
|
|
112
|
+
description (str, optional): file descriptor. Defaults to None.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
(MessageBuilder): self
|
|
116
|
+
"""
|
|
117
|
+
self.attachments.append(
|
|
118
|
+
_Attachment(
|
|
119
|
+
id=len(self.attachments),
|
|
120
|
+
filename=os.path.basename(file_path),
|
|
121
|
+
path=file_path,
|
|
122
|
+
description=description
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
return self
|
|
126
|
+
|
|
127
|
+
def set_flags(self, **flags: Unpack[MessageFlagParams]):
|
|
128
|
+
"""Set this message's flags using MessageFlagParams.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
flags (Unpack[MessageFlagParams]): message flags to set. (set respective flag to True to toggle.)
|
|
132
|
+
|
|
133
|
+
Raises:
|
|
134
|
+
(ValueError): invalid flag
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
(MessageBuilder): self
|
|
138
|
+
"""
|
|
139
|
+
_flag_map = {
|
|
140
|
+
'crossposted': MessageFlags.CROSSPOSTED,
|
|
141
|
+
'is_crosspost': MessageFlags.IS_CROSSPOST,
|
|
142
|
+
'suppress_embeds': MessageFlags.SUPPRESS_EMBEDS,
|
|
143
|
+
'ephemeral': MessageFlags.EPHEMERAL,
|
|
144
|
+
'loading': MessageFlags.LOADING,
|
|
145
|
+
'is_components_v2': MessageFlags.IS_COMPONENTS_V2,
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# each flag maps to a specific combined bit!
|
|
149
|
+
for name, value in flags.items():
|
|
150
|
+
if name not in _flag_map:
|
|
151
|
+
raise ValueError(f"Invalid flag: {name}")
|
|
152
|
+
if value:
|
|
153
|
+
self.flags |= _flag_map[name]
|
|
154
|
+
|
|
155
|
+
return self
|
|
156
|
+
|
|
157
|
+
def _set_reference(self,
|
|
158
|
+
message_id: int,
|
|
159
|
+
channel_id: int,
|
|
160
|
+
ref_type: Literal['Default', 'Forward'] = 'Default'
|
|
161
|
+
):
|
|
162
|
+
"""Internal helper for setting this message's reference message. Used in replies.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
message_id (int): message to reference
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
(MessageBuilder): self
|
|
169
|
+
"""
|
|
170
|
+
_ref_types = {
|
|
171
|
+
'DEFAULT': 0,
|
|
172
|
+
'FORWARD': 1
|
|
173
|
+
}
|
|
174
|
+
self.message_reference = _MessageReference(
|
|
175
|
+
type=_ref_types.get(ref_type.upper()),
|
|
176
|
+
channel_id=channel_id,
|
|
177
|
+
message_id=message_id
|
|
178
|
+
)
|
|
179
|
+
return self
|
discord/parts/modal.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from discord.model import DataModel
|
|
3
|
+
from .components_v2 import Label
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class ModalBuilder(DataModel):
|
|
7
|
+
title: str
|
|
8
|
+
custom_id: str = None
|
|
9
|
+
components: list[Label] = field(default_factory=list)
|
|
10
|
+
|
|
11
|
+
def add_label(self, component: Label):
|
|
12
|
+
"""Add a label component to this modal.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
component (Label): the label component
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
ModalBuilder: self
|
|
19
|
+
"""
|
|
20
|
+
self.components.append(component)
|
|
21
|
+
return self
|
discord/parts/role.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from discord.model import DataModel
|
|
4
|
+
|
|
5
|
+
from ..models.role import RoleColors
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Role(DataModel):
|
|
9
|
+
"""Parameters for creating/editing a role."""
|
|
10
|
+
|
|
11
|
+
colors: RoleColors
|
|
12
|
+
"""Colors of the role."""
|
|
13
|
+
|
|
14
|
+
name: str = None
|
|
15
|
+
"""Name of the role."""
|
|
16
|
+
|
|
17
|
+
permissions: int = 0
|
|
18
|
+
"""Permission bit set."""
|
|
19
|
+
|
|
20
|
+
hoist: bool = False
|
|
21
|
+
"""If the role is pinned in the user listing."""
|
|
22
|
+
|
|
23
|
+
mentionable: bool = False
|
|
24
|
+
"""If the role is mentionable."""
|
|
25
|
+
|
|
26
|
+
unicode_emoji: Optional[str] = None
|
|
27
|
+
"""Unicode emoji of the role."""
|
|
28
|
+
|
|
29
|
+
def set_color(self, hex: str):
|
|
30
|
+
"""Set this role's color with a hex. (format: #FFFFFF)
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
hex (str): color as a hex code
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
(Role): self
|
|
37
|
+
"""
|
|
38
|
+
self.color=int(hex.strip('#'), 16)
|
|
39
|
+
return self
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# discord/resources
|
|
2
|
+
|
|
3
|
+
from .guild import Guild
|
|
4
|
+
from .channel import Channel
|
|
5
|
+
from .message import Message
|
|
6
|
+
from .bot_emojis import BotEmojis
|
|
7
|
+
from .user import User
|
|
8
|
+
from .interaction import Interaction
|
|
9
|
+
from .application import Application
|
|
10
|
+
from .interaction import Interaction
|