pincer.objects.app.command   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 243
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 10
eloc 97
dl 0
loc 243
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A AppCommandOptionChoice.__post_init__() 0 3 1
A AppCommand.__eq__() 0 19 2
A AppCommand.__post_init__() 0 5 3
A InteractableStructure.__call__() 0 2 1
A AppCommand.__hash__() 0 2 1
A AppCommand.add_option() 0 12 2
1
# Copyright Pincer 2021-Present
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
# Full MIT License can be found in `LICENSE` at the project root.
3
4
from __future__ import annotations
5
6
from dataclasses import dataclass, field
7
from typing import (
8
    Any,
9
    Awaitable,
10
    Callable,
11
    Generic,
12
    List,
13
    Optional,
14
    Union,
15
    TYPE_CHECKING,
16
    TypeVar,
17
)
18
19
from .command_types import AppCommandOptionType, AppCommandType
20
from ..app.throttle_scope import ThrottleScope
21
from ...commands.groups import Group, Subgroup
22
from ...objects.guild.channel import ChannelType
23
from ...utils.api_object import APIObject, GuildProperty
24
from ...utils.snowflake import Snowflake
25
from ...utils.types import Coro, choice_value_types
26
from ...utils.types import MISSING
27
28
if TYPE_CHECKING:
29
    from ...utils.types import APINullable
30
31
T = TypeVar("T")
32
33
34
@dataclass(repr=False)
35
class AppCommandInteractionDataOption(APIObject):
36
    """Represents a Discord Application Command Interaction Data Option
37
38
    Attributes
39
    ----------
40
    name: :class:`str`
41
        The name of the parameter
42
    value: :class:`str`
43
        The value of the pair
44
    type: APINullable[:class:`str`]
45
        Value of application command option type
46
    options: APINullable[List[:data:`~pincer.objects.app.command.AppCommandInteractionDataOption`]]
47
        Present if this option is a group or subcommand
48
    """
49
50
    # noqa: E501
51
    name: str
52
    value: APINullable[str] = MISSING
53
    type: APINullable[AppCommandOptionType] = MISSING
54
    options: APINullable[List[AppCommandInteractionDataOption]] = MISSING
55
56
57
@dataclass(repr=False)
58
class AppCommandOptionChoice(APIObject):
59
    """Represents a Discord Application Command Option Choice object
60
61
    Attributes
62
    ----------
63
    name: :class:`str`
64
        1-100 character choice name
65
    value: Union[:data:`~pincer.utils.types.choice_value_types`]
66
        Value of the choice, up to 100 characters if string
67
    """
68
69
    name: str
70
    value: choice_value_types
71
72
    def __post_init__(self):
73
        # APIObject __post_init_ causes issues by converting `value` to a string
74
        self.name = str(self.name)
75
76
77
@dataclass(repr=False)
78
class AppCommandOption(APIObject):
0 ignored issues
show
best-practice introduced by
Too many instance attributes (10/7)
Loading history...
79
    """Represents a Discord Application Command Option object
80
81
    Attributes
82
    ----------
83
    type: :class:`~pincer.objects.AppCommandOptionType`
84
        The type of option
85
    name: :class:`str`
86
        1-32 lowercase character name matching `^[\\w-]{1,32}$`
87
    description: :class:`str`
88
        1-100 character description
89
    required: APINullable[:class:`bool`]
90
        If the parameter is required or optional |default| :data:`False`
91
    choices: APINullable[List[:class:`~pincer.objects.app.command.AppCommandOptionChoice`]]
92
        Choices for ``STRING``, ``INTEGER``, and ``NUMBER``
93
        types for the user to pick from, max 25
94
    options: APINullable[List[:class:`~pincer.objects.app.command.AppCommandOptionChoice`]]
95
        If the option is a subcommand or subcommand group type,
96
        this nested options will be the parameters
97
    """
98
99
    # noqa: E501
100
    type: AppCommandOptionType
101
    name: str
102
    description: str
103
104
    required: bool = False
105
    autocomplete: APINullable[bool] = MISSING
106
    choices: APINullable[List[AppCommandOptionChoice]] = MISSING
107
    options: APINullable[List[AppCommandOption]] = MISSING
108
    channel_types: APINullable[List[ChannelType]] = MISSING
109
    min_value: APINullable[Union[int, float]] = MISSING
110
    max_value: APINullable[Union[int, float]] = MISSING
111
112
113
@dataclass(repr=False)
114
class AppCommand(APIObject, GuildProperty):
0 ignored issues
show
best-practice introduced by
Too many instance attributes (11/7)
Loading history...
115
    """Represents a Discord Application Command object
116
117
    Attributes
118
    ----------
119
    type: :class:`~pincer.objects.app.command.AppCommandType`
120
        The type of command, defaults ``1`` if not set
121
    name: :class:`str`
122
        1-32 character name
123
    description: :class:`str`
124
        1-100 character description for ``CHAT_INPUT`` commands,
125
        empty string for ``USER`` and ``MESSAGE`` commands
126
    id: APINullable[:class:`~pincer.utils.snowflake.Snowflake`]
127
        Unique id of the command
128
    version: APINullable[:class:`~pincer.utils.snowflake.Snowflake`]
129
        Auto-incrementing version identifier updated during substantial
130
        record changes
131
    application_id: APINullable[:class:`~pincer.utils.snowflake.Snowflake`]
132
        Unique id of the parent application
133
    options: APINullable[List[:class:`~pincer.objects.app.command.AppCommandOption`]]
134
        The parameters for the command, max 25
135
    guild_id: APINullable[:class:`~pincer.utils.snowflake.Snowflake`]
136
        Guild id of the command, if not global
137
    default_permission: APINullable[:class:`bool`]
138
        Whether the command is enabled by default
139
        when the app is added to a guild
140
    """
141
142
    # noqa: E501
143
    type: AppCommandType
144
    name: str
145
    description: str
146
147
    id: APINullable[Snowflake] = MISSING
148
    version: APINullable[Snowflake] = MISSING
149
    application_id: APINullable[Snowflake] = MISSING
150
    options: APINullable[List[AppCommandOption]] = MISSING
151
    guild_id: APINullable[Snowflake] = MISSING
152
    default_permission: APINullable[bool] = True
153
    default_member_permissions: APINullable[None] = None
154
    dm_permission: APINullable[None] = None
155
156
    def __post_init__(self):
157
        super().__post_init__()
158
159
        if self.options is MISSING and self.type is AppCommandType.MESSAGE:
160
            self.options = []
161
162
    def __eq__(self, other: Union[AppCommand, InteractableStructure]):
163
        if isinstance(other, InteractableStructure):
164
            other = other.app
165
166
        # `description` and `options` are tested for equality with a custom check
167
        eq_props = ("type", "name", "guild_id", "default_permission", "options")
168
169
        eq = (
170
            self.__getattribute__(prop) == other.__getattribute__(prop)
171
            for prop in eq_props
172
        )
173
174
        return all(
175
            (
176
                *eq,
177
                self.description == other.description
178
                # If this command has a MISSING description, Discord would return
179
                # registered the command with the description ''
180
                or self.description is MISSING and not other.description,
181
            )
182
        )
183
184
    def __hash__(self):
185
        return hash((self.id, self.name, self.guild_id, self.type))
186
187
    def add_option(self, option: AppCommandOption):
188
        """Add a new option field to the current application command.
189
190
        Parameters
191
        ----------
192
        option : :class:`~pincer.objects.app.command.AppCommandOption`
193
            The option which will be appended.
194
        """
195
        if self.options:
196
            self.options.append(option)
197
        else:
198
            self.options = [option]
199
200
201
@dataclass(repr=False)
202
class InteractableStructure(Generic[T]):
0 ignored issues
show
best-practice introduced by
Too many instance attributes (9/7)
Loading history...
203
    """Represents the structure of how the client saves the existing
204
    commands to registers. This is generic over Application Commands,
205
    Message Components, and Autocomplete.
206
207
    Attributes
208
    ----------
209
    call: :class:`~pincer.utils.types.Coro`
210
        The coroutine which should be called when the command gets
211
        executed.
212
    metadata: T
213
        The metadata for this command. |default| :data:`None`
214
    manager : Optional[Any]
215
        The manager for this interactable. |default| :data:`None`
216
    extensions: List[Callable[..., Awaitable[bool]]]
217
        List of extensions for this command. |default| :data:`[]`
218
    cooldown: :class:`int`
219
        Amount of times for cooldown |default| :data:`0`
220
    cooldown_scale: :class:`float`
221
        Search time for cooldown |default| :data:`60.0`
222
    cooldown_scope: :class:`~pincer.objects.app.throttle_scope.ThrottleScope`
223
        The type of cooldown |default| :data:`ThrottleScope.USER`
224
    """
225
226
    call: Coro
227
228
    metadata: Optional[T] = None
229
    manager: Optional[Any] = None
230
    extensions: List[Callable[..., Awaitable[bool]]] = field(
231
        default_factory=list
232
    )
233
234
    cooldown: int = 0
235
    cooldown_scale: float = 60.0
236
    cooldown_scope: ThrottleScope = ThrottleScope.USER
237
238
    group: APINullable[Group] = MISSING
239
    sub_group: APINullable[Subgroup] = MISSING
240
241
    def __call__(self, *args: Any, **kwargs: Any) -> Any:
242
        self.call(*args, **kwargs)
243