hikari-arc 0.5.0__py3-none-any.whl → 0.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- arc/__init__.py +8 -2
- arc/abc/__init__.py +10 -1
- arc/abc/client.py +116 -30
- arc/abc/command.py +54 -10
- arc/abc/error_handler.py +10 -2
- arc/abc/limiter.py +5 -16
- arc/abc/option.py +71 -3
- arc/abc/plugin.py +92 -0
- arc/client.py +3 -3
- arc/command/message.py +4 -4
- arc/command/option/attachment.py +3 -3
- arc/command/option/bool.py +3 -4
- arc/command/option/channel.py +3 -3
- arc/command/option/float.py +4 -4
- arc/command/option/int.py +4 -4
- arc/command/option/mentionable.py +3 -3
- arc/command/option/role.py +3 -3
- arc/command/option/str.py +4 -4
- arc/command/option/user.py +3 -3
- arc/command/slash.py +116 -115
- arc/command/user.py +3 -3
- arc/context/base.py +114 -20
- arc/errors.py +31 -12
- arc/events.py +5 -1
- arc/internal/about.py +1 -1
- arc/internal/options.py +106 -0
- arc/internal/sigparse.py +19 -1
- arc/internal/sync.py +7 -2
- arc/internal/types.py +7 -12
- arc/plugin.py +2 -2
- arc/utils/__init__.py +4 -1
- arc/utils/hooks/__init__.py +2 -2
- arc/utils/hooks/limiters.py +70 -202
- arc/utils/ratelimiter.py +243 -0
- {hikari_arc-0.5.0.dist-info → hikari_arc-0.6.0.dist-info}/METADATA +11 -6
- hikari_arc-0.6.0.dist-info/RECORD +52 -0
- hikari_arc-0.5.0.dist-info/RECORD +0 -50
- {hikari_arc-0.5.0.dist-info → hikari_arc-0.6.0.dist-info}/LICENSE +0 -0
- {hikari_arc-0.5.0.dist-info → hikari_arc-0.6.0.dist-info}/WHEEL +0 -0
- {hikari_arc-0.5.0.dist-info → hikari_arc-0.6.0.dist-info}/top_level.txt +0 -0
arc/client.py
CHANGED
|
@@ -146,7 +146,7 @@ class GatewayClientBase(Client[GatewayBotT]):
|
|
|
146
146
|
The event type to subscribe to.
|
|
147
147
|
|
|
148
148
|
`EventT` must be a subclass of `hikari.events.base_events.Event`.
|
|
149
|
-
callback : t.Callable[
|
|
149
|
+
callback : t.Callable[EventT], t.Awaitable[None]]
|
|
150
150
|
The callback to call when the event is dispatched.
|
|
151
151
|
"""
|
|
152
152
|
self.app.event_manager.subscribe(event_type, callback) # pyright: ignore reportGeneralTypeIssues
|
|
@@ -158,7 +158,7 @@ class GatewayClientBase(Client[GatewayBotT]):
|
|
|
158
158
|
----------
|
|
159
159
|
event_type : type[EventT]
|
|
160
160
|
The event type to unsubscribe from.
|
|
161
|
-
callback : t.Callable[
|
|
161
|
+
callback : t.Callable[[EventT], t.Awaitable[None]]
|
|
162
162
|
The callback to unsubscribe.
|
|
163
163
|
"""
|
|
164
164
|
self.app.event_manager.unsubscribe(event_type, callback) # pyright: ignore reportGeneralTypeIssues
|
|
@@ -178,7 +178,7 @@ class GatewayClientBase(Client[GatewayBotT]):
|
|
|
178
178
|
|
|
179
179
|
Returns
|
|
180
180
|
-------
|
|
181
|
-
t.Callable[t.Callable[
|
|
181
|
+
t.Callable[t.Callable[[EventT], t.Awaitable[None]]], t.Callable[[EventT], t.Awaitable[None]]]
|
|
182
182
|
A decorator for a coroutine function that passes it to
|
|
183
183
|
`EventManager.subscribe` before returning the function
|
|
184
184
|
reference.
|
arc/command/message.py
CHANGED
|
@@ -8,12 +8,12 @@ import hikari
|
|
|
8
8
|
from arc.abc.command import CallableCommandBase
|
|
9
9
|
from arc.context import AutodeferMode, Context
|
|
10
10
|
from arc.errors import CommandInvokeError
|
|
11
|
-
from arc.internal.types import ClientT,
|
|
11
|
+
from arc.internal.types import ClientT, MessageCommandCallbackT, ResponseBuilderT
|
|
12
12
|
|
|
13
13
|
if t.TYPE_CHECKING:
|
|
14
14
|
import asyncio
|
|
15
15
|
|
|
16
|
-
from
|
|
16
|
+
from arc.abc import CallableCommandProto
|
|
17
17
|
|
|
18
18
|
__all__ = ("MessageCommand", "message_command")
|
|
19
19
|
|
|
@@ -69,7 +69,7 @@ def message_command(
|
|
|
69
69
|
autodefer: bool | AutodeferMode | hikari.UndefinedType = hikari.UNDEFINED,
|
|
70
70
|
default_permissions: hikari.Permissions | hikari.UndefinedType = hikari.UNDEFINED,
|
|
71
71
|
name_localizations: t.Mapping[hikari.Locale, str] | None = None,
|
|
72
|
-
) -> t.Callable[[
|
|
72
|
+
) -> t.Callable[[MessageCommandCallbackT[ClientT]], MessageCommand[ClientT]]:
|
|
73
73
|
"""A decorator that creates a context-menu command on a message.
|
|
74
74
|
|
|
75
75
|
Parameters
|
|
@@ -105,7 +105,7 @@ def message_command(
|
|
|
105
105
|
```
|
|
106
106
|
"""
|
|
107
107
|
|
|
108
|
-
def decorator(callback:
|
|
108
|
+
def decorator(callback: MessageCommandCallbackT[ClientT]) -> MessageCommand[ClientT]:
|
|
109
109
|
guild_ids = tuple(hikari.Snowflake(i) for i in guilds) if guilds is not hikari.UNDEFINED else hikari.UNDEFINED
|
|
110
110
|
|
|
111
111
|
return MessageCommand(
|
arc/command/option/attachment.py
CHANGED
|
@@ -5,7 +5,7 @@ import typing as t
|
|
|
5
5
|
import attr
|
|
6
6
|
import hikari
|
|
7
7
|
|
|
8
|
-
from arc.abc.option import CommandOptionBase, OptionParams
|
|
8
|
+
from arc.abc.option import CommandOptionBase, OptionParams, OptionType
|
|
9
9
|
from arc.internal.types import ClientT
|
|
10
10
|
|
|
11
11
|
if t.TYPE_CHECKING:
|
|
@@ -46,8 +46,8 @@ class AttachmentOption(CommandOptionBase[hikari.Attachment, ClientT, AttachmentP
|
|
|
46
46
|
"""
|
|
47
47
|
|
|
48
48
|
@property
|
|
49
|
-
def option_type(self) ->
|
|
50
|
-
return
|
|
49
|
+
def option_type(self) -> OptionType:
|
|
50
|
+
return OptionType.ATTACHMENT
|
|
51
51
|
|
|
52
52
|
@classmethod
|
|
53
53
|
def _from_params(cls, *, name: str, is_required: bool, params: AttachmentParams, **kwargs: t.Any) -> te.Self:
|
arc/command/option/bool.py
CHANGED
|
@@ -3,9 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import typing as t
|
|
4
4
|
|
|
5
5
|
import attr
|
|
6
|
-
import hikari
|
|
7
6
|
|
|
8
|
-
from arc.abc.option import CommandOptionBase, OptionParams
|
|
7
|
+
from arc.abc.option import CommandOptionBase, OptionParams, OptionType
|
|
9
8
|
from arc.internal.types import ClientT
|
|
10
9
|
|
|
11
10
|
if t.TYPE_CHECKING:
|
|
@@ -46,8 +45,8 @@ class BoolOption(CommandOptionBase[bool, ClientT, BoolParams]):
|
|
|
46
45
|
"""
|
|
47
46
|
|
|
48
47
|
@property
|
|
49
|
-
def option_type(self) ->
|
|
50
|
-
return
|
|
48
|
+
def option_type(self) -> OptionType:
|
|
49
|
+
return OptionType.BOOLEAN
|
|
51
50
|
|
|
52
51
|
@classmethod
|
|
53
52
|
def _from_params(cls, *, name: str, is_required: bool, params: BoolParams, **kwargs: t.Any) -> te.Self:
|
arc/command/option/channel.py
CHANGED
|
@@ -5,7 +5,7 @@ import typing as t
|
|
|
5
5
|
import attr
|
|
6
6
|
import hikari
|
|
7
7
|
|
|
8
|
-
from arc.abc.option import CommandOptionBase, OptionParams
|
|
8
|
+
from arc.abc.option import CommandOptionBase, OptionParams, OptionType
|
|
9
9
|
from arc.internal.types import ClientT
|
|
10
10
|
|
|
11
11
|
if t.TYPE_CHECKING:
|
|
@@ -57,8 +57,8 @@ class ChannelOption(CommandOptionBase[hikari.PartialChannel, ClientT, ChannelPar
|
|
|
57
57
|
"""The channel types that the option can be."""
|
|
58
58
|
|
|
59
59
|
@property
|
|
60
|
-
def option_type(self) ->
|
|
61
|
-
return
|
|
60
|
+
def option_type(self) -> OptionType:
|
|
61
|
+
return OptionType.CHANNEL
|
|
62
62
|
|
|
63
63
|
@classmethod
|
|
64
64
|
def _from_params(cls, *, name: str, is_required: bool, params: ChannelParams, **kwargs: t.Any) -> te.Self:
|
arc/command/option/float.py
CHANGED
|
@@ -3,12 +3,12 @@ from __future__ import annotations
|
|
|
3
3
|
import typing as t
|
|
4
4
|
|
|
5
5
|
import attr
|
|
6
|
-
import hikari
|
|
7
6
|
|
|
8
|
-
from arc.abc.option import OptionWithChoices, OptionWithChoicesParams
|
|
7
|
+
from arc.abc.option import OptionType, OptionWithChoices, OptionWithChoicesParams
|
|
9
8
|
from arc.internal.types import ClientT
|
|
10
9
|
|
|
11
10
|
if t.TYPE_CHECKING:
|
|
11
|
+
import hikari
|
|
12
12
|
import typing_extensions as te
|
|
13
13
|
|
|
14
14
|
from ...internal.types import AutocompleteCallbackT
|
|
@@ -97,8 +97,8 @@ class FloatOption(OptionWithChoices[float, ClientT, FloatParams[ClientT]]):
|
|
|
97
97
|
"""The maximum value of the option."""
|
|
98
98
|
|
|
99
99
|
@property
|
|
100
|
-
def option_type(self) ->
|
|
101
|
-
return
|
|
100
|
+
def option_type(self) -> OptionType:
|
|
101
|
+
return OptionType.FLOAT
|
|
102
102
|
|
|
103
103
|
@classmethod
|
|
104
104
|
def _from_params(cls, *, name: str, is_required: bool, params: FloatParams[ClientT], **kwargs: t.Any) -> te.Self:
|
arc/command/option/int.py
CHANGED
|
@@ -3,12 +3,12 @@ from __future__ import annotations
|
|
|
3
3
|
import typing as t
|
|
4
4
|
|
|
5
5
|
import attr
|
|
6
|
-
import hikari
|
|
7
6
|
|
|
8
|
-
from arc.abc.option import OptionWithChoices, OptionWithChoicesParams
|
|
7
|
+
from arc.abc.option import OptionType, OptionWithChoices, OptionWithChoicesParams
|
|
9
8
|
from arc.internal.types import ClientT
|
|
10
9
|
|
|
11
10
|
if t.TYPE_CHECKING:
|
|
11
|
+
import hikari
|
|
12
12
|
import typing_extensions as te
|
|
13
13
|
|
|
14
14
|
from ...internal.types import AutocompleteCallbackT
|
|
@@ -97,8 +97,8 @@ class IntOption(OptionWithChoices[int, ClientT, IntParams[ClientT]]):
|
|
|
97
97
|
"""The maximum value of the option."""
|
|
98
98
|
|
|
99
99
|
@property
|
|
100
|
-
def option_type(self) ->
|
|
101
|
-
return
|
|
100
|
+
def option_type(self) -> OptionType:
|
|
101
|
+
return OptionType.INTEGER
|
|
102
102
|
|
|
103
103
|
@classmethod
|
|
104
104
|
def _from_params(cls, *, name: str, is_required: bool, params: IntParams[ClientT], **kwargs: t.Any) -> te.Self:
|
|
@@ -5,7 +5,7 @@ import typing as t
|
|
|
5
5
|
import attr
|
|
6
6
|
import hikari
|
|
7
7
|
|
|
8
|
-
from arc.abc.option import CommandOptionBase, OptionParams
|
|
8
|
+
from arc.abc.option import CommandOptionBase, OptionParams, OptionType
|
|
9
9
|
from arc.internal.types import ClientT
|
|
10
10
|
|
|
11
11
|
if t.TYPE_CHECKING:
|
|
@@ -47,8 +47,8 @@ class MentionableOption(CommandOptionBase[hikari.Role | hikari.User, ClientT, Me
|
|
|
47
47
|
"""
|
|
48
48
|
|
|
49
49
|
@property
|
|
50
|
-
def option_type(self) ->
|
|
51
|
-
return
|
|
50
|
+
def option_type(self) -> OptionType:
|
|
51
|
+
return OptionType.MENTIONABLE
|
|
52
52
|
|
|
53
53
|
@classmethod
|
|
54
54
|
def _from_params(cls, *, name: str, is_required: bool, params: MentionableParams, **kwargs: t.Any) -> te.Self:
|
arc/command/option/role.py
CHANGED
|
@@ -5,7 +5,7 @@ import typing as t
|
|
|
5
5
|
import attr
|
|
6
6
|
import hikari
|
|
7
7
|
|
|
8
|
-
from arc.abc.option import CommandOptionBase, OptionParams
|
|
8
|
+
from arc.abc.option import CommandOptionBase, OptionParams, OptionType
|
|
9
9
|
from arc.internal.types import ClientT
|
|
10
10
|
|
|
11
11
|
if t.TYPE_CHECKING:
|
|
@@ -46,8 +46,8 @@ class RoleOption(CommandOptionBase[hikari.Role, ClientT, RoleParams]):
|
|
|
46
46
|
"""
|
|
47
47
|
|
|
48
48
|
@property
|
|
49
|
-
def option_type(self) ->
|
|
50
|
-
return
|
|
49
|
+
def option_type(self) -> OptionType:
|
|
50
|
+
return OptionType.ROLE
|
|
51
51
|
|
|
52
52
|
@classmethod
|
|
53
53
|
def _from_params(cls, *, name: str, is_required: bool, params: RoleParams, **kwargs: t.Any) -> te.Self:
|
arc/command/option/str.py
CHANGED
|
@@ -3,12 +3,12 @@ from __future__ import annotations
|
|
|
3
3
|
import typing as t
|
|
4
4
|
|
|
5
5
|
import attr
|
|
6
|
-
import hikari
|
|
7
6
|
|
|
8
|
-
from arc.abc.option import OptionWithChoices, OptionWithChoicesParams
|
|
7
|
+
from arc.abc.option import OptionType, OptionWithChoices, OptionWithChoicesParams
|
|
9
8
|
from arc.internal.types import ClientT
|
|
10
9
|
|
|
11
10
|
if t.TYPE_CHECKING:
|
|
11
|
+
import hikari
|
|
12
12
|
import typing_extensions as te
|
|
13
13
|
|
|
14
14
|
from arc.internal.types import AutocompleteCallbackT
|
|
@@ -98,8 +98,8 @@ class StrOption(OptionWithChoices[str, ClientT, StrParams[ClientT]]):
|
|
|
98
98
|
"""The maximum length of the option."""
|
|
99
99
|
|
|
100
100
|
@property
|
|
101
|
-
def option_type(self) ->
|
|
102
|
-
return
|
|
101
|
+
def option_type(self) -> OptionType:
|
|
102
|
+
return OptionType.STRING
|
|
103
103
|
|
|
104
104
|
@classmethod
|
|
105
105
|
def _from_params(cls, *, name: str, is_required: bool, params: StrParams[ClientT], **kwargs: t.Any) -> te.Self:
|
arc/command/option/user.py
CHANGED
|
@@ -5,7 +5,7 @@ import typing as t
|
|
|
5
5
|
import attr
|
|
6
6
|
import hikari
|
|
7
7
|
|
|
8
|
-
from arc.abc.option import CommandOptionBase, OptionParams
|
|
8
|
+
from arc.abc.option import CommandOptionBase, OptionParams, OptionType
|
|
9
9
|
from arc.internal.types import ClientT
|
|
10
10
|
|
|
11
11
|
if t.TYPE_CHECKING:
|
|
@@ -47,8 +47,8 @@ class UserOption(CommandOptionBase[hikari.User, ClientT, UserParams]):
|
|
|
47
47
|
"""
|
|
48
48
|
|
|
49
49
|
@property
|
|
50
|
-
def option_type(self) ->
|
|
51
|
-
return
|
|
50
|
+
def option_type(self) -> OptionType:
|
|
51
|
+
return OptionType.USER
|
|
52
52
|
|
|
53
53
|
@classmethod
|
|
54
54
|
def _from_params(cls, *, name: str, is_required: bool, params: UserParams, **kwargs: t.Any) -> te.Self:
|
arc/command/slash.py
CHANGED
|
@@ -7,9 +7,10 @@ import attr
|
|
|
7
7
|
import hikari
|
|
8
8
|
|
|
9
9
|
from arc.abc.command import CallableCommandBase, CallableCommandProto, CommandBase, SubCommandBase, _CommandSettings
|
|
10
|
-
from arc.abc.option import OptionWithChoices
|
|
10
|
+
from arc.abc.option import OptionType, OptionWithChoices
|
|
11
11
|
from arc.context import AutocompleteData, AutodeferMode, Context
|
|
12
12
|
from arc.errors import AutocompleteError, CommandInvokeError
|
|
13
|
+
from arc.internal.options import resolve_options
|
|
13
14
|
from arc.internal.sigparse import parse_command_signature
|
|
14
15
|
from arc.internal.types import ClientT, CommandCallbackT, HookT, PostHookT, ResponseBuilderT, SlashCommandLike
|
|
15
16
|
from arc.locale import CommandLocaleRequest, LocaleResponse
|
|
@@ -33,64 +34,6 @@ __all__ = (
|
|
|
33
34
|
)
|
|
34
35
|
|
|
35
36
|
|
|
36
|
-
def _resolve_options(
|
|
37
|
-
local_options: t.MutableMapping[str, CommandOptionBase[ClientT, t.Any, t.Any]],
|
|
38
|
-
incoming_options: t.Sequence[hikari.CommandInteractionOption],
|
|
39
|
-
resolved: hikari.ResolvedOptionData | None,
|
|
40
|
-
) -> dict[str, t.Any]:
|
|
41
|
-
"""Resolve the options into kwargs for the callback.
|
|
42
|
-
|
|
43
|
-
Parameters
|
|
44
|
-
----------
|
|
45
|
-
local_options : t.MutableMapping[str, Option[t.Any, t.Any]]
|
|
46
|
-
The options of the locally stored command.
|
|
47
|
-
incoming_options : t.Sequence[hikari.CommandInteractionOption]
|
|
48
|
-
The options of the interaction.
|
|
49
|
-
resolved : hikari.ResolvedOptionData
|
|
50
|
-
The resolved option data of the interaction.
|
|
51
|
-
|
|
52
|
-
Returns
|
|
53
|
-
-------
|
|
54
|
-
dict[str, Any]
|
|
55
|
-
The resolved options as kwargs, ready to be passed to the callback.
|
|
56
|
-
"""
|
|
57
|
-
option_kwargs: dict[str, t.Any] = {}
|
|
58
|
-
|
|
59
|
-
for arg_name, opt in local_options.items():
|
|
60
|
-
inter_opt = next((o for o in incoming_options if o.name == opt.name), None)
|
|
61
|
-
|
|
62
|
-
if inter_opt is None:
|
|
63
|
-
continue
|
|
64
|
-
|
|
65
|
-
if isinstance(inter_opt.value, hikari.Snowflake) and resolved:
|
|
66
|
-
match inter_opt.type:
|
|
67
|
-
case hikari.OptionType.USER:
|
|
68
|
-
value = resolved.members.get(inter_opt.value) or resolved.users[inter_opt.value]
|
|
69
|
-
case hikari.OptionType.ATTACHMENT:
|
|
70
|
-
value = resolved.attachments[inter_opt.value]
|
|
71
|
-
case hikari.OptionType.CHANNEL:
|
|
72
|
-
value = resolved.channels[inter_opt.value]
|
|
73
|
-
case hikari.OptionType.ROLE:
|
|
74
|
-
value = resolved.roles[inter_opt.value]
|
|
75
|
-
case hikari.OptionType.MENTIONABLE:
|
|
76
|
-
value = (
|
|
77
|
-
resolved.members.get(inter_opt.value)
|
|
78
|
-
or resolved.users.get(inter_opt.value)
|
|
79
|
-
or resolved.roles[inter_opt.value]
|
|
80
|
-
)
|
|
81
|
-
case _:
|
|
82
|
-
raise ValueError(f"Unexpected option type '{inter_opt.type}.'")
|
|
83
|
-
|
|
84
|
-
option_kwargs[arg_name] = value
|
|
85
|
-
|
|
86
|
-
elif isinstance(inter_opt.value, hikari.Snowflake):
|
|
87
|
-
raise ValueError(f"Missing resolved option data for '{inter_opt.name}'.")
|
|
88
|
-
else:
|
|
89
|
-
option_kwargs[arg_name] = inter_opt.value
|
|
90
|
-
|
|
91
|
-
return option_kwargs
|
|
92
|
-
|
|
93
|
-
|
|
94
37
|
def _choices_to_builders(
|
|
95
38
|
choices: t.Sequence[hikari.api.AutocompleteChoiceBuilder] | t.Sequence[t.Any],
|
|
96
39
|
) -> t.Sequence[hikari.api.AutocompleteChoiceBuilder]:
|
|
@@ -126,6 +69,11 @@ class SlashCommand(CallableCommandBase[ClientT, hikari.api.SlashCommandBuilder])
|
|
|
126
69
|
def qualified_name(self) -> t.Sequence[str]:
|
|
127
70
|
return (self.name,)
|
|
128
71
|
|
|
72
|
+
@property
|
|
73
|
+
def display_name(self) -> str:
|
|
74
|
+
"""The display name of this command."""
|
|
75
|
+
return f"/{self.name}"
|
|
76
|
+
|
|
129
77
|
def _get_context(
|
|
130
78
|
self, interaction: hikari.CommandInteraction, command: CallableCommandProto[ClientT]
|
|
131
79
|
) -> Context[ClientT]:
|
|
@@ -134,7 +82,9 @@ class SlashCommand(CallableCommandBase[ClientT, hikari.api.SlashCommandBuilder])
|
|
|
134
82
|
if interaction.command_type is not hikari.CommandType.SLASH:
|
|
135
83
|
raise ValueError(f"Expected slash command, got {interaction.command_type}")
|
|
136
84
|
|
|
137
|
-
|
|
85
|
+
ctx = Context(self.client, command, interaction)
|
|
86
|
+
ctx._options = interaction.options
|
|
87
|
+
return ctx
|
|
138
88
|
|
|
139
89
|
def _to_dict(self) -> dict[str, t.Any]:
|
|
140
90
|
sorted_options = sorted(self.options.values(), key=lambda option: option.is_required, reverse=True)
|
|
@@ -164,11 +114,36 @@ class SlashCommand(CallableCommandBase[ClientT, hikari.api.SlashCommandBuilder])
|
|
|
164
114
|
return await super().invoke(
|
|
165
115
|
interaction,
|
|
166
116
|
*args,
|
|
167
|
-
**{**kwargs, **
|
|
117
|
+
**{**kwargs, **resolve_options(self.options, interaction.options, interaction.resolved)},
|
|
168
118
|
)
|
|
169
119
|
else:
|
|
170
120
|
return await super().invoke(interaction, *args, **kwargs)
|
|
171
121
|
|
|
122
|
+
def make_mention(self, *, guild: hikari.Snowflakeish | hikari.PartialGuild | None = None) -> str:
|
|
123
|
+
"""Make a slash mention for this command.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
guild : hikari.SnowflakeishOr[hikari.PartialGuild] | None
|
|
128
|
+
The guild the command is registered in. If None, the global command's ID is used.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
str
|
|
133
|
+
The slash command mention.
|
|
134
|
+
|
|
135
|
+
Raises
|
|
136
|
+
------
|
|
137
|
+
KeyError
|
|
138
|
+
If the command has not been published in the given guild or globally.
|
|
139
|
+
"""
|
|
140
|
+
instance = self._instances.get(hikari.Snowflake(guild) if guild else None)
|
|
141
|
+
|
|
142
|
+
if instance is None:
|
|
143
|
+
raise KeyError(f"Command '{self.display_name}' has not been published in the given scope.")
|
|
144
|
+
|
|
145
|
+
return f"</{self.name}:{instance.id}>"
|
|
146
|
+
|
|
172
147
|
async def _on_autocomplete(
|
|
173
148
|
self, interaction: hikari.AutocompleteInteraction
|
|
174
149
|
) -> hikari.api.InteractionAutocompleteBuilder | None:
|
|
@@ -249,6 +224,11 @@ class SlashGroup(CommandBase[ClientT, hikari.api.SlashCommandBuilder]):
|
|
|
249
224
|
def qualified_name(self) -> t.Sequence[str]:
|
|
250
225
|
return (self.name,)
|
|
251
226
|
|
|
227
|
+
@property
|
|
228
|
+
def display_name(self) -> str:
|
|
229
|
+
"""The display name of this command."""
|
|
230
|
+
return f"/{self.name}"
|
|
231
|
+
|
|
252
232
|
def _to_dict(self) -> dict[str, t.Any]:
|
|
253
233
|
return {
|
|
254
234
|
**super()._to_dict(),
|
|
@@ -283,11 +263,13 @@ class SlashGroup(CommandBase[ClientT, hikari.api.SlashCommandBuilder]):
|
|
|
283
263
|
self,
|
|
284
264
|
subcommand: SlashSubCommand[ClientT],
|
|
285
265
|
interaction: hikari.CommandInteraction,
|
|
266
|
+
options: t.Sequence[hikari.CommandInteractionOption] | None = None,
|
|
286
267
|
*args: t.Any,
|
|
287
268
|
**kwargs: t.Any,
|
|
288
269
|
) -> asyncio.Future[ResponseBuilderT] | None:
|
|
289
270
|
"""Invoke a subcommand."""
|
|
290
271
|
ctx = self._get_context(interaction, subcommand)
|
|
272
|
+
ctx._options = options
|
|
291
273
|
|
|
292
274
|
if (autodefer := subcommand.autodefer) and autodefer.should_autodefer:
|
|
293
275
|
ctx._start_autodefer(autodefer)
|
|
@@ -314,12 +296,12 @@ class SlashGroup(CommandBase[ClientT, hikari.api.SlashCommandBuilder]):
|
|
|
314
296
|
if sub.options is None:
|
|
315
297
|
if not isinstance(subcmd, SlashSubCommand):
|
|
316
298
|
raise CommandInvokeError(f"Slash group got subgroup without options: '{subcmd.name}'.")
|
|
317
|
-
return await self._invoke_subcmd(subcmd, interaction, *args, **kwargs)
|
|
299
|
+
return await self._invoke_subcmd(subcmd, interaction, None, *args, **kwargs)
|
|
318
300
|
|
|
319
301
|
# Resolve options and invoke if it does
|
|
320
302
|
if isinstance(subcmd, SlashSubCommand):
|
|
321
|
-
res =
|
|
322
|
-
return await self._invoke_subcmd(subcmd, interaction, *args, **{**kwargs, **res})
|
|
303
|
+
res = resolve_options(subcmd.options, sub.options, interaction.resolved)
|
|
304
|
+
return await self._invoke_subcmd(subcmd, interaction, sub.options, *args, **{**kwargs, **res})
|
|
323
305
|
|
|
324
306
|
# Get second-order subcommand
|
|
325
307
|
subsub = next((o for o in sub.options if o.name in subcmd.children), None)
|
|
@@ -331,11 +313,11 @@ class SlashGroup(CommandBase[ClientT, hikari.api.SlashCommandBuilder]):
|
|
|
331
313
|
|
|
332
314
|
# Invoke it if it has no options
|
|
333
315
|
if subsub.options is None:
|
|
334
|
-
return await self._invoke_subcmd(subsubcmd, interaction, *args, **kwargs)
|
|
316
|
+
return await self._invoke_subcmd(subsubcmd, interaction, None, *args, **kwargs)
|
|
335
317
|
|
|
336
318
|
# Resolve options and invoke if it does
|
|
337
|
-
res =
|
|
338
|
-
return await self._invoke_subcmd(subsubcmd, interaction, *args, **{**kwargs, **res})
|
|
319
|
+
res = resolve_options(subsubcmd.options, subsub.options, interaction.resolved)
|
|
320
|
+
return await self._invoke_subcmd(subsubcmd, interaction, subsub.options, *args, **{**kwargs, **res})
|
|
339
321
|
|
|
340
322
|
async def _on_autocomplete(
|
|
341
323
|
self, interaction: hikari.AutocompleteInteraction
|
|
@@ -486,8 +468,8 @@ class SlashSubGroup(SubCommandBase[ClientT, SlashGroup[ClientT]]):
|
|
|
486
468
|
"""
|
|
487
469
|
|
|
488
470
|
@property
|
|
489
|
-
def option_type(self) ->
|
|
490
|
-
return
|
|
471
|
+
def option_type(self) -> OptionType:
|
|
472
|
+
return OptionType.SUB_COMMAND_GROUP
|
|
491
473
|
|
|
492
474
|
@property
|
|
493
475
|
def command_type(self) -> hikari.CommandType:
|
|
@@ -497,6 +479,10 @@ class SlashSubGroup(SubCommandBase[ClientT, SlashGroup[ClientT]]):
|
|
|
497
479
|
def qualified_name(self) -> t.Sequence[str]:
|
|
498
480
|
return (self.parent.name, self.name)
|
|
499
481
|
|
|
482
|
+
@property
|
|
483
|
+
def display_name(self) -> str:
|
|
484
|
+
return "/" + " ".join(self.qualified_name)
|
|
485
|
+
|
|
500
486
|
@property
|
|
501
487
|
def client(self) -> ClientT:
|
|
502
488
|
"""The client that includes this subgroup."""
|
|
@@ -599,49 +585,6 @@ class SlashSubCommand(
|
|
|
599
585
|
|
|
600
586
|
_invoke_task: asyncio.Task[t.Any] | None = attr.field(default=None, init=False)
|
|
601
587
|
|
|
602
|
-
def _resolve_settings(self) -> _CommandSettings:
|
|
603
|
-
settings = self._parent._resolve_settings() if self._parent else _CommandSettings.default()
|
|
604
|
-
|
|
605
|
-
return settings.apply(
|
|
606
|
-
_CommandSettings(
|
|
607
|
-
autodefer=self._autodefer,
|
|
608
|
-
default_permissions=hikari.UNDEFINED,
|
|
609
|
-
is_nsfw=hikari.UNDEFINED,
|
|
610
|
-
is_dm_enabled=hikari.UNDEFINED,
|
|
611
|
-
)
|
|
612
|
-
)
|
|
613
|
-
|
|
614
|
-
def _resolve_hooks(self) -> list[HookT[ClientT]]:
|
|
615
|
-
assert self._parent is not None
|
|
616
|
-
return self._parent._resolve_hooks() + self._hooks
|
|
617
|
-
|
|
618
|
-
def _resolve_post_hooks(self) -> list[PostHookT[ClientT]]:
|
|
619
|
-
assert self._parent is not None
|
|
620
|
-
return self._parent._resolve_post_hooks() + self._post_hooks
|
|
621
|
-
|
|
622
|
-
async def _handle_exception(self, ctx: Context[ClientT], exc: Exception) -> None:
|
|
623
|
-
try:
|
|
624
|
-
if self.error_handler:
|
|
625
|
-
await self.error_handler(ctx, exc)
|
|
626
|
-
else:
|
|
627
|
-
raise exc
|
|
628
|
-
except Exception as e:
|
|
629
|
-
assert self._parent is not None
|
|
630
|
-
await self._parent._handle_exception(ctx, e)
|
|
631
|
-
|
|
632
|
-
@property
|
|
633
|
-
def qualified_name(self) -> t.Sequence[str]:
|
|
634
|
-
if self._parent is None:
|
|
635
|
-
raise ValueError("Cannot get qualified name of subcommand without parent.")
|
|
636
|
-
|
|
637
|
-
if isinstance(self._parent, SlashSubGroup):
|
|
638
|
-
if self._parent._parent is None:
|
|
639
|
-
raise ValueError("Cannot get qualified name of subcommand without parent.")
|
|
640
|
-
|
|
641
|
-
return (self._parent._parent.name, self._parent.name, self.name)
|
|
642
|
-
|
|
643
|
-
return (self._parent.name, self.name)
|
|
644
|
-
|
|
645
588
|
@property
|
|
646
589
|
def root(self) -> SlashGroup[ClientT]:
|
|
647
590
|
"""The root group of this subcommand."""
|
|
@@ -656,18 +599,27 @@ class SlashSubCommand(
|
|
|
656
599
|
|
|
657
600
|
return self._parent
|
|
658
601
|
|
|
602
|
+
@property
|
|
603
|
+
def qualified_name(self) -> t.Sequence[str]:
|
|
604
|
+
if isinstance(self._parent, SlashSubGroup):
|
|
605
|
+
return (self.root.name, self.parent.name, self.name)
|
|
606
|
+
|
|
607
|
+
return (self.parent.name, self.name)
|
|
608
|
+
|
|
659
609
|
@property
|
|
660
610
|
def parent(self) -> SlashGroup[ClientT] | SlashSubGroup[ClientT]:
|
|
661
611
|
"""The parent of this subcommand."""
|
|
662
|
-
|
|
612
|
+
if self._parent is None:
|
|
613
|
+
raise ValueError("Cannot get parent of subcommand without parent.")
|
|
614
|
+
return self._parent
|
|
663
615
|
|
|
664
616
|
@property
|
|
665
617
|
def command_type(self) -> hikari.CommandType:
|
|
666
618
|
return hikari.CommandType.SLASH
|
|
667
619
|
|
|
668
620
|
@property
|
|
669
|
-
def option_type(self) ->
|
|
670
|
-
return
|
|
621
|
+
def option_type(self) -> OptionType:
|
|
622
|
+
return OptionType.SUB_COMMAND
|
|
671
623
|
|
|
672
624
|
@property
|
|
673
625
|
def client(self) -> ClientT:
|
|
@@ -686,6 +638,55 @@ class SlashSubCommand(
|
|
|
686
638
|
assert autodefer is not hikari.UNDEFINED
|
|
687
639
|
return autodefer
|
|
688
640
|
|
|
641
|
+
@property
|
|
642
|
+
def display_name(self) -> str:
|
|
643
|
+
return "/" + " ".join(self.qualified_name)
|
|
644
|
+
|
|
645
|
+
def make_mention(self, guild: hikari.Snowflakeish | hikari.PartialGuild | None = None) -> str:
|
|
646
|
+
"""Make a slash mention for this command.
|
|
647
|
+
|
|
648
|
+
Returns
|
|
649
|
+
-------
|
|
650
|
+
str
|
|
651
|
+
The slash command mention.
|
|
652
|
+
"""
|
|
653
|
+
instance = self.root._instances.get(hikari.Snowflake(guild) if guild else None)
|
|
654
|
+
|
|
655
|
+
if instance is None:
|
|
656
|
+
raise KeyError(f"Command '{self.display_name}' has not been published in the given scope.")
|
|
657
|
+
|
|
658
|
+
return f"</{' '.join(self.qualified_name)}:{instance.id}>"
|
|
659
|
+
|
|
660
|
+
def _resolve_settings(self) -> _CommandSettings:
|
|
661
|
+
settings = self._parent._resolve_settings() if self._parent else _CommandSettings.default()
|
|
662
|
+
|
|
663
|
+
return settings.apply(
|
|
664
|
+
_CommandSettings(
|
|
665
|
+
autodefer=self._autodefer,
|
|
666
|
+
default_permissions=hikari.UNDEFINED,
|
|
667
|
+
is_nsfw=hikari.UNDEFINED,
|
|
668
|
+
is_dm_enabled=hikari.UNDEFINED,
|
|
669
|
+
)
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
def _resolve_hooks(self) -> list[HookT[ClientT]]:
|
|
673
|
+
assert self._parent is not None
|
|
674
|
+
return self._parent._resolve_hooks() + self._hooks
|
|
675
|
+
|
|
676
|
+
def _resolve_post_hooks(self) -> list[PostHookT[ClientT]]:
|
|
677
|
+
assert self._parent is not None
|
|
678
|
+
return self._parent._resolve_post_hooks() + self._post_hooks
|
|
679
|
+
|
|
680
|
+
async def _handle_exception(self, ctx: Context[ClientT], exc: Exception) -> None:
|
|
681
|
+
try:
|
|
682
|
+
if self.error_handler:
|
|
683
|
+
await self.error_handler(ctx, exc)
|
|
684
|
+
else:
|
|
685
|
+
raise exc
|
|
686
|
+
except Exception as e:
|
|
687
|
+
assert self._parent is not None
|
|
688
|
+
await self._parent._handle_exception(ctx, e)
|
|
689
|
+
|
|
689
690
|
def _request_option_locale(self, client: Client[t.Any], command: CommandProto) -> None:
|
|
690
691
|
super()._request_option_locale(client, command)
|
|
691
692
|
|
arc/command/user.py
CHANGED
|
@@ -14,7 +14,7 @@ if t.TYPE_CHECKING:
|
|
|
14
14
|
import asyncio
|
|
15
15
|
|
|
16
16
|
from arc.abc.command import CallableCommandProto
|
|
17
|
-
from arc.internal.types import
|
|
17
|
+
from arc.internal.types import UserCommandCallbackT
|
|
18
18
|
|
|
19
19
|
__all__ = ("UserCommand", "user_command")
|
|
20
20
|
|
|
@@ -72,7 +72,7 @@ def user_command(
|
|
|
72
72
|
autodefer: bool | AutodeferMode | hikari.UndefinedType = hikari.UNDEFINED,
|
|
73
73
|
default_permissions: hikari.Permissions | hikari.UndefinedType = hikari.UNDEFINED,
|
|
74
74
|
name_localizations: t.Mapping[hikari.Locale, str] | None = None,
|
|
75
|
-
) -> t.Callable[[
|
|
75
|
+
) -> t.Callable[[UserCommandCallbackT[ClientT]], UserCommand[ClientT]]:
|
|
76
76
|
"""A decorator that creates a context-menu command on a user.
|
|
77
77
|
|
|
78
78
|
Parameters
|
|
@@ -106,7 +106,7 @@ def user_command(
|
|
|
106
106
|
```
|
|
107
107
|
"""
|
|
108
108
|
|
|
109
|
-
def decorator(callback:
|
|
109
|
+
def decorator(callback: UserCommandCallbackT[ClientT]) -> UserCommand[ClientT]:
|
|
110
110
|
guild_ids = tuple(hikari.Snowflake(i) for i in guilds) if guilds is not hikari.UNDEFINED else hikari.UNDEFINED
|
|
111
111
|
|
|
112
112
|
return UserCommand(
|