hikari-arc 1.2.1__py3-none-any.whl → 1.3.1__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/abc/option.py CHANGED
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
  import abc
4
4
  import enum
5
5
  import typing as t
6
- from typing import Any
7
6
 
8
7
  import attr
9
8
  import hikari
@@ -24,10 +23,12 @@ __all__ = (
24
23
  "OptionWithChoicesParams",
25
24
  "OptionBase",
26
25
  "CommandOptionBase",
26
+ "ConverterOption",
27
27
  "OptionType",
28
28
  )
29
29
 
30
30
  T = t.TypeVar("T")
31
+ OriginT = t.TypeVar("OriginT")
31
32
 
32
33
  Option = t.Annotated
33
34
  """Alias for typing.Annotated.
@@ -49,8 +50,9 @@ arc.Option[int, arc.IntParams(...)]
49
50
  class OptionType(enum.IntEnum):
50
51
  """The type of a command option.
51
52
 
52
- This is practically identical to `hikari.OptionType` at the moment.
53
- It may however be used in the future to define custom option types.
53
+ This includes all hikari option types along with some custom ones.
54
+
55
+ Custom arc-specific options start with 10k.
54
56
  """
55
57
 
56
58
  SUB_COMMAND = 1
@@ -92,6 +94,14 @@ class OptionType(enum.IntEnum):
92
94
  ATTACHMENT = 11
93
95
  """Denotes a command option where the value will be an attachment."""
94
96
 
97
+ # Custom optiontypes are 10k+
98
+
99
+ MEMBER = 10001
100
+ """Denotes a command option where the value will be resolved to a member."""
101
+
102
+ COLOR = 10002
103
+ """Denotes a command option where the value will be a color."""
104
+
95
105
  @classmethod
96
106
  def from_hikari(cls, option_type: hikari.OptionType) -> OptionType:
97
107
  """Convert a hikari.OptionType to an OptionType."""
@@ -99,10 +109,13 @@ class OptionType(enum.IntEnum):
99
109
 
100
110
  def to_hikari(self) -> hikari.OptionType:
101
111
  """Convert an OptionType to a hikari.OptionType."""
102
- # TODO: Map custom option types to their respective hikari.OptionType
103
- return hikari.OptionType(self.value)
112
+ if self.value < 10000:
113
+ return hikari.OptionType(self.value)
104
114
 
105
- # TODO: When adding custom convertible option types, add them with an offset of 1000 or so
115
+ if self is OptionType.MEMBER:
116
+ return hikari.OptionType.USER
117
+ else:
118
+ return hikari.OptionType.STRING
106
119
 
107
120
 
108
121
  class OptionParams(t.Generic[T]):
@@ -273,15 +286,22 @@ class CommandOptionBase(OptionBase[T], t.Generic[T, ClientT, ParamsT]):
273
286
  is_required: bool = True
274
287
  """Whether the option is required."""
275
288
 
289
+ arg_name: str
290
+ """The name of the parameter this option represents.
291
+ This is going to be the same as `name` unless `name` was overriden.
292
+ """
293
+
276
294
  @classmethod
277
295
  @abc.abstractmethod
278
- def _from_params(cls, *, name: str, is_required: bool, params: ParamsT, **kwargs: t.Any) -> te.Self:
296
+ def _from_params(cls, *, name: str, arg_name: str, is_required: bool, params: ParamsT, **kwargs: t.Any) -> te.Self:
279
297
  """Construct a new Option instance from the given parameters object.
280
298
 
281
299
  Parameters
282
300
  ----------
283
301
  name : str
284
302
  The name of the option
303
+ arg_name : str
304
+ The name of the parameter this option represents
285
305
  is_required : bool
286
306
  Whether the option is required
287
307
  params : ParamsT
@@ -290,10 +310,19 @@ class CommandOptionBase(OptionBase[T], t.Generic[T, ClientT, ParamsT]):
290
310
  Any additional keyword arguments to pass to the constructor
291
311
  """
292
312
 
293
- def _to_dict(self) -> dict[str, Any]:
313
+ def _to_dict(self) -> dict[str, t.Any]:
294
314
  return {**super()._to_dict(), "is_required": self.is_required}
295
315
 
296
316
 
317
+ @attr.define(slots=True, kw_only=True)
318
+ class ConverterOption(CommandOptionBase[T, ClientT, ParamsT], t.Generic[T, ClientT, ParamsT, OriginT]):
319
+ """An option with a built-in converter."""
320
+
321
+ @abc.abstractmethod
322
+ def _convert_value(self, value: OriginT) -> T:
323
+ """Convert the value to the desired type."""
324
+
325
+
297
326
  @attr.define(slots=True, kw_only=True)
298
327
  class OptionWithChoices(CommandOptionBase[ChoiceT, ClientT, ParamsT]):
299
328
  """An option that can have choices or be autocompleted."""
arc/abc/plugin.py CHANGED
@@ -155,7 +155,7 @@ class PluginBase(HasErrorHandler[ClientT], Hookable[ClientT], HasConcurrencyLimi
155
155
  async def _handle_exception(self, ctx: Context[ClientT], exc: Exception) -> None:
156
156
  try:
157
157
  if self.error_handler is not None:
158
- await self.error_handler(ctx, exc)
158
+ await ctx._injection_ctx.call_with_async_di(self.error_handler, ctx, exc)
159
159
  else:
160
160
  raise exc
161
161
  except Exception as exc:
@@ -209,12 +209,12 @@ class PluginBase(HasErrorHandler[ClientT], Hookable[ClientT], HasConcurrencyLimi
209
209
  raise TypeError(f"Unknown command type '{type(command).__name__}'.")
210
210
 
211
211
  @t.overload
212
- def include(self) -> t.Callable[[CallableCommandBase[ClientT, BuilderT]], CallableCommandBase[ClientT, BuilderT]]:
213
- ...
212
+ def include(
213
+ self,
214
+ ) -> t.Callable[[CallableCommandBase[ClientT, BuilderT]], CallableCommandBase[ClientT, BuilderT]]: ...
214
215
 
215
216
  @t.overload
216
- def include(self, command: CallableCommandBase[ClientT, BuilderT]) -> CallableCommandBase[ClientT, BuilderT]:
217
- ...
217
+ def include(self, command: CallableCommandBase[ClientT, BuilderT]) -> CallableCommandBase[ClientT, BuilderT]: ...
218
218
 
219
219
  def include(
220
220
  self, command: CallableCommandBase[ClientT, BuilderT] | None = None
@@ -323,12 +323,10 @@ class PluginBase(HasErrorHandler[ClientT], Hookable[ClientT], HasConcurrencyLimi
323
323
  return group
324
324
 
325
325
  @t.overload
326
- def inject_dependencies(self, func: t.Callable[P, T]) -> t.Callable[P, T]:
327
- ...
326
+ def inject_dependencies(self, func: t.Callable[P, T]) -> t.Callable[P, T]: ...
328
327
 
329
328
  @t.overload
330
- def inject_dependencies(self) -> t.Callable[[t.Callable[P, T]], t.Callable[P, T]]:
331
- ...
329
+ def inject_dependencies(self) -> t.Callable[[t.Callable[P, T]], t.Callable[P, T]]: ...
332
330
 
333
331
  def inject_dependencies(
334
332
  self, func: t.Callable[P, T] | None = None
@@ -404,26 +402,24 @@ class PluginBase(HasErrorHandler[ClientT], Hookable[ClientT], HasConcurrencyLimi
404
402
  @t.overload
405
403
  def walk_commands(
406
404
  self, command_type: t.Literal[hikari.CommandType.USER], *, callable_only: bool = False
407
- ) -> t.Iterator[UserCommand[ClientT]]:
408
- ...
405
+ ) -> t.Iterator[UserCommand[ClientT]]: ...
409
406
 
410
407
  @t.overload
411
408
  def walk_commands(
412
409
  self, command_type: t.Literal[hikari.CommandType.MESSAGE], *, callable_only: bool = False
413
- ) -> t.Iterator[MessageCommand[ClientT]]:
414
- ...
410
+ ) -> t.Iterator[MessageCommand[ClientT]]: ...
415
411
 
416
412
  @t.overload
417
413
  def walk_commands(
418
414
  self, command_type: t.Literal[hikari.CommandType.SLASH], *, callable_only: t.Literal[False]
419
- ) -> t.Iterator[SlashCommand[ClientT] | SlashSubCommand[ClientT] | SlashGroup[ClientT] | SlashSubGroup[ClientT]]:
420
- ...
415
+ ) -> t.Iterator[
416
+ SlashCommand[ClientT] | SlashSubCommand[ClientT] | SlashGroup[ClientT] | SlashSubGroup[ClientT]
417
+ ]: ...
421
418
 
422
419
  @t.overload
423
420
  def walk_commands(
424
421
  self, command_type: t.Literal[hikari.CommandType.SLASH], *, callable_only: t.Literal[True]
425
- ) -> t.Iterator[SlashCommand[ClientT] | SlashSubCommand[ClientT]]:
426
- ...
422
+ ) -> t.Iterator[SlashCommand[ClientT] | SlashSubCommand[ClientT]]: ...
427
423
 
428
424
  def walk_commands( # noqa: C901
429
425
  self, command_type: hikari.CommandType, *, callable_only: bool = False
arc/client.py CHANGED
@@ -18,8 +18,7 @@ if t.TYPE_CHECKING:
18
18
  import typing_extensions as te
19
19
 
20
20
  from arc import AutodeferMode
21
-
22
- from .internal.types import EventCallbackT, EventT, ResponseBuilderT
21
+ from arc.internal.types import EventCallbackT, EventT, ResponseBuilderT
23
22
 
24
23
  __all__ = (
25
24
  "GatewayClientBase",
arc/command/__init__.py CHANGED
@@ -6,10 +6,16 @@ from .option import (
6
6
  BoolParams,
7
7
  ChannelOption,
8
8
  ChannelParams,
9
+ ColorOption,
10
+ ColorParams,
11
+ ColourOption,
12
+ ColourParams,
9
13
  FloatOption,
10
14
  FloatParams,
11
15
  IntOption,
12
16
  IntParams,
17
+ MemberOption,
18
+ MemberParams,
13
19
  MentionableOption,
14
20
  MentionableParams,
15
21
  RoleOption,
@@ -56,6 +62,12 @@ __all__ = (
56
62
  "MentionableParams",
57
63
  "AttachmentOption",
58
64
  "AttachmentParams",
65
+ "MemberOption",
66
+ "MemberParams",
67
+ "ColorOption",
68
+ "ColorParams",
69
+ "ColourOption",
70
+ "ColourParams",
59
71
  "UserCommand",
60
72
  "user_command",
61
73
  "MessageCommand",
@@ -1,6 +1,7 @@
1
1
  from .attachment import AttachmentOption, AttachmentParams
2
2
  from .bool import BoolOption, BoolParams
3
3
  from .channel import ChannelOption, ChannelParams
4
+ from .custom import ColorOption, ColorParams, ColourOption, ColourParams, MemberOption, MemberParams
4
5
  from .float import FloatOption, FloatParams
5
6
  from .int import IntOption, IntParams
6
7
  from .mentionable import MentionableOption, MentionableParams
@@ -27,6 +28,12 @@ __all__ = (
27
28
  "MentionableParams",
28
29
  "AttachmentOption",
29
30
  "AttachmentParams",
31
+ "MemberOption",
32
+ "MemberParams",
33
+ "ColorOption",
34
+ "ColorParams",
35
+ "ColourOption",
36
+ "ColourParams",
30
37
  )
31
38
 
32
39
  # MIT License
@@ -52,9 +52,12 @@ class AttachmentOption(CommandOptionBase[hikari.Attachment, ClientT, AttachmentP
52
52
  return OptionType.ATTACHMENT
53
53
 
54
54
  @classmethod
55
- def _from_params(cls, *, name: str, is_required: bool, params: AttachmentParams, **kwargs: t.Any) -> te.Self:
55
+ def _from_params(
56
+ cls, *, name: str, arg_name: str, is_required: bool, params: AttachmentParams, **kwargs: t.Any
57
+ ) -> te.Self:
56
58
  return cls(
57
59
  name=name,
60
+ arg_name=arg_name,
58
61
  description=params.description,
59
62
  is_required=is_required,
60
63
  name_localizations=params.name_localizations,
@@ -51,9 +51,12 @@ class BoolOption(CommandOptionBase[bool, ClientT, BoolParams]):
51
51
  return OptionType.BOOLEAN
52
52
 
53
53
  @classmethod
54
- def _from_params(cls, *, name: str, is_required: bool, params: BoolParams, **kwargs: t.Any) -> te.Self:
54
+ def _from_params(
55
+ cls, *, name: str, arg_name: str, is_required: bool, params: BoolParams, **kwargs: t.Any
56
+ ) -> te.Self:
55
57
  return cls(
56
58
  name=name,
59
+ arg_name=arg_name,
57
60
  description=params.description,
58
61
  is_required=is_required,
59
62
  name_localizations=params.name_localizations,
@@ -63,10 +63,13 @@ class ChannelOption(CommandOptionBase[hikari.PartialChannel, ClientT, ChannelPar
63
63
  return OptionType.CHANNEL
64
64
 
65
65
  @classmethod
66
- def _from_params(cls, *, name: str, is_required: bool, params: ChannelParams, **kwargs: t.Any) -> te.Self:
66
+ def _from_params(
67
+ cls, *, name: str, arg_name: str, is_required: bool, params: ChannelParams, **kwargs: t.Any
68
+ ) -> te.Self:
67
69
  channel_types = kwargs.pop("channel_types")
68
70
  return cls(
69
71
  name=name,
72
+ arg_name=arg_name,
70
73
  description=params.description,
71
74
  is_required=is_required,
72
75
  name_localizations=params.name_localizations,
@@ -0,0 +1,4 @@
1
+ from .color import ColorOption, ColorParams, ColourOption, ColourParams
2
+ from .member import MemberOption, MemberParams
3
+
4
+ __all__ = ("ColorOption", "ColorParams", "ColourOption", "ColourParams", "MemberOption", "MemberParams")
@@ -0,0 +1,106 @@
1
+ from __future__ import annotations
2
+
3
+ import typing as t
4
+
5
+ import attr
6
+ import hikari
7
+
8
+ from arc.abc.option import ConverterOption, OptionParams, OptionType
9
+ from arc.errors import OptionConverterFailureError
10
+ from arc.internal.types import ClientT
11
+
12
+ if t.TYPE_CHECKING:
13
+ import typing_extensions as te
14
+
15
+
16
+ __all__ = ("ColorOption", "ColorParams", "ColourOption", "ColourParams")
17
+
18
+
19
+ @t.final
20
+ class ColorParams(OptionParams[hikari.Color]):
21
+ """The parameters for a color option.
22
+
23
+ Parameters
24
+ ----------
25
+ description : str
26
+ The description of the option
27
+
28
+ Other Parameters
29
+ ----------------
30
+ name : str
31
+ The name of the option. If not provided, the name of the parameter will be used.
32
+ name_localizations : Mapping[hikari.Locale, str] | None
33
+ The name of the option in different locales
34
+ description_localizations : Mapping[hikari.Locale, str] | None
35
+ The description of the option in different locales
36
+ """
37
+
38
+ __slots__ = ()
39
+
40
+
41
+ @attr.define(slots=True, kw_only=True)
42
+ class ColorOption(ConverterOption[hikari.Color, ClientT, ColorParams, str]):
43
+ """A slash command option that represents a color.
44
+
45
+ ??? hint
46
+ To add an option of this type to your command, add an argument to your command function with the following type hint:
47
+ ```py
48
+ opt_name: arc.Option[hikari.Color, ColorParams(...)]
49
+ ```
50
+ """
51
+
52
+ @property
53
+ def option_type(self) -> OptionType:
54
+ return OptionType.COLOR
55
+
56
+ def _convert_value(self, value: str) -> hikari.Color:
57
+ try:
58
+ return hikari.Color.of(value)
59
+ except ValueError as exc:
60
+ raise OptionConverterFailureError(
61
+ self, value, f"Option '{self.name}' expected a valid color, got {value!r}."
62
+ ) from exc
63
+
64
+ @classmethod
65
+ def _from_params(
66
+ cls, *, name: str, arg_name: str, is_required: bool, params: ColorParams, **kwargs: t.Any
67
+ ) -> te.Self:
68
+ return cls(
69
+ name=name,
70
+ arg_name=arg_name,
71
+ description=params.description,
72
+ is_required=is_required,
73
+ name_localizations=params.name_localizations,
74
+ description_localizations=params.description_localizations,
75
+ **kwargs,
76
+ )
77
+
78
+
79
+ # God save the queen
80
+ ColourParams = ColorParams
81
+ """An alias for `ColorParams`."""
82
+
83
+ ColourOption = ColorOption
84
+ """An alias for `ColorOption`."""
85
+
86
+ # MIT License
87
+ #
88
+ # Copyright (c) 2023-present hypergonial
89
+ #
90
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
91
+ # of this software and associated documentation files (the "Software"), to deal
92
+ # in the Software without restriction, including without limitation the rights
93
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
94
+ # copies of the Software, and to permit persons to whom the Software is
95
+ # furnished to do so, subject to the following conditions:
96
+ #
97
+ # The above copyright notice and this permission notice shall be included in all
98
+ # copies or substantial portions of the Software.
99
+ #
100
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
101
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
102
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
103
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
104
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
105
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
106
+ # SOFTWARE.
@@ -0,0 +1,98 @@
1
+ from __future__ import annotations
2
+
3
+ import typing as t
4
+
5
+ import attr
6
+ import hikari
7
+
8
+ from arc.abc.option import ConverterOption, OptionParams, OptionType
9
+ from arc.errors import OptionConverterFailureError
10
+ from arc.internal.types import ClientT
11
+
12
+ if t.TYPE_CHECKING:
13
+ import typing_extensions as te
14
+
15
+
16
+ __all__ = ("MemberOption", "MemberParams")
17
+
18
+
19
+ @t.final
20
+ class MemberParams(OptionParams[hikari.InteractionMember]):
21
+ """The parameters for a member option.
22
+
23
+ Parameters
24
+ ----------
25
+ description : str
26
+ The description of the option
27
+
28
+ Other Parameters
29
+ ----------------
30
+ name : str
31
+ The name of the option. If not provided, the name of the parameter will be used.
32
+ name_localizations : Mapping[hikari.Locale, str] | None
33
+ The name of the option in different locales
34
+ description_localizations : Mapping[hikari.Locale, str] | None
35
+ The description of the option in different locales
36
+ """
37
+
38
+ __slots__ = ()
39
+
40
+
41
+ @attr.define(slots=True, kw_only=True)
42
+ class MemberOption(ConverterOption[hikari.InteractionMember, ClientT, MemberParams, hikari.User]):
43
+ """A slash command option that represents a member.
44
+
45
+ ??? hint
46
+ To add an option of this type to your command, add an argument to your command function with the following type hint:
47
+ ```py
48
+ opt_name: arc.Option[hikari.Member, MemberParams(...)]
49
+ ```
50
+ """
51
+
52
+ @property
53
+ def option_type(self) -> OptionType:
54
+ return OptionType.MEMBER
55
+
56
+ def _convert_value(self, value: hikari.User) -> hikari.InteractionMember:
57
+ if isinstance(value, hikari.InteractionMember):
58
+ return value
59
+ raise OptionConverterFailureError(
60
+ self, value, f"Option '{self.name}' expected an InteractionMember, got {value!r}."
61
+ )
62
+
63
+ @classmethod
64
+ def _from_params(
65
+ cls, *, name: str, arg_name: str, is_required: bool, params: MemberParams, **kwargs: t.Any
66
+ ) -> te.Self:
67
+ return cls(
68
+ name=name,
69
+ arg_name=arg_name,
70
+ description=params.description,
71
+ is_required=is_required,
72
+ name_localizations=params.name_localizations,
73
+ description_localizations=params.description_localizations,
74
+ **kwargs,
75
+ )
76
+
77
+
78
+ # MIT License
79
+ #
80
+ # Copyright (c) 2023-present hypergonial
81
+ #
82
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
83
+ # of this software and associated documentation files (the "Software"), to deal
84
+ # in the Software without restriction, including without limitation the rights
85
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
86
+ # copies of the Software, and to permit persons to whom the Software is
87
+ # furnished to do so, subject to the following conditions:
88
+ #
89
+ # The above copyright notice and this permission notice shall be included in all
90
+ # copies or substantial portions of the Software.
91
+ #
92
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
93
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
94
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
95
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
96
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
97
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
98
+ # SOFTWARE.
@@ -103,9 +103,12 @@ class FloatOption(OptionWithChoices[float, ClientT, FloatParams[ClientT]]):
103
103
  return OptionType.FLOAT
104
104
 
105
105
  @classmethod
106
- def _from_params(cls, *, name: str, is_required: bool, params: FloatParams[ClientT], **kwargs: t.Any) -> te.Self:
106
+ def _from_params(
107
+ cls, *, name: str, arg_name: str, is_required: bool, params: FloatParams[ClientT], **kwargs: t.Any
108
+ ) -> te.Self:
107
109
  return cls(
108
110
  name=name,
111
+ arg_name=arg_name,
109
112
  description=params.description,
110
113
  is_required=is_required,
111
114
  min=params.min,
arc/command/option/int.py CHANGED
@@ -103,9 +103,12 @@ class IntOption(OptionWithChoices[int, ClientT, IntParams[ClientT]]):
103
103
  return OptionType.INTEGER
104
104
 
105
105
  @classmethod
106
- def _from_params(cls, *, name: str, is_required: bool, params: IntParams[ClientT], **kwargs: t.Any) -> te.Self:
106
+ def _from_params(
107
+ cls, *, name: str, arg_name: str, is_required: bool, params: IntParams[ClientT], **kwargs: t.Any
108
+ ) -> te.Self:
107
109
  return cls(
108
110
  name=name,
111
+ arg_name=arg_name,
109
112
  description=params.description,
110
113
  is_required=is_required,
111
114
  min=params.min,
@@ -53,9 +53,12 @@ class MentionableOption(CommandOptionBase[hikari.Role | hikari.User, ClientT, Me
53
53
  return OptionType.MENTIONABLE
54
54
 
55
55
  @classmethod
56
- def _from_params(cls, *, name: str, is_required: bool, params: MentionableParams, **kwargs: t.Any) -> te.Self:
56
+ def _from_params(
57
+ cls, *, name: str, arg_name: str, is_required: bool, params: MentionableParams, **kwargs: t.Any
58
+ ) -> te.Self:
57
59
  return cls(
58
60
  name=name,
61
+ arg_name=arg_name,
59
62
  description=params.description,
60
63
  is_required=is_required,
61
64
  name_localizations=params.name_localizations,
@@ -52,9 +52,12 @@ class RoleOption(CommandOptionBase[hikari.Role, ClientT, RoleParams]):
52
52
  return OptionType.ROLE
53
53
 
54
54
  @classmethod
55
- def _from_params(cls, *, name: str, is_required: bool, params: RoleParams, **kwargs: t.Any) -> te.Self:
55
+ def _from_params(
56
+ cls, *, name: str, arg_name: str, is_required: bool, params: RoleParams, **kwargs: t.Any
57
+ ) -> te.Self:
56
58
  return cls(
57
59
  name=name,
60
+ arg_name=arg_name,
58
61
  description=params.description,
59
62
  is_required=is_required,
60
63
  name_localizations=params.name_localizations,
arc/command/option/str.py CHANGED
@@ -104,9 +104,12 @@ class StrOption(OptionWithChoices[str, ClientT, StrParams[ClientT]]):
104
104
  return OptionType.STRING
105
105
 
106
106
  @classmethod
107
- def _from_params(cls, *, name: str, is_required: bool, params: StrParams[ClientT], **kwargs: t.Any) -> te.Self:
107
+ def _from_params(
108
+ cls, *, name: str, arg_name: str, is_required: bool, params: StrParams[ClientT], **kwargs: t.Any
109
+ ) -> te.Self:
108
110
  return cls(
109
111
  name=name,
112
+ arg_name=arg_name,
110
113
  description=params.description,
111
114
  is_required=is_required,
112
115
  min_length=params.min_length,
@@ -53,9 +53,12 @@ class UserOption(CommandOptionBase[hikari.User, ClientT, UserParams]):
53
53
  return OptionType.USER
54
54
 
55
55
  @classmethod
56
- def _from_params(cls, *, name: str, is_required: bool, params: UserParams, **kwargs: t.Any) -> te.Self:
56
+ def _from_params(
57
+ cls, *, name: str, arg_name: str, is_required: bool, params: UserParams, **kwargs: t.Any
58
+ ) -> te.Self:
57
59
  return cls(
58
60
  name=name,
61
+ arg_name=arg_name,
59
62
  description=params.description,
60
63
  is_required=is_required,
61
64
  name_localizations=params.name_localizations,
arc/command/slash.py CHANGED
@@ -36,9 +36,12 @@ __all__ = (
36
36
 
37
37
 
38
38
  def _choices_to_builders(
39
- choices: t.Sequence[hikari.api.AutocompleteChoiceBuilder] | t.Sequence[t.Any],
39
+ choices: t.Sequence[hikari.api.AutocompleteChoiceBuilder] | t.Sequence[t.Any] | t.Mapping[str, t.Any],
40
40
  ) -> t.Sequence[hikari.api.AutocompleteChoiceBuilder]:
41
41
  """Convert a sequence of choices to a sequence of choice builders."""
42
+ if isinstance(choices, t.Mapping):
43
+ return [hikari.impl.AutocompleteChoiceBuilder(str(k), v) for k, v in choices.items()]
44
+
42
45
  return [
43
46
  (
44
47
  hikari.impl.AutocompleteChoiceBuilder(str(e), e)
@@ -403,12 +406,10 @@ class SlashGroup(CommandBase[ClientT, hikari.api.SlashCommandBuilder]):
403
406
  sub._request_option_locale(self._client, self)
404
407
 
405
408
  @t.overload
406
- def include(self) -> t.Callable[[SlashSubCommand[ClientT]], SlashSubCommand[ClientT]]:
407
- ...
409
+ def include(self) -> t.Callable[[SlashSubCommand[ClientT]], SlashSubCommand[ClientT]]: ...
408
410
 
409
411
  @t.overload
410
- def include(self, command: SlashSubCommand[ClientT]) -> SlashSubCommand[ClientT]:
411
- ...
412
+ def include(self, command: SlashSubCommand[ClientT]) -> SlashSubCommand[ClientT]: ...
412
413
 
413
414
  def include(
414
415
  self, command: SlashSubCommand[ClientT] | None = None
@@ -540,12 +541,12 @@ class SlashSubGroup(SubCommandBase[ClientT, SlashGroup[ClientT]]):
540
541
  async def _handle_exception(self, ctx: Context[ClientT], exc: Exception) -> None:
541
542
  try:
542
543
  if self.error_handler:
543
- await self.error_handler(ctx, exc)
544
+ await ctx._injection_ctx.call_with_async_di(self.error_handler, ctx, exc)
544
545
  else:
545
546
  raise exc
546
- except Exception as e:
547
+ except Exception as exc:
547
548
  assert self._parent is not None
548
- await self._parent._handle_exception(ctx, e)
549
+ await ctx._injection_ctx.call_with_async_di(self._parent._handle_exception, ctx, exc)
549
550
 
550
551
  def _request_option_locale(self, client: Client[t.Any], command: CommandProto) -> None:
551
552
  super()._request_option_locale(client, command)
@@ -554,12 +555,10 @@ class SlashSubGroup(SubCommandBase[ClientT, SlashGroup[ClientT]]):
554
555
  subcommand._request_option_locale(client, command)
555
556
 
556
557
  @t.overload
557
- def include(self) -> t.Callable[[SlashSubCommand[ClientT]], SlashSubCommand[ClientT]]:
558
- ...
558
+ def include(self) -> t.Callable[[SlashSubCommand[ClientT]], SlashSubCommand[ClientT]]: ...
559
559
 
560
560
  @t.overload
561
- def include(self, command: SlashSubCommand[ClientT]) -> SlashSubCommand[ClientT]:
562
- ...
561
+ def include(self, command: SlashSubCommand[ClientT]) -> SlashSubCommand[ClientT]: ...
563
562
 
564
563
  def include(
565
564
  self, command: SlashSubCommand[ClientT] | None = None
@@ -700,7 +699,7 @@ class SlashSubCommand(
700
699
  raise exc
701
700
  except Exception as e:
702
701
  assert self._parent is not None
703
- await self._parent._handle_exception(ctx, e)
702
+ await self._handle_exception(ctx, e)
704
703
 
705
704
  def _request_option_locale(self, client: Client[t.Any], command: CommandProto) -> None:
706
705
  super()._request_option_locale(client, command)