scurrypy 0.4.2__py3-none-any.whl → 0.5.3__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.

Files changed (65) hide show
  1. scurrypy/__init__.py +376 -0
  2. {discord → scurrypy}/client_like.py +1 -1
  3. {discord → scurrypy}/dispatch/command_dispatcher.py +13 -5
  4. {discord → scurrypy}/dispatch/event_dispatcher.py +15 -15
  5. {discord → scurrypy}/events/channel_events.py +1 -1
  6. {discord → scurrypy}/events/interaction_events.py +21 -9
  7. {discord → scurrypy}/events/message_events.py +4 -4
  8. {discord → scurrypy}/http.py +1 -1
  9. {discord → scurrypy}/intents.py +1 -1
  10. scurrypy/model.py +71 -0
  11. {discord → scurrypy}/models/emoji.py +17 -1
  12. {discord → scurrypy}/models/interaction.py +5 -0
  13. scurrypy/parts/channel.py +42 -0
  14. scurrypy/parts/command.py +90 -0
  15. scurrypy/parts/components.py +224 -0
  16. scurrypy/parts/components_v2.py +144 -0
  17. scurrypy/parts/embed.py +83 -0
  18. scurrypy/parts/message.py +137 -0
  19. scurrypy/parts/modal.py +16 -0
  20. {discord → scurrypy}/parts/role.py +1 -13
  21. {discord → scurrypy}/resources/channel.py +6 -6
  22. {discord → scurrypy}/resources/guild.py +3 -4
  23. {discord → scurrypy}/resources/interaction.py +23 -22
  24. {discord → scurrypy}/resources/message.py +13 -13
  25. {scurrypy-0.4.2.dist-info → scurrypy-0.5.3.dist-info}/METADATA +19 -25
  26. scurrypy-0.5.3.dist-info/RECORD +54 -0
  27. scurrypy-0.5.3.dist-info/top_level.txt +1 -0
  28. discord/__init__.py +0 -223
  29. discord/model.py +0 -90
  30. discord/parts/action_row.py +0 -208
  31. discord/parts/channel.py +0 -20
  32. discord/parts/command.py +0 -102
  33. discord/parts/components_v2.py +0 -353
  34. discord/parts/embed.py +0 -154
  35. discord/parts/message.py +0 -194
  36. discord/parts/modal.py +0 -21
  37. scurrypy-0.4.2.dist-info/RECORD +0 -54
  38. scurrypy-0.4.2.dist-info/top_level.txt +0 -1
  39. {discord → scurrypy}/client.py +0 -0
  40. {discord → scurrypy}/config.py +0 -0
  41. {discord → scurrypy}/dispatch/__init__.py +0 -0
  42. {discord → scurrypy}/dispatch/prefix_dispatcher.py +0 -0
  43. {discord → scurrypy}/error.py +0 -0
  44. {discord → scurrypy}/events/__init__.py +0 -0
  45. {discord → scurrypy}/events/guild_events.py +0 -0
  46. {discord → scurrypy}/events/hello_event.py +0 -0
  47. {discord → scurrypy}/events/reaction_events.py +0 -0
  48. {discord → scurrypy}/events/ready_event.py +0 -0
  49. {discord → scurrypy}/gateway.py +0 -0
  50. {discord → scurrypy}/logger.py +0 -0
  51. {discord → scurrypy}/models/__init__.py +0 -0
  52. {discord → scurrypy}/models/application.py +0 -0
  53. {discord → scurrypy}/models/guild.py +0 -0
  54. {discord → scurrypy}/models/integration.py +0 -0
  55. {discord → scurrypy}/models/member.py +0 -0
  56. {discord → scurrypy}/models/role.py +0 -0
  57. {discord → scurrypy}/models/user.py +0 -0
  58. {discord → scurrypy}/parts/__init__.py +0 -0
  59. {discord → scurrypy}/parts/component_types.py +0 -0
  60. {discord → scurrypy}/resources/__init__.py +0 -0
  61. {discord → scurrypy}/resources/application.py +0 -0
  62. {discord → scurrypy}/resources/bot_emojis.py +0 -0
  63. {discord → scurrypy}/resources/user.py +0 -0
  64. {scurrypy-0.4.2.dist-info → scurrypy-0.5.3.dist-info}/WHEEL +0 -0
  65. {scurrypy-0.4.2.dist-info → scurrypy-0.5.3.dist-info}/licenses/LICENSE +0 -0
scurrypy/model.py ADDED
@@ -0,0 +1,71 @@
1
+ from dataclasses import dataclass, fields, is_dataclass
2
+ from typing import get_args, get_origin, Union
3
+
4
+ from .http import HTTPClient
5
+
6
+ @dataclass
7
+ class DataModel:
8
+ """DataModel is a base class for Discord JSONs that provides hydration from raw dicts,
9
+ optional field defaults, and access to HTTP-bound methods.
10
+ """
11
+
12
+ @classmethod
13
+ def from_dict(cls, data: dict, http: 'HTTPClient' = None):
14
+ """Hydrates the given data into the dataclass child.
15
+
16
+ Args:
17
+ data (dict): JSON data
18
+ http (HTTPClient, optional): HTTP session for requests
19
+
20
+ Returns:
21
+ (dataclass): hydrated dataclass
22
+ """
23
+ def unwrap_optional(t):
24
+ if get_origin(t) is Union:
25
+ args = tuple(a for a in get_args(t) if a is not type(None))
26
+ return args[0] if len(args) == 1 else Union[args]
27
+ return t
28
+
29
+ kwargs = {}
30
+ for f in fields(cls):
31
+ v = data.get(f.name)
32
+ t = unwrap_optional(f.type)
33
+
34
+ if v is None:
35
+ kwargs[f.name] = None
36
+ elif is_dataclass(t):
37
+ kwargs[f.name] = t.from_dict(v, http)
38
+ elif get_origin(t) is list:
39
+ lt = get_args(t)[0]
40
+ kwargs[f.name] = [lt.from_dict(x, http) if is_dataclass(lt) else x for x in v]
41
+ else:
42
+ try:
43
+ kwargs[f.name] = t(v)
44
+ except Exception:
45
+ kwargs[f.name] = v # fallback to raw
46
+
47
+ inst = cls(**kwargs)
48
+ if http: inst._http = http
49
+ return inst
50
+
51
+ def to_dict(self):
52
+ """Recursively turns the dataclass into a dictionary and drops empty fields.
53
+
54
+ Returns:
55
+ (dict): serialized dataclasss
56
+ """
57
+ def serialize(val):
58
+ if isinstance(val, list):
59
+ return [serialize(v) for v in val if v is not None]
60
+ if isinstance(val, DataModel):
61
+ return val.to_dict()
62
+ return val
63
+
64
+ result = {}
65
+ for f in fields(self):
66
+ if f.name.startswith('_'):
67
+ continue
68
+ val = getattr(self, f.name)
69
+ # if val not in (None, [], {}, "", 0):
70
+ result[f.name] = serialize(val)
71
+ return result
@@ -13,7 +13,7 @@ class EmojiModel(DataModel):
13
13
  """ID of the emoji (if custom)."""
14
14
 
15
15
  animated: bool = False
16
- """If the emoji is animated. Defaults to `False`."""
16
+ """If the emoji is animated. Defaults to False."""
17
17
 
18
18
  @property
19
19
  def mention(self) -> str:
@@ -32,3 +32,19 @@ class EmojiModel(DataModel):
32
32
  return quote(f"a:{self.name}:{self.id}")
33
33
 
34
34
  return quote(f"{self.name}:{self.id}")
35
+
36
+ @property
37
+ def url(self) -> str:
38
+ """
39
+ Return the full qualifying link for this emoji.
40
+
41
+ !!! important
42
+ This only works for custom Discord emojis (those with an ID).
43
+ Unicode emojis will return `None`.
44
+ """
45
+ if not self.id:
46
+ return None
47
+
48
+ ext = 'gif' if self.animated else 'png'
49
+
50
+ return f"https://cdn.discordapp.com/emojis/{self.id}.{ext}"
@@ -3,6 +3,8 @@ from ..model import DataModel
3
3
 
4
4
  @dataclass
5
5
  class InteractionCallbackDataModel(DataModel):
6
+ """Represents the interaction callback object."""
7
+
6
8
  id: int
7
9
  """ID of the interaction."""
8
10
 
@@ -23,4 +25,7 @@ class InteractionCallbackDataModel(DataModel):
23
25
 
24
26
  @dataclass
25
27
  class InteractionCallbackModel(DataModel):
28
+ """Represents the interaction callback response object."""
29
+
26
30
  interaction: InteractionCallbackDataModel
31
+ """The interaction object associated with the interaction response."""
@@ -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.emoji 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]."""
@@ -0,0 +1,144 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Optional
3
+ from ..model import DataModel
4
+
5
+ from .component_types import *
6
+
7
+ class ComponentV2Types:
8
+ SECTION = 9
9
+ TEXT_DISPLAY = 10
10
+ THUMBNAIL = 11
11
+ MEDIA_GALLERY = 12
12
+ FILE = 13
13
+ SEPARATOR = 14
14
+ CONTAINER = 17
15
+ LABEL = 18
16
+
17
+ @dataclass
18
+ class SectionPart(DataModel, ContainerChild):
19
+ """Represents the Section component."""
20
+
21
+ accessory: Optional[SectionAccessory] = None
22
+ """A component that is contextually associated to the content of the section."""
23
+
24
+ components: list[SectionChild] = field(default_factory=list)
25
+ """Component(s) representing the content of the section that is contextually associated to the accessory."""
26
+
27
+ type: int = field(init=False, default=ComponentV2Types.SECTION)
28
+ """Component type. Always `ComponentV2Types.SECTION` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
29
+
30
+ @dataclass
31
+ class TextDisplay(DataModel, ContainerChild, SectionChild):
32
+ """Represents the Text Display component."""
33
+
34
+ content: str
35
+ """Text that will be displayed similar to a message."""
36
+
37
+ type: int = field(init=False, default=ComponentV2Types.TEXT_DISPLAY)
38
+ """Component type. Always `ComponentV2Types.TEXT_DISPLAY` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
39
+
40
+ @dataclass
41
+ class Thumbnail(DataModel, SectionAccessory):
42
+ """Represents the Thumbnail component."""
43
+
44
+ media: str
45
+ """Media of the thumbnail. http or attachment://<filename> scheme."""
46
+
47
+ description: Optional[str] = None
48
+ """Description for the media."""
49
+
50
+ spoiler: Optional[bool] = False
51
+ """Whether the thumbnail should be a spoiler (or blurred out)."""
52
+
53
+ type: int = field(init=False, default=ComponentV2Types.THUMBNAIL)
54
+ """Component type. Always `ComponentV2Types.THUMBNAIL` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
55
+
56
+ @dataclass
57
+ class MediaGalleryItem(DataModel):
58
+ """Represents the Media Gallery Item component."""
59
+
60
+ media: str
61
+ """Image data. http or attachment://<filename> scheme."""
62
+
63
+ description: Optional[str] = None
64
+ """Alt text for the media."""
65
+
66
+ spoiler: Optional[bool] = False
67
+ """Whether the thumbnail should be a spoiler (or blurred out)."""
68
+
69
+ @dataclass
70
+ class MediaGallery(DataModel, ContainerChild):
71
+ """Represents the Media Gallery component."""
72
+
73
+ items: list[MediaGalleryItem] = field(default_factory=list)
74
+ """1 to 10 nedia gallery items. See [`MediaGalleryItem`][scurrypy.parts.components_v2.MediaGalleryItem]."""
75
+
76
+ type: int = field(init=False, default=ComponentV2Types.MEDIA_GALLERY)
77
+ """Component type. Always `ComponentV2Types.MEDIA_GALLERY` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
78
+
79
+ @dataclass
80
+ class File(DataModel, ContainerChild):
81
+ """Represents the File component."""
82
+
83
+ file: str
84
+ """File name. ONLY supports attachment://<filename> scheme."""
85
+
86
+ spoiler: Optional[bool] = False
87
+ """Whether the thumbnail should be a spoiler (or blurred out)."""
88
+
89
+ type: int = field(init=False, default=ComponentV2Types.FILE)
90
+ """Component type. Always `ComponentV2Types.File` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
91
+
92
+ class SeparatorTypes:
93
+ """Represents separator types constants."""
94
+
95
+ SMALL_PADDING = 1
96
+ """Small separator padding."""
97
+
98
+ LARGE_PADDING = 2
99
+ """Large separator padding."""
100
+
101
+ @dataclass
102
+ class Separator(DataModel, ContainerChild):
103
+ """Represents the Separator component."""
104
+
105
+ divider: bool = True
106
+ """Whether a visual divider should be displayed in the component. Defaults to True."""
107
+
108
+ spacing: Optional[int] = SeparatorTypes.SMALL_PADDING
109
+ """Size of separator padding. Defaults to `SMALL_PADDING`. See [`SeparatorTypes`][scurrypy.parts.components_v2.SeparatorTypes]."""
110
+
111
+ type: int = field(init=False, default=ComponentV2Types.SEPARATOR)
112
+ """Component type. Always `ComponentV2Types.SEPARATOR` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
113
+
114
+ @dataclass
115
+ class ContainerPart(DataModel):
116
+ """Represents a container of display and interactable components."""
117
+
118
+ components: list[ContainerChild] = field(default_factory=list)
119
+ """Child components that are encapsulated within the Container."""
120
+
121
+ accent_color: Optional[int] = None
122
+ """Color for the accent as an integer."""
123
+
124
+ spoiler: Optional[bool] = False
125
+ """If the container should be blurred out. Defaults to False."""
126
+
127
+ type: int = field(init=False, default=ComponentV2Types.CONTAINER)
128
+ """Component type. Always `ComponentV2Types.CONTAINER` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""
129
+
130
+ @dataclass
131
+ class Label(DataModel):
132
+ """Represents the Discord Label component."""
133
+
134
+ label: str
135
+ """Label text."""
136
+
137
+ component: LabelChild = None
138
+ """A component within the label."""
139
+
140
+ description: Optional[str] = None
141
+ """An optional description text for the label."""
142
+
143
+ type: int = field(init=False, default=ComponentV2Types.LABEL)
144
+ """Component type. Always `ComponentV2Types.LABEL` for this class. See [`ComponentV2Types`][scurrypy.parts.components_v2.ComponentV2Types]."""