scurrypy 0.4__py3-none-any.whl → 0.6.6__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.
Files changed (72) hide show
  1. scurrypy/__init__.py +429 -0
  2. scurrypy/client.py +335 -0
  3. {discord → scurrypy}/client_like.py +8 -1
  4. scurrypy/dispatch/command_dispatcher.py +205 -0
  5. {discord → scurrypy}/dispatch/event_dispatcher.py +21 -21
  6. {discord → scurrypy}/dispatch/prefix_dispatcher.py +31 -12
  7. {discord → scurrypy}/error.py +6 -18
  8. {discord → scurrypy}/events/channel_events.py +2 -1
  9. scurrypy/events/gateway_events.py +31 -0
  10. {discord → scurrypy}/events/guild_events.py +2 -1
  11. {discord → scurrypy}/events/interaction_events.py +28 -13
  12. {discord → scurrypy}/events/message_events.py +8 -5
  13. {discord → scurrypy}/events/reaction_events.py +1 -2
  14. {discord → scurrypy}/events/ready_event.py +1 -3
  15. scurrypy/gateway.py +183 -0
  16. scurrypy/http.py +310 -0
  17. {discord → scurrypy}/intents.py +5 -7
  18. {discord → scurrypy}/logger.py +14 -61
  19. scurrypy/model.py +71 -0
  20. scurrypy/models.py +258 -0
  21. scurrypy/parts/channel.py +42 -0
  22. scurrypy/parts/command.py +90 -0
  23. scurrypy/parts/components.py +224 -0
  24. scurrypy/parts/components_v2.py +144 -0
  25. scurrypy/parts/embed.py +83 -0
  26. scurrypy/parts/message.py +134 -0
  27. scurrypy/parts/modal.py +16 -0
  28. {discord → scurrypy}/parts/role.py +2 -14
  29. {discord → scurrypy}/resources/application.py +1 -2
  30. {discord → scurrypy}/resources/bot_emojis.py +1 -1
  31. {discord → scurrypy}/resources/channel.py +9 -8
  32. {discord → scurrypy}/resources/guild.py +14 -16
  33. {discord → scurrypy}/resources/interaction.py +50 -43
  34. {discord → scurrypy}/resources/message.py +15 -16
  35. {discord → scurrypy}/resources/user.py +3 -4
  36. scurrypy-0.6.6.dist-info/METADATA +108 -0
  37. scurrypy-0.6.6.dist-info/RECORD +47 -0
  38. {scurrypy-0.4.dist-info → scurrypy-0.6.6.dist-info}/licenses/LICENSE +1 -1
  39. scurrypy-0.6.6.dist-info/top_level.txt +1 -0
  40. discord/__init__.py +0 -223
  41. discord/client.py +0 -375
  42. discord/dispatch/command_dispatcher.py +0 -163
  43. discord/gateway.py +0 -155
  44. discord/http.py +0 -280
  45. discord/model.py +0 -90
  46. discord/models/__init__.py +0 -1
  47. discord/models/application.py +0 -37
  48. discord/models/emoji.py +0 -34
  49. discord/models/guild.py +0 -35
  50. discord/models/integration.py +0 -23
  51. discord/models/interaction.py +0 -26
  52. discord/models/member.py +0 -27
  53. discord/models/role.py +0 -53
  54. discord/models/user.py +0 -15
  55. discord/parts/action_row.py +0 -208
  56. discord/parts/channel.py +0 -20
  57. discord/parts/command.py +0 -102
  58. discord/parts/components_v2.py +0 -353
  59. discord/parts/embed.py +0 -154
  60. discord/parts/message.py +0 -194
  61. discord/parts/modal.py +0 -21
  62. scurrypy-0.4.dist-info/METADATA +0 -130
  63. scurrypy-0.4.dist-info/RECORD +0 -54
  64. scurrypy-0.4.dist-info/top_level.txt +0 -1
  65. {discord → scurrypy}/config.py +0 -0
  66. {discord → scurrypy}/dispatch/__init__.py +0 -0
  67. {discord → scurrypy}/events/__init__.py +0 -0
  68. {discord → scurrypy}/events/hello_event.py +0 -0
  69. {discord → scurrypy}/parts/__init__.py +0 -0
  70. {discord → scurrypy}/parts/component_types.py +0 -0
  71. {discord → scurrypy}/resources/__init__.py +0 -0
  72. {scurrypy-0.4.dist-info → scurrypy-0.6.6.dist-info}/WHEEL +0 -0
scurrypy/models.py ADDED
@@ -0,0 +1,258 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+ from .model import DataModel
4
+
5
+ from urllib.parse import quote
6
+
7
+ @dataclass
8
+ class EmojiModel(DataModel):
9
+ """Represents a Discord emoji."""
10
+ name: str
11
+ """Name of emoji."""
12
+
13
+ id: int = 0
14
+ """ID of the emoji (if custom)."""
15
+
16
+ animated: bool = False
17
+ """If the emoji is animated. Defaults to False."""
18
+
19
+ @property
20
+ def mention(self) -> str:
21
+ """For use in message content."""
22
+ return f"<a:{self.name}:{self.id}>" if self.animated else f"<:{self.name}:{self.id}>"
23
+
24
+ @property
25
+ def api_code(self) -> str:
26
+ """Return the correct API code for this emoji (URL-safe)."""
27
+ if not self.id:
28
+ # unicode emoji
29
+ return quote(self.name)
30
+
31
+ # custom emoji
32
+ if self.animated:
33
+ return quote(f"a:{self.name}:{self.id}")
34
+
35
+ return quote(f"{self.name}:{self.id}")
36
+
37
+ @property
38
+ def url(self) -> str:
39
+ """
40
+ Return the full qualifying link for this emoji.
41
+
42
+ !!! warning "Important"
43
+ This only works for custom Discord emojis (those with an ID).
44
+ Unicode emojis will return `None`.
45
+ """
46
+ if not self.id:
47
+ return None
48
+
49
+ ext = 'gif' if self.animated else 'png'
50
+
51
+ return f"https://cdn.discordapp.com/emojis/{self.id}.{ext}"
52
+
53
+ # Guild Models
54
+
55
+ @dataclass
56
+ class ReadyGuildModel(DataModel):
57
+ """Guild info from Ready event."""
58
+ id: int
59
+ """ID of the associated guild."""
60
+
61
+ unavailable: bool
62
+ """If the guild is offline."""
63
+
64
+ @dataclass
65
+ class GuildModel(DataModel):
66
+ """Represents a Discord guild."""
67
+
68
+ id: int
69
+ """ID of the guild."""
70
+
71
+ name: str
72
+ """Name of the guild."""
73
+
74
+ icon: Optional[str] = None
75
+ """Icon hash of the guild."""
76
+
77
+ emojis: list[EmojiModel] = None
78
+ """List of emojis reigstered in the guild."""
79
+
80
+ approximate_member_count: Optional[int] = None
81
+ """Approximate member count."""
82
+
83
+ description: str = None
84
+ """Description of the guild."""
85
+
86
+ # User Models
87
+
88
+ @dataclass
89
+ class UserModel(DataModel):
90
+ """Describes the User object."""
91
+ id: int
92
+ """ID of the user."""
93
+
94
+ username: str
95
+ """Username of the user."""
96
+
97
+ avatar: str
98
+ """Avatar hash of the user."""
99
+
100
+ @dataclass
101
+ class ApplicationModel(DataModel):
102
+ """Represents a bot application object."""
103
+ id: int
104
+ """ID of the app."""
105
+
106
+ name: str
107
+ """Name of the app."""
108
+
109
+ icon: str
110
+ """Icon hash of the app."""
111
+
112
+ description: str
113
+ """Description of the app."""
114
+
115
+ bot_public: bool
116
+ """If other users can add this app to a guild."""
117
+
118
+ bot: UserModel
119
+ """Partial user obhect for the bot user associated with the app."""
120
+
121
+ owner: UserModel
122
+ """Partial user object for the owner of the app."""
123
+
124
+ guild_id: int
125
+ """Guild ID associated with the app (e.g., a support server)."""
126
+
127
+ guild: GuildModel
128
+ """Partial guild object of the associated guild."""
129
+
130
+ approximate_guild_count: int
131
+ """Approximate guild member count."""
132
+
133
+ @dataclass
134
+ class IntegrationModel(DataModel):
135
+ """Represents a guild integration."""
136
+
137
+ id: int
138
+ """ID of the integration."""
139
+
140
+ name: str
141
+ """Name of the integration."""
142
+
143
+ type: str
144
+ """Type of integration (e.g., twitch, youtube, discord, or guild_subscription)."""
145
+
146
+ enabled: bool
147
+ """If the integration is enabled."""
148
+
149
+ application: Optional[ApplicationModel] = None
150
+ """The bot aaplication for Discord integrations."""
151
+
152
+ @dataclass
153
+ class MemberModel(DataModel):
154
+ """Represents a guild member."""
155
+
156
+ roles: list[int]
157
+ """List of roles registered to the guild member."""
158
+
159
+ user: UserModel
160
+ """User data associated with the guild member."""
161
+
162
+ nick: str
163
+ """Server nickname of the guild member."""
164
+
165
+ avatar: str
166
+ """Server avatar hash of the guild mmeber."""
167
+
168
+ joined_at: str
169
+ """ISO8601 timestamp of when the guild member joined server."""
170
+
171
+ deaf: bool
172
+ """If the member is deaf in a VC (input)."""
173
+
174
+ mute: bool
175
+ """If the member is muted in VC (output)."""
176
+
177
+ # Interaction Models
178
+
179
+ @dataclass
180
+ class InteractionCallbackDataModel(DataModel):
181
+ """Represents the interaction callback object."""
182
+
183
+ id: int
184
+ """ID of the interaction."""
185
+
186
+ type: int
187
+ """Type of interaction."""
188
+
189
+ activity_instance_id: str
190
+ """Instance ID of activity if an activity was launched or joined."""
191
+
192
+ response_message_id: int
193
+ """ID of the message created by the interaction."""
194
+
195
+ response_message_loading: bool
196
+ """If the interaction is in a loading state."""
197
+
198
+ response_message_ephemeral: bool
199
+ """If the interaction is ephemeral."""
200
+
201
+ @dataclass
202
+ class InteractionCallbackModel(DataModel):
203
+ """Represents the interaction callback response object."""
204
+
205
+ interaction: InteractionCallbackDataModel
206
+ """The interaction object associated with the interaction response."""
207
+
208
+ # Role Models
209
+
210
+ @dataclass
211
+ class RoleColors(DataModel):
212
+ """Role color data."""
213
+
214
+ primary_color: int
215
+ """Primary color of the role."""
216
+
217
+ secondary_color: int
218
+ """Secondary color of the role. Creates a gradient."""
219
+
220
+ tertiary_color: int
221
+ """Tertiary color of the role. Creates a holographic style."""
222
+
223
+ @dataclass
224
+ class RoleModel(DataModel):
225
+ """Represents a Discord role."""
226
+
227
+ id: int
228
+ """ID of the role."""
229
+
230
+ name: str
231
+ """Name of the role."""
232
+
233
+ colors: RoleColors
234
+ """Colors of the role."""
235
+
236
+ hoist: bool
237
+ """If the role is pinned in user listing."""
238
+
239
+ position: int
240
+ """Position of the role."""
241
+
242
+ permissions: str
243
+ """Permission bit set."""
244
+
245
+ managed: bool
246
+ """If the role is managed by an integration."""
247
+
248
+ mentionable: bool
249
+ """If the role is mentionable."""
250
+
251
+ flags: int
252
+ """Role flags combined as a bitfield."""
253
+
254
+ icon: Optional[str] = None
255
+ """Icon hash of the role."""
256
+
257
+ unicode_emoji: Optional[str] = None
258
+ """Unicode emoji of the role."""
@@ -0,0 +1,42 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+ from ..model import DataModel
4
+
5
+ class ChannelTypes:
6
+ """
7
+ Constants for channel types.
8
+
9
+ !!! note
10
+ Only supported Channel Types listed here
11
+ """
12
+
13
+ GUILD_TEXT = 0
14
+ """Text channel within a server."""
15
+
16
+ GUILD_CATEGORY = 4
17
+ """Organizational category that contains up to 50 channels."""
18
+
19
+ GUILD_ANNOUNCEMENT = 5
20
+ """Channel that users can follow and crosspost into their own server (formerly news channels)."""
21
+
22
+ @dataclass
23
+ class GuildChannel(DataModel):
24
+ """Parameters for creating/editing a guild channel."""
25
+
26
+ name: Optional[str] = None
27
+ """Name of the channel."""
28
+
29
+ type: Optional[int] = None
30
+ """Type of channel. See [`ChannelTypes`][scurrypy.parts.channel.ChannelTypes]."""
31
+
32
+ topic: Optional[str] = None
33
+ """Topic of channel."""
34
+
35
+ position: Optional[int] = None
36
+ """Sorting position of the channel (channels with the same position are sorted by id)."""
37
+
38
+ parent_id: Optional[int] = None
39
+ """ID of the parent category for a channel."""
40
+
41
+ nsfw: Optional[bool] = None
42
+ """Whether the channel is NSFW."""
@@ -0,0 +1,90 @@
1
+ from dataclasses import dataclass, field
2
+
3
+ from ..model import DataModel
4
+
5
+ class CommandTypes:
6
+ CHAT_INPUT = 1
7
+ USER_COMMAND = 2
8
+ MESSAGE_COMMAND = 3
9
+
10
+ class CommandOptionTypes:
11
+ """Slash command option input types."""
12
+
13
+ STRING = 3
14
+ """string (text)"""
15
+
16
+ INTEGER = 4
17
+ """integer (whole)"""
18
+
19
+ BOOLEAN = 5
20
+ """boolean (true/false)"""
21
+
22
+ USER = 6
23
+ """user pangination"""
24
+
25
+ CHANNEL = 7
26
+ """channel pangination"""
27
+
28
+ ROLE = 8
29
+ """role pangination"""
30
+
31
+ MENTIONABLE = 9
32
+ """any pangination (role, channel, user)"""
33
+
34
+ NUMBER = 10
35
+ """number (float, integer)"""
36
+
37
+ ATTACHMENT = 11
38
+ """file upload"""
39
+
40
+ @dataclass
41
+ class CommandOption(DataModel):
42
+ """Option for a slash command."""
43
+
44
+ type: int
45
+ """Type of option. See [`CommandOptionTypes`][scurrypy.parts.command.CommandOptionTypes]."""
46
+
47
+ name: str
48
+ """Name of option."""
49
+
50
+ description: str
51
+ """Description of option."""
52
+
53
+ required: bool = False
54
+ """Whether this option is required. Defaults to False."""
55
+
56
+ @dataclass
57
+ class SlashCommand(DataModel):
58
+ """Represents the slash command object."""
59
+
60
+ name: str
61
+ """Name of the command."""
62
+
63
+ description: str
64
+ """Description of the command."""
65
+
66
+ options: list[CommandOption] = field(default_factory=list)
67
+ """Parameters or options for the command."""
68
+
69
+ type: int = field(init=False, default=CommandTypes.CHAT_INPUT)
70
+ """Command type. Always `CommandTypes.CHAT_INPUT` for this class. See [`CommandTypes`][scurrypy.parts.command.CommandTypes]."""
71
+
72
+ @dataclass
73
+ class UserCommand(DataModel):
74
+ """Represents the user command object"""
75
+
76
+ name: str
77
+ """Name of the command."""
78
+
79
+ type: int = field(init=False, default=CommandTypes.USER_COMMAND)
80
+ """Command type. Always `CommandTypes.USER_COMMAND` for this class. See [`CommandTypes`][scurrypy.parts.command.CommandTypes]."""
81
+
82
+ @dataclass
83
+ class MessageCommand(DataModel):
84
+ """Represents the message command object."""
85
+
86
+ name: str
87
+ """Name of the command."""
88
+
89
+ type: int = field(init=False, default=CommandTypes.MESSAGE_COMMAND)
90
+ """Command type. Always `CommandTypes.MESSAGE_COMMAND` for this class. See [`CommandTypes`][scurrypy.parts.command.CommandTypes]."""
@@ -0,0 +1,224 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Literal, Optional
3
+ from ..model import DataModel
4
+
5
+ from .component_types import *
6
+
7
+ from ..models import EmojiModel
8
+
9
+ class ComponentTypes:
10
+ ACTION_ROW = 1
11
+ BUTTON = 2
12
+ STRING_SELECT = 3
13
+ TEXT_INPUT = 4
14
+ USER_SELECT = 5
15
+ ROLE_SELECT = 6
16
+ MENTIONABLE_SELECT = 7
17
+ CHANNEL_SELECT = 8
18
+
19
+ @dataclass
20
+ class ActionRowPart(DataModel, ContainerChild):
21
+ """Represents a container of interactable components."""
22
+
23
+ components: list[ActionRowChild] = field(default_factory=list)
24
+ """Up to 5 interactive button components or a single select component."""
25
+
26
+ type: int = field(init=False, default=ComponentTypes.ACTION_ROW)
27
+ """Component type. Always `ComponentTypes.ACTION_ROW` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
28
+
29
+ class ButtonStyles:
30
+ """Represents button styles for a Button component."""
31
+
32
+ PRIMARY = 1
33
+ """The most important or recommended action in a group of options. (Blurple)"""
34
+
35
+ SECONDARY = 2
36
+ """Alternative or supporting actions. (Gray)"""
37
+
38
+ SUCCESS = 3
39
+ """Positive confirmation or completion actions. (Green)"""
40
+
41
+ DANGER = 4
42
+ """An action with irreversible consequences. (Red)"""
43
+
44
+ LINK = 5
45
+ """Navigates to a URL. (Gray + window)"""
46
+
47
+ @dataclass
48
+ class Button(DataModel, ActionRowChild, SectionAccessory):
49
+ """Represents the Button component."""
50
+
51
+ style: int
52
+ """A button style. See [`ButtonStyles`][scurrypy.parts.components.ButtonStyles]."""
53
+
54
+ custom_id: str
55
+ """ID for the button."""
56
+
57
+ label: Optional[str] = None
58
+ """Text that appears on the button."""
59
+
60
+ emoji: EmojiModel = None
61
+ """Partial emoji icon."""
62
+
63
+ url: Optional[str] = None
64
+ """URL for link-style buttons."""
65
+
66
+ disabled: Optional[bool] = False
67
+ """Whether the button is disabled. Defaults to False."""
68
+
69
+ type: int = field(init=False, default=ComponentTypes.BUTTON)
70
+ """Component type. Always `ComponentTypes.BUTTON` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
71
+
72
+ @dataclass
73
+ class SelectOption(DataModel):
74
+ """Represents the Select Option component"""
75
+
76
+ label: str
77
+ """User-facing name of the option."""
78
+
79
+ value: str
80
+ """Developer-defined value of the option."""
81
+
82
+ description: Optional[str] = None
83
+ """Additional description of the option."""
84
+
85
+ emoji: Optional[EmojiModel] = None
86
+ """Partial emoji obhect."""
87
+
88
+ default: Optional[bool] = False
89
+ """Whether this option is selected by default."""
90
+
91
+ @dataclass
92
+ class StringSelect(DataModel, ActionRowChild, LabelChild):
93
+ """Represents the String Select component."""
94
+
95
+ custom_id: str
96
+ """ID for the select menu."""
97
+
98
+ options: list[SelectOption] = field(default_factory=list)
99
+ """Specified choices in a select menu. See [`SelectOption`][scurrypy.parts.components.SelectOption]."""
100
+
101
+ placeholder: Optional[str] = None
102
+ """Placeholder text if nothing is selected or default."""
103
+
104
+ min_values: Optional[int] = 1
105
+ """Minimum number of items that must be chosen."""
106
+
107
+ max_values: Optional[int] = 1
108
+ """Maximum number of items that can be chosen."""
109
+
110
+ required: Optional[bool] = False
111
+ """Whether the string select is required to answer in a modal. Defaults to False."""
112
+
113
+ disabled: Optional[bool] = False # does not work on Modals!
114
+ """Whether select menu is disabled in a message. Defaults to False."""
115
+
116
+ type: int = field(init=False, default=ComponentTypes.STRING_SELECT)
117
+ """Component type. Always `ComponentTypes.STRING_SELECT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
118
+
119
+ class TextInputStyles:
120
+ """Represents the types of Text Inputs."""
121
+
122
+ SHORT = 1
123
+ """One line text input."""
124
+
125
+ PARAGRAPH = 2
126
+ """Multi-line text input."""
127
+
128
+ @dataclass
129
+ class TextInput(DataModel, LabelChild):
130
+ """Represents the Text Input component."""
131
+
132
+ style: TextInputStyles = TextInputStyles.SHORT
133
+ """Text input style. See [`TextInputStyles`][scurrypy.parts.components.TextInputStyles]."""
134
+
135
+ custom_id: str = None
136
+ """ID for the input."""
137
+
138
+ required: Optional[bool] = False
139
+ """Whether this component is required to be filled."""
140
+
141
+ min_length: Optional[int] = None
142
+ """Minimum input length for a text input."""
143
+
144
+ max_length: Optional[int] = None
145
+ """Maximum input length for a text input."""
146
+
147
+ required: Optional[bool] = True
148
+ """Whether this component is required to be filled. Defaults to True."""
149
+
150
+ value: Optional[str] = None
151
+ """Pre-filled value for this component."""
152
+
153
+ placeholder: Optional[str] = None
154
+ """Custom placeholder text if the input is empty."""
155
+
156
+ type: int = field(init=False, default=ComponentTypes.TEXT_INPUT)
157
+ """Component type. Always `ComponentTypes.TEXT_INPUT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
158
+
159
+ @dataclass
160
+ class DefaultValue(DataModel):
161
+ """Represents the Default Value for Select components."""
162
+
163
+ id: int
164
+ """ID of role, user, or channel."""
165
+
166
+ type: Literal["role", "user", "channel"]
167
+ """Type of value that `id` represents."""
168
+
169
+ @dataclass
170
+ class SelectMenu(DataModel):
171
+ """Represents common fields for Discord's select menus."""
172
+
173
+ custom_id: str
174
+ """ID for the select menu."""
175
+
176
+ placeholder: Optional[str] = None
177
+ """Placeholder text if nothing is selected."""
178
+
179
+ default_values: list[DefaultValue] = field(default_factory=list)
180
+ """
181
+ List of default values for auto-populated select menu components. See [`DefaultValue`][scurrypy.parts.components.DefaultValue].
182
+ Number of default values must be in the range of `min_values` to `max_values`.
183
+ """
184
+
185
+ min_values: Optional[int] = 1
186
+ """Minimum number of items that must be chosen. Defaults to 1."""
187
+
188
+ max_values: Optional[int] = 1
189
+ """Maximum number of items that can be chosen. Defaults to 1."""
190
+
191
+ required: Optional[bool] = False
192
+ """Whether the user select is required to answer in a modal. Defaults to False."""
193
+
194
+ disabled: Optional[bool] = False
195
+ """Whether select menu is disabled in a message. Defaults to False."""
196
+
197
+
198
+ @dataclass
199
+ class UserSelect(SelectMenu, ActionRowChild, LabelChild):
200
+ """Represents the User Select component."""
201
+
202
+ type: int = field(init=False, default=ComponentTypes.USER_SELECT)
203
+ """Component type. Always `ComponentTypes.USER_SELECT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
204
+
205
+ @dataclass
206
+ class RoleSelect(SelectMenu, ActionRowChild, LabelChild):
207
+ """Represents the Role Select component."""
208
+
209
+ type: int = field(init=False, default=ComponentTypes.ROLE_SELECT)
210
+ """Component type. Always `ComponentTypes.ROLE_SELECT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
211
+
212
+ @dataclass
213
+ class MentionableSelect(SelectMenu, ActionRowChild, LabelChild):
214
+ """Represents the Mentionable Select component."""
215
+
216
+ type: int = field(init=False, default=ComponentTypes.MENTIONABLE_SELECT)
217
+ """Component type. Always `ComponentTypes.MENTIONABLE_SELECT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""
218
+
219
+ @dataclass
220
+ class ChannelSelect(SelectMenu, ActionRowChild, LabelChild):
221
+ """Represents the Channel Select component."""
222
+
223
+ type: int = field(init=False, default=ComponentTypes.CHANNEL_SELECT)
224
+ """Component type. Always `ComponentTypes.CHANNEL_SELECT` for this class. See [`ComponentTypes`][scurrypy.parts.components.ComponentTypes]."""