Passed
Push — main ( dfd8dc...1ef013 )
by
unknown
01:38
created

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

Complexity

Conditions 9

Size

Total Lines 20
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 20
rs 6.6666
c 0
b 0
f 0
cc 9
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 typing import List, Union, TYPE_CHECKING
8
9
from .command_types import AppCommandOptionType, AppCommandType
10
from ...utils.api_object import APIObject
0 ignored issues
show
Bug introduced by
The name api_object does not seem to exist in module pincer.utils.
Loading history...
introduced by
Cannot import 'utils.api_object' due to syntax error 'invalid syntax (<unknown>, line 81)'
Loading history...
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
@dataclass
22
class AppCommandInteractionDataOption(APIObject):
23
    """
24
    Represents a Discord Application Command Interaction Data Option
25
26
    :param name:
27
        the name of the parameter
28
29
    :param type:
30
        value of application command option type
31
32
    :param value:
33
        the value of the pair
34
35
    :param options:
36
        present if this option is a group or subcommand
37
    """
38
    name: str
39
    value: APINullable[str] = MISSING
40
    type: APINullable[AppCommandOptionType] = MISSING
41
    options: APINullable[
42
        List[AppCommandInteractionDataOption]] = MISSING
43
44
45
@dataclass
46
class AppCommandOptionChoice(APIObject):
47
    """
48
    Represents a Discord Application Command Option Choice object
49
50
    :param name:
51
        1-100 character choice name
52
53
    :param value:
54
        value of the choice, up to 100 characters if string
55
    """
56
    name: str
57
    value: Union[choice_value_types]
58
59
60
@dataclass
61
class AppCommandOption(APIObject):
62
    """
63
    Represents a Discord Application Command Option object
64
65
    :param type:
66
        the type of option
67
68
    :param name:
69
        1-32 lowercase character name matching `^[\\w-]{1,32}$`
70
71
    :param description:
72
        1-100 character description
73
74
    :param required:
75
        if the parameter is required or optional--default `False`
76
77
    :param choices:
78
        choices for `STRING`, `INTEGER`, and `NUMBER`
79
        types for the user to pick from, max 25
80
81
    :param options:
82
        if the option is a subcommand or subcommand group type,
83
        this nested options will be the parameters
84
    """
85
    type: AppCommandOptionType
86
    name: str
87
    description: str
88
89
    required: APINullable[bool] = False
90
    choices: APINullable[List[AppCommandOptionChoice]] = MISSING
91
    options: APINullable[List[AppCommandOption]] = MISSING
92
93
    def __post_init__(self):
94
        self.type = AppCommandOptionType(self.type)
95
        self.choices = convert(
96
            self.choices,
97
            AppCommandOptionChoice.from_dict,
98
            AppCommandOptionChoice
99
        )
100
        self.options = convert(
101
            self.options,
102
            AppCommandOption.from_dict,
103
            AppCommandOption
104
        )
105
106
107
@dataclass
0 ignored issues
show
best-practice introduced by
Too many instance attributes (12/7)
Loading history...
108
class AppCommand(APIObject):
109
    """
110
    Represents a Discord Application Command object
111
112
    :param id:
113
        unique id of the command
114
115
    :param type:
116
        the type of command, defaults `1` if not set
117
118
    :param application_id:
119
        unique id of the parent application
120
121
    :param guild_id:
122
        guild id of the command, if not global
123
124
    :param name:
125
        1-32 character name
126
127
    :param description:
128
        1-100 character description for `CHAT_INPUT` commands,
129
        empty string for `USER` and `MESSAGE` commands
130
131
    :param options:
132
        the parameters for the command, max 25
133
134
    :param default_permission:
135
        whether the command is enabled by default
136
        when the app is added to a guild
137
138
    :param version:
139
        autoincrementing version identifier updated during substantial
140
        record changes
141
    :param default_member_permissions:
142
        # TODO: Fix docs for this when discord has implemented it.
143
    :param dm_permission:
144
        # TODO: Fix docs for this when discord has implemented it.
145
    """
146
    type: AppCommandType
147
    name: str
148
    description: str
149
150
    id: APINullable[Snowflake] = MISSING
151
    version: APINullable[Snowflake] = MISSING
152
    application_id: APINullable[Snowflake] = MISSING
153
    options: APINullable[List[AppCommandOption]] = MISSING
154
    guild_id: APINullable[Snowflake] = MISSING
155
    default_permission: APINullable[bool] = True
156
    default_member_permissions: APINullable[None] = None
157
    dm_permission: APINullable[None] = None
158
159
    _eq_props = [
160
        "type", "name", "description", "guild_id", "default_permission"
161
    ]
162
163
    def __post_init__(self):
164
        self.id = convert(self.id, Snowflake.from_string)
165
        self.version = convert(self.version, Snowflake.from_string)
166
        self.type = AppCommandType(self.type)
167
        self.application_id = convert(
168
            self.application_id, Snowflake.from_string
169
        )
170
171
        self.options = convert(
172
            self.options,
173
            AppCommandOption.from_dict,
174
            AppCommandOption
175
        )
176
        self.guild_id = convert(self.guild_id, Snowflake.from_string)
177
178
        self.options = [] if self.options is MISSING else self.options
179
180
    def __eq__(self, other: Union[AppCommand, ClientCommandStructure]):
181
        if isinstance(other, ClientCommandStructure):
182
            other = other.app
183
184
        is_equal = all(
185
            self.__getattribute__(prop) == other.__getattribute__(prop)
186
            for prop in self._eq_props
187
        )
188
189
        if (
0 ignored issues
show
best-practice introduced by
Too many boolean expressions in if statement (7/5)
Loading history...
190
                (self.options is MISSING and other.options is not MISSING)
191
                or (self.options is not MISSING and other.options is MISSING)
192
                and not is_equal
193
        ) or len(other.options) != len(self.options) \
194
                or self.guild_id != other.guild_id:
195
            return False
196
197
        return not any(
198
            option != get_index(self.options, idx)
199
            for idx, option in enumerate(other.options)
200
        )
201
202
    def __hash__(self):
203
        return hash((self.id, self.name, self.description, self.guild_id))
204
205
    def add_option(self, option: AppCommandOption):
206
        """
207
        Add a new option field to the current application command.
208
209
        :param option: The option which will be appended.
210
        """
211
        if self.options:
212
            self.options.append(option)
213
        else:
214
            self.options = [option]
215
216
217
@dataclass
218
class ClientCommandStructure:
219
    """
220
    Represents the structure of how the client saves the existing
221
    commands in the register.
222
223
    :param app:
224
        The command application.
225
226
    :param call:
227
        The coroutine which should be called when the command gets
228
        executed.
229
    """
230
    app: AppCommand
231
    call: Coro
232
    cooldown: int
233
    cooldown_scale: float
234
    cooldown_scope: ThrottleScope
235