Passed
Push — main ( eb4ae0...cb096b )
by
unknown
01:43
created

AppCommand.__post_init__()   A

Complexity

Conditions 3

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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