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.
- scurrypy/__init__.py +376 -0
- {discord → scurrypy}/client_like.py +1 -1
- {discord → scurrypy}/dispatch/command_dispatcher.py +13 -5
- {discord → scurrypy}/dispatch/event_dispatcher.py +15 -15
- {discord → scurrypy}/events/channel_events.py +1 -1
- {discord → scurrypy}/events/interaction_events.py +21 -9
- {discord → scurrypy}/events/message_events.py +4 -4
- {discord → scurrypy}/http.py +1 -1
- {discord → scurrypy}/intents.py +1 -1
- scurrypy/model.py +71 -0
- {discord → scurrypy}/models/emoji.py +17 -1
- {discord → scurrypy}/models/interaction.py +5 -0
- scurrypy/parts/channel.py +42 -0
- scurrypy/parts/command.py +90 -0
- scurrypy/parts/components.py +224 -0
- scurrypy/parts/components_v2.py +144 -0
- scurrypy/parts/embed.py +83 -0
- scurrypy/parts/message.py +137 -0
- scurrypy/parts/modal.py +16 -0
- {discord → scurrypy}/parts/role.py +1 -13
- {discord → scurrypy}/resources/channel.py +6 -6
- {discord → scurrypy}/resources/guild.py +3 -4
- {discord → scurrypy}/resources/interaction.py +23 -22
- {discord → scurrypy}/resources/message.py +13 -13
- {scurrypy-0.4.2.dist-info → scurrypy-0.5.3.dist-info}/METADATA +19 -25
- scurrypy-0.5.3.dist-info/RECORD +54 -0
- scurrypy-0.5.3.dist-info/top_level.txt +1 -0
- discord/__init__.py +0 -223
- discord/model.py +0 -90
- discord/parts/action_row.py +0 -208
- discord/parts/channel.py +0 -20
- discord/parts/command.py +0 -102
- discord/parts/components_v2.py +0 -353
- discord/parts/embed.py +0 -154
- discord/parts/message.py +0 -194
- discord/parts/modal.py +0 -21
- scurrypy-0.4.2.dist-info/RECORD +0 -54
- scurrypy-0.4.2.dist-info/top_level.txt +0 -1
- {discord → scurrypy}/client.py +0 -0
- {discord → scurrypy}/config.py +0 -0
- {discord → scurrypy}/dispatch/__init__.py +0 -0
- {discord → scurrypy}/dispatch/prefix_dispatcher.py +0 -0
- {discord → scurrypy}/error.py +0 -0
- {discord → scurrypy}/events/__init__.py +0 -0
- {discord → scurrypy}/events/guild_events.py +0 -0
- {discord → scurrypy}/events/hello_event.py +0 -0
- {discord → scurrypy}/events/reaction_events.py +0 -0
- {discord → scurrypy}/events/ready_event.py +0 -0
- {discord → scurrypy}/gateway.py +0 -0
- {discord → scurrypy}/logger.py +0 -0
- {discord → scurrypy}/models/__init__.py +0 -0
- {discord → scurrypy}/models/application.py +0 -0
- {discord → scurrypy}/models/guild.py +0 -0
- {discord → scurrypy}/models/integration.py +0 -0
- {discord → scurrypy}/models/member.py +0 -0
- {discord → scurrypy}/models/role.py +0 -0
- {discord → scurrypy}/models/user.py +0 -0
- {discord → scurrypy}/parts/__init__.py +0 -0
- {discord → scurrypy}/parts/component_types.py +0 -0
- {discord → scurrypy}/resources/__init__.py +0 -0
- {discord → scurrypy}/resources/application.py +0 -0
- {discord → scurrypy}/resources/bot_emojis.py +0 -0
- {discord → scurrypy}/resources/user.py +0 -0
- {scurrypy-0.4.2.dist-info → scurrypy-0.5.3.dist-info}/WHEEL +0 -0
- {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
|
|
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]."""
|