Passed
Pull Request — main (#106)
by Yohann
01:30
created

pincer.objects.app.command.AppCommand.__eq__()   B

Complexity

Conditions 8

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 22
rs 7.3333
c 0
b 0
f 0
cc 8
nop 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
7
from enum import IntEnum
8
from typing import List, Union, TYPE_CHECKING
9
10
from ...utils.api_object import APIObject
11
from ...utils.conversion import convert
12
from ...utils.extraction import get_index
13
from ...utils.snowflake import Snowflake
14
from ...utils.types import MISSING
15
16
if TYPE_CHECKING:
17
    from ..app.throttle_scope import ThrottleScope
18
    from ...utils.types import APINullable, Coro, choice_value_types
19
20
21
class AppCommandType(IntEnum):
22
    """
23
    Defines the different types of application commands.
24
25
    :param CHAT_INPUT:
26
        Slash commands; a text-based command that shows up when a user
27
        types /
28
29
    :param USER:
30
        A UI-based command that shows up when you right click or tap on
31
        a user
32
33
    :param MESSAGE:
34
        A UI-based command that shows up when you right click or tap on
35
        a message
36
    """
37
    CHAT_INPUT = 1
38
    USER = 2
39
    MESSAGE = 3
40
41
42
class AppCommandOptionType(IntEnum):
43
    """
44
    Represents a parameter type.
45
46
    :param SUB_COMMAND:
47
        The parameter will be a subcommand.
48
49
    :param SUB_COMMAND_GROUP:
50
        The parameter will be a group of subcommands.
51
52
    :param STRING:
53
        The parameter will be a string.
54
55
    :param INTEGER:
56
        The parameter will be an integer/number. (-2^53 and 2^53)
57
58
    :param BOOLEAN:
59
        The parameter will be a boolean.
60
61
    :param USER:
62
        The parameter will be a Discord user object.
63
64
    :param CHANNEL:
65
        The parameter will be a Discord channel object.
66
67
    :param ROLE:
68
        The parameter will be a Discord role object.
69
70
    :param MENTIONABLE:
71
        The parameter will be mentionable.
72
73
    :param NUMBER:
74
        The parameter will be a float. (-2^53 and 2^53)
75
    """
76
    SUB_COMMAND = 1
77
    SUB_COMMAND_GROUP = 2
78
    STRING = 3
79
    INTEGER = 4  # 54-bit
80
    BOOLEAN = 5
81
    USER = 6
82
    CHANNEL = 7
83
    ROLE = 8
84
    MENTIONABLE = 9
85
    NUMBER = 10  # 54-bit
86
87
88
@dataclass
89
class AppCommandInteractionDataOption(APIObject):
90
    """
91
    Represents a Discord Application Command Interaction Data Option
92
93
    :param name:
94
        the name of the parameter
95
96
    :param type:
97
        value of application command option type
98
99
    :param value:
100
        the value of the pair
101
102
    :param options:
103
        present if this option is a group or subcommand
104
    """
105
    name: str
106
    value: APINullable[str] = MISSING
0 ignored issues
show
introduced by
The variable APINullable does not seem to be defined in case TYPE_CHECKING on line 16 is False. Are you sure this can never be the case?
Loading history...
107
    type: APINullable[AppCommandOptionType] = MISSING
108
    options: APINullable[
109
        List[AppCommandInteractionDataOption]] = MISSING
110
111
    def __post_init__(self):
112
        self.type = convert(self.type, AppCommandOptionType)
113
        self.options = convert(
114
            self.options,
115
            AppCommandInteractionDataOption.from_dict,
116
            AppCommandInteractionDataOption
117
        )
118
119
120
@dataclass
121
class AppCommandOptionChoice(APIObject):
122
    """
123
    Represents a Discord Application Command Option Choice object
124
125
    :param name:
126
        1-100 character choice name
127
128
    :param value:
129
        value of the choice, up to 100 characters if string
130
    """
131
    name: str
132
    value: Union[choice_value_types]
0 ignored issues
show
introduced by
The variable choice_value_types does not seem to be defined in case TYPE_CHECKING on line 16 is False. Are you sure this can never be the case?
Loading history...
133
134
135
@dataclass
136
class AppCommandOption(APIObject):
137
    """
138
    Represents a Discord Application Command Option object
139
140
    :param type:
141
        the type of option
142
143
    :param name:
144
        1-32 lowercase character name matching `^[\\w-]{1,32}$`
145
146
    :param description:
147
        1-100 character description
148
149
    :param required:
150
        if the parameter is required or optional--default `False`
151
152
    :param choices:
153
        choices for `STRING`, `INTEGER`, and `NUMBER`
154
        types for the user to pick from, max 25
155
156
    :param options:
157
        if the option is a subcommand or subcommand group type,
158
        this nested options will be the parameters
159
    """
160
    type: AppCommandOptionType
161
    name: str
162
    description: str
163
164
    required: APINullable[bool] = False
0 ignored issues
show
introduced by
The variable APINullable does not seem to be defined in case TYPE_CHECKING on line 16 is False. Are you sure this can never be the case?
Loading history...
165
    choices: APINullable[List[AppCommandOptionChoice]] = MISSING
166
    options: APINullable[List[AppCommandOption]] = MISSING
167
168
    def __post_init__(self):
169
        self.type = AppCommandOptionType(self.type)
170
        self.choices = convert(
171
            self.choices,
172
            AppCommandOptionChoice.from_dict,
173
            AppCommandOptionChoice
174
        )
175
        self.options = convert(
176
            self.options,
177
            AppCommandOption.from_dict,
178
            AppCommandOption
179
        )
180
181
182
@dataclass
0 ignored issues
show
best-practice introduced by
Too many instance attributes (10/7)
Loading history...
183
class AppCommand(APIObject):
184
    """
185
    Represents a Discord Application Command object
186
187
    :param id:
188
        unique id of the command
189
190
    :param type:
191
        the type of command, defaults `1` if not set
192
193
    :param application_id:
194
        unique id of the parent application
195
196
    :param guild_id:
197
        guild id of the command, if not global
198
199
    :param name:
200
        1-32 character name
201
202
    :param description:
203
        1-100 character description for `CHAT_INPUT` commands,
204
        empty string for `USER` and `MESSAGE` commands
205
206
    :param options:
207
        the parameters for the command, max 25
208
209
    :param default_permission:
210
        whether the command is enabled by default
211
        when the app is added to a guild
212
213
    :param version:
214
        autoincrementing version identifier updated during substantial
215
        record changes
216
    """
217
    type: AppCommandType
218
    name: str
219
    description: str
220
221
    id: APINullable[Snowflake] = MISSING
0 ignored issues
show
introduced by
The variable APINullable does not seem to be defined in case TYPE_CHECKING on line 16 is False. Are you sure this can never be the case?
Loading history...
222
    version: APINullable[Snowflake] = MISSING
223
    application_id: APINullable[Snowflake] = MISSING
224
    options: APINullable[List[AppCommandOption]] = MISSING
225
    guild_id: APINullable[Snowflake] = MISSING
226
    default_permission: APINullable[bool] = True
227
228
    _eq_props = [
229
        "type", "name", "description", "guild_id", "default_permission"
230
    ]
231
232
    def __post_init__(self):
233
        self.id = convert(self.id, Snowflake.from_string)
234
        self.version = convert(self.version, Snowflake.from_string)
235
        self.application_id = convert(
236
            self.application_id, Snowflake.from_string
237
        )
238
239
        self.options = convert(
240
            self.options,
241
            AppCommandOption.from_dict,
242
            AppCommandOption
243
        )
244
        self.guild_id = convert(self.guild_id, Snowflake.from_string)
245
246
        self.options = [] if self.options is MISSING else self.options
247
248
    def __eq__(self, other: Union[AppCommand, ClientCommandStructure]):
249
        if isinstance(other, ClientCommandStructure):
250
            other = other.app
251
252
        is_equal = all(
253
            self.__getattribute__(prop) == other.__getattribute__(prop)
254
            for prop in self._eq_props
255
        )
256
257
        if (
258
                (self.options is MISSING and other.options is not MISSING)
259
                or (self.options is not MISSING and other.options is MISSING)
260
                and not is_equal
261
        ):
262
            return False
263
264
        if len(other.options) != len(self.options):
265
            return False
266
267
        return not any(
268
            option != get_index(self.options, idx)
269
            for idx, option in enumerate(other.options)
270
        )
271
272
    def add_option(self, option: AppCommandOption):
273
        """
274
        Add a new option field to the current application command.
275
276
        :param option: The option which will be appended.
277
        """
278
        if self.options:
279
            self.options.append(option)
280
        else:
281
            self.options = [option]
282
283
284
@dataclass
285
class ClientCommandStructure:
286
    """
287
    Represents the structure of how the client saves the existing
288
    commands in the register.
289
290
    :param app:
291
        The command application.
292
293
    :param call:
294
        The coroutine which should be called when the command gets
295
        executed.
296
    """
297
    app: AppCommand
298
    call: Coro
0 ignored issues
show
introduced by
The variable Coro does not seem to be defined in case TYPE_CHECKING on line 16 is False. Are you sure this can never be the case?
Loading history...
299
    cooldown: int
300
    cooldown_scale: float
301
    cooldown_scope: ThrottleScope
0 ignored issues
show
introduced by
The variable ThrottleScope does not seem to be defined in case TYPE_CHECKING on line 16 is False. Are you sure this can never be the case?
Loading history...
302