hikari-arc 1.2.0__py3-none-any.whl → 1.3.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/abc/command.py CHANGED
@@ -361,7 +361,7 @@ class CommandBase(
361
361
  async def _handle_exception(self, ctx: Context[ClientT], exc: Exception) -> None:
362
362
  try:
363
363
  if self.error_handler is not None:
364
- await self.error_handler(ctx, exc)
364
+ await ctx._injection_ctx.call_with_async_di(self.error_handler, ctx, exc)
365
365
  else:
366
366
  raise exc
367
367
  except Exception as exc:
@@ -402,12 +402,12 @@ class CommandBase(
402
402
  return None
403
403
 
404
404
  def _resolve_hooks(self) -> list[HookT[ClientT]]:
405
- plugin_hooks = self.plugin._resolve_hooks() if self.plugin else []
406
- return self.client._hooks + plugin_hooks + self._hooks
405
+ upstream_hooks = self.plugin._resolve_hooks() if self.plugin else self.client._hooks
406
+ return upstream_hooks + self._hooks
407
407
 
408
408
  def _resolve_post_hooks(self) -> list[PostHookT[ClientT]]:
409
- plugin_hooks = self.plugin._resolve_post_hooks() if self.plugin else []
410
- return self.client._post_hooks + plugin_hooks + self._post_hooks
409
+ upstream_hooks = self.plugin._resolve_post_hooks() if self.plugin else self.client._post_hooks
410
+ return upstream_hooks + self._post_hooks
411
411
 
412
412
  async def publish(self, guild: hikari.SnowflakeishOr[hikari.PartialGuild] | None = None) -> hikari.PartialCommand:
413
413
  """Publish this command to the given guild, or globally if no guild is provided.
@@ -549,10 +549,10 @@ class CommandBase(
549
549
  try:
550
550
  hooks = command._resolve_hooks()
551
551
  for hook in hooks:
552
- res = hook(ctx)
553
-
554
- if inspect.isawaitable(res):
555
- res = await res
552
+ if inspect.iscoroutinefunction(hook):
553
+ res = await ctx._injection_ctx.call_with_async_di(hook, ctx)
554
+ else:
555
+ res = ctx._injection_ctx.call_with_di(hook, ctx)
556
556
 
557
557
  res = t.cast(HookResult | None, res)
558
558
 
@@ -570,9 +570,9 @@ class CommandBase(
570
570
  post_hooks = command._resolve_post_hooks()
571
571
  for hook in post_hooks:
572
572
  if inspect.iscoroutinefunction(hook):
573
- await hook(ctx)
573
+ await ctx._injection_ctx.call_with_async_di(hook, ctx)
574
574
  else:
575
- hook(ctx)
575
+ ctx._injection_ctx.call_with_di(hook, ctx)
576
576
  except Exception as e:
577
577
  await command._handle_exception(ctx, e)
578
578
  finally:
@@ -585,6 +585,9 @@ class CommandBase(
585
585
  """Handle the callback of a command. Invoke all hooks and the callback, and handle any exceptions."""
586
586
  # If hook aborted, stop invocation
587
587
 
588
+ injection_ctx = await self.client._create_overriding_ctx_for_command(ctx)
589
+ ctx._injection_ctx = injection_ctx
590
+
588
591
  max_concurrency = command._resolve_concurrency_limiter()
589
592
 
590
593
  if max_concurrency is not None and max_concurrency.is_exhausted(ctx):
@@ -599,7 +602,7 @@ class CommandBase(
599
602
  if await self._handle_pre_hooks(command, ctx):
600
603
  return
601
604
 
602
- await self.client.injector.call_with_async_di(command.callback, ctx, *args, **kwargs)
605
+ await injection_ctx.call_with_async_di(command.callback, ctx, *args, **kwargs)
603
606
 
604
607
  except Exception as e:
605
608
  ctx._has_command_failed = True
arc/abc/error_handler.py CHANGED
@@ -27,12 +27,10 @@ class HasErrorHandler(abc.ABC, t.Generic[ClientT]):
27
27
  @t.overload
28
28
  def set_error_handler(
29
29
  self, callback: None = ...
30
- ) -> t.Callable[[ErrorHandlerCallbackT[ClientT]], ErrorHandlerCallbackT[ClientT]]:
31
- ...
30
+ ) -> t.Callable[[ErrorHandlerCallbackT[ClientT]], ErrorHandlerCallbackT[ClientT]]: ...
32
31
 
33
32
  @t.overload
34
- def set_error_handler(self, callback: ErrorHandlerCallbackT[ClientT]) -> ErrorHandlerCallbackT[ClientT]:
35
- ...
33
+ def set_error_handler(self, callback: ErrorHandlerCallbackT[ClientT]) -> ErrorHandlerCallbackT[ClientT]: ...
36
34
 
37
35
  def set_error_handler(
38
36
  self, callback: ErrorHandlerCallbackT[ClientT] | None = None
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
@@ -8,7 +8,7 @@ import typing as t
8
8
 
9
9
  import hikari
10
10
 
11
- from arc.abc.command import _CommandSettings
11
+ from arc.abc.command import CallableCommandBase, _CommandSettings
12
12
  from arc.abc.concurrency_limiting import ConcurrencyLimiterProto, HasConcurrencyLimiter
13
13
  from arc.abc.error_handler import HasErrorHandler
14
14
  from arc.abc.hookable import Hookable
@@ -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,16 +209,19 @@ 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[[CommandBase[ClientT, BuilderT]], CommandBase[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: CommandBase[ClientT, BuilderT]) -> CommandBase[ClientT, BuilderT]:
217
- ...
217
+ def include(self, command: CallableCommandBase[ClientT, BuilderT]) -> CallableCommandBase[ClientT, BuilderT]: ...
218
218
 
219
219
  def include(
220
- self, command: CommandBase[ClientT, BuilderT] | None = None
221
- ) -> CommandBase[ClientT, BuilderT] | t.Callable[[CommandBase[ClientT, BuilderT]], CommandBase[ClientT, BuilderT]]:
220
+ self, command: CallableCommandBase[ClientT, BuilderT] | None = None
221
+ ) -> (
222
+ CallableCommandBase[ClientT, BuilderT]
223
+ | t.Callable[[CallableCommandBase[ClientT, BuilderT]], CallableCommandBase[ClientT, BuilderT]]
224
+ ):
222
225
  """Add a command to this plugin.
223
226
 
224
227
  !!! note
@@ -235,7 +238,7 @@ class PluginBase(HasErrorHandler[ClientT], Hookable[ClientT], HasConcurrencyLimi
235
238
  If the command is already included in this plugin.
236
239
  """
237
240
 
238
- def decorator(command: CommandBase[ClientT, BuilderT]) -> CommandBase[ClientT, BuilderT]:
241
+ def decorator(command: CallableCommandBase[ClientT, BuilderT]) -> CallableCommandBase[ClientT, BuilderT]:
239
242
  if command.plugin is not None:
240
243
  raise ValueError(f"Command '{command.name}' is already registered with plugin '{command.plugin.name}'.")
241
244
 
@@ -320,12 +323,10 @@ class PluginBase(HasErrorHandler[ClientT], Hookable[ClientT], HasConcurrencyLimi
320
323
  return group
321
324
 
322
325
  @t.overload
323
- def inject_dependencies(self, func: t.Callable[P, T]) -> t.Callable[P, T]:
324
- ...
326
+ def inject_dependencies(self, func: t.Callable[P, T]) -> t.Callable[P, T]: ...
325
327
 
326
328
  @t.overload
327
- def inject_dependencies(self) -> t.Callable[[t.Callable[P, T]], t.Callable[P, T]]:
328
- ...
329
+ def inject_dependencies(self) -> t.Callable[[t.Callable[P, T]], t.Callable[P, T]]: ...
329
330
 
330
331
  def inject_dependencies(
331
332
  self, func: t.Callable[P, T] | None = None
@@ -401,26 +402,24 @@ class PluginBase(HasErrorHandler[ClientT], Hookable[ClientT], HasConcurrencyLimi
401
402
  @t.overload
402
403
  def walk_commands(
403
404
  self, command_type: t.Literal[hikari.CommandType.USER], *, callable_only: bool = False
404
- ) -> t.Iterator[UserCommand[ClientT]]:
405
- ...
405
+ ) -> t.Iterator[UserCommand[ClientT]]: ...
406
406
 
407
407
  @t.overload
408
408
  def walk_commands(
409
409
  self, command_type: t.Literal[hikari.CommandType.MESSAGE], *, callable_only: bool = False
410
- ) -> t.Iterator[MessageCommand[ClientT]]:
411
- ...
410
+ ) -> t.Iterator[MessageCommand[ClientT]]: ...
412
411
 
413
412
  @t.overload
414
413
  def walk_commands(
415
414
  self, command_type: t.Literal[hikari.CommandType.SLASH], *, callable_only: t.Literal[False]
416
- ) -> t.Iterator[SlashCommand[ClientT] | SlashSubCommand[ClientT] | SlashGroup[ClientT] | SlashSubGroup[ClientT]]:
417
- ...
415
+ ) -> t.Iterator[
416
+ SlashCommand[ClientT] | SlashSubCommand[ClientT] | SlashGroup[ClientT] | SlashSubGroup[ClientT]
417
+ ]: ...
418
418
 
419
419
  @t.overload
420
420
  def walk_commands(
421
421
  self, command_type: t.Literal[hikari.CommandType.SLASH], *, callable_only: t.Literal[True]
422
- ) -> t.Iterator[SlashCommand[ClientT] | SlashSubCommand[ClientT]]:
423
- ...
422
+ ) -> t.Iterator[SlashCommand[ClientT] | SlashSubCommand[ClientT]]: ...
424
423
 
425
424
  def walk_commands( # noqa: C901
426
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,