Passed
Pull Request — main (#389)
by
unknown
01:54
created

AppCommandOptionChoice.__post_init__()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
228