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/__init__.py +12 -1
- arc/__main__.py +1 -0
- arc/abc/__init__.py +2 -0
- arc/abc/client.py +246 -70
- arc/abc/command.py +15 -12
- arc/abc/error_handler.py +2 -4
- arc/abc/option.py +37 -8
- arc/abc/plugin.py +20 -21
- arc/client.py +1 -2
- arc/command/__init__.py +12 -0
- arc/command/option/__init__.py +7 -0
- arc/command/option/attachment.py +4 -1
- arc/command/option/bool.py +4 -1
- arc/command/option/channel.py +4 -1
- arc/command/option/custom/__init__.py +4 -0
- arc/command/option/custom/color.py +106 -0
- arc/command/option/custom/member.py +98 -0
- arc/command/option/float.py +4 -1
- arc/command/option/int.py +4 -1
- arc/command/option/mentionable.py +4 -1
- arc/command/option/role.py +4 -1
- arc/command/option/str.py +4 -1
- arc/command/option/user.py +4 -1
- arc/command/slash.py +17 -20
- arc/context/base.py +66 -29
- arc/errors.py +18 -0
- arc/extension.py +4 -8
- arc/internal/about.py +2 -2
- arc/internal/options.py +9 -4
- arc/internal/sigparse.py +19 -5
- arc/internal/sync.py +3 -3
- arc/internal/types.py +3 -1
- arc/utils/concurrency_limiter.py +9 -4
- arc/utils/ratelimiter.py +1 -1
- {hikari_arc-1.2.0.dist-info → hikari_arc-1.3.0.dist-info}/METADATA +17 -17
- hikari_arc-1.3.0.dist-info/RECORD +59 -0
- {hikari_arc-1.2.0.dist-info → hikari_arc-1.3.0.dist-info}/WHEEL +1 -1
- hikari_arc-1.2.0.dist-info/RECORD +0 -56
- {hikari_arc-1.2.0.dist-info → hikari_arc-1.3.0.dist-info}/LICENSE +0 -0
- {hikari_arc-1.2.0.dist-info → hikari_arc-1.3.0.dist-info}/top_level.txt +0 -0
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(
|
|
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,
|
arc/command/option/user.py
CHANGED
|
@@ -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(
|
|
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
|
|
@@ -518,7 +519,7 @@ class SlashSubGroup(SubCommandBase[ClientT, SlashGroup[ClientT]]):
|
|
|
518
519
|
|
|
519
520
|
return settings.apply(
|
|
520
521
|
_CommandSettings(
|
|
521
|
-
autodefer=self.
|
|
522
|
+
autodefer=self._autodefer,
|
|
522
523
|
default_permissions=hikari.UNDEFINED,
|
|
523
524
|
is_nsfw=hikari.UNDEFINED,
|
|
524
525
|
is_dm_enabled=hikari.UNDEFINED,
|
|
@@ -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
|
|
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
|
|
547
|
+
except Exception as exc:
|
|
547
548
|
assert self._parent is not None
|
|
548
|
-
await self._parent._handle_exception
|
|
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.
|
|
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)
|
|
@@ -746,7 +745,7 @@ def slash_command(
|
|
|
746
745
|
default_permissions: hikari.Permissions | hikari.UndefinedType = hikari.UNDEFINED,
|
|
747
746
|
name_localizations: t.Mapping[hikari.Locale, str] | None = None,
|
|
748
747
|
description_localizations: t.Mapping[hikari.Locale, str] | None = None,
|
|
749
|
-
) -> t.Callable[[
|
|
748
|
+
) -> t.Callable[[CommandCallbackT[ClientT]], SlashCommand[ClientT]]:
|
|
750
749
|
"""A decorator that creates a slash command.
|
|
751
750
|
|
|
752
751
|
Parameters
|
|
@@ -791,7 +790,7 @@ def slash_command(
|
|
|
791
790
|
```
|
|
792
791
|
"""
|
|
793
792
|
|
|
794
|
-
def decorator(func:
|
|
793
|
+
def decorator(func: CommandCallbackT[ClientT]) -> SlashCommand[ClientT]:
|
|
795
794
|
guild_ids = tuple(hikari.Snowflake(i) for i in guilds) if guilds is not hikari.UNDEFINED else hikari.UNDEFINED
|
|
796
795
|
options = parse_command_signature(func)
|
|
797
796
|
|
|
@@ -819,7 +818,7 @@ def slash_subcommand(
|
|
|
819
818
|
autodefer: bool | AutodeferMode | hikari.UndefinedType = hikari.UNDEFINED,
|
|
820
819
|
name_localizations: t.Mapping[hikari.Locale, str] | None = None,
|
|
821
820
|
description_localizations: t.Mapping[hikari.Locale, str] | None = None,
|
|
822
|
-
) -> t.Callable[[
|
|
821
|
+
) -> t.Callable[[CommandCallbackT[ClientT]], SlashSubCommand[ClientT]]:
|
|
823
822
|
"""A decorator that creates a slash sub command. It should be included in a slash command group.
|
|
824
823
|
|
|
825
824
|
Parameters
|
|
@@ -859,9 +858,7 @@ def slash_subcommand(
|
|
|
859
858
|
```
|
|
860
859
|
"""
|
|
861
860
|
|
|
862
|
-
def decorator(
|
|
863
|
-
func: t.Callable[t.Concatenate[Context[ClientT], ...], t.Awaitable[None]],
|
|
864
|
-
) -> SlashSubCommand[ClientT]:
|
|
861
|
+
def decorator(func: CommandCallbackT[ClientT]) -> SlashSubCommand[ClientT]:
|
|
865
862
|
options = parse_command_signature(func)
|
|
866
863
|
|
|
867
864
|
return SlashSubCommand(
|
arc/context/base.py
CHANGED
|
@@ -7,6 +7,7 @@ import logging
|
|
|
7
7
|
import typing as t
|
|
8
8
|
from contextlib import suppress
|
|
9
9
|
|
|
10
|
+
import alluka
|
|
10
11
|
import attr
|
|
11
12
|
import hikari
|
|
12
13
|
|
|
@@ -23,6 +24,9 @@ __all__ = ("Context", "InteractionResponse", "AutodeferMode")
|
|
|
23
24
|
|
|
24
25
|
logger = logging.getLogger(__name__)
|
|
25
26
|
|
|
27
|
+
T = t.TypeVar("T")
|
|
28
|
+
DefaultT = t.TypeVar("DefaultT")
|
|
29
|
+
|
|
26
30
|
|
|
27
31
|
@t.final
|
|
28
32
|
class AutodeferMode(enum.IntEnum):
|
|
@@ -162,14 +166,14 @@ class InteractionResponse:
|
|
|
162
166
|
|
|
163
167
|
async def edit(
|
|
164
168
|
self,
|
|
165
|
-
content: t.Any | hikari.UndefinedType = hikari.UNDEFINED,
|
|
169
|
+
content: t.Any | hikari.UndefinedType | None = hikari.UNDEFINED,
|
|
166
170
|
*,
|
|
167
|
-
component: hikari.api.ComponentBuilder | hikari.UndefinedType = hikari.UNDEFINED,
|
|
168
|
-
components: t.Sequence[hikari.api.ComponentBuilder] | hikari.UndefinedType = hikari.UNDEFINED,
|
|
169
|
-
attachment: hikari.Resourceish | hikari.UndefinedType = hikari.UNDEFINED,
|
|
170
|
-
attachments: t.Sequence[hikari.Resourceish] | hikari.UndefinedType = hikari.UNDEFINED,
|
|
171
|
-
embed: hikari.Embed | hikari.UndefinedType = hikari.UNDEFINED,
|
|
172
|
-
embeds: t.Sequence[hikari.Embed] | hikari.UndefinedType = hikari.UNDEFINED,
|
|
171
|
+
component: hikari.api.ComponentBuilder | hikari.UndefinedType | None = hikari.UNDEFINED,
|
|
172
|
+
components: t.Sequence[hikari.api.ComponentBuilder] | hikari.UndefinedType | None = hikari.UNDEFINED,
|
|
173
|
+
attachment: hikari.Resourceish | hikari.UndefinedType | None = hikari.UNDEFINED,
|
|
174
|
+
attachments: t.Sequence[hikari.Resourceish] | hikari.UndefinedType | None = hikari.UNDEFINED,
|
|
175
|
+
embed: hikari.Embed | hikari.UndefinedType | None = hikari.UNDEFINED,
|
|
176
|
+
embeds: t.Sequence[hikari.Embed] | hikari.UndefinedType | None = hikari.UNDEFINED,
|
|
173
177
|
mentions_everyone: bool | hikari.UndefinedType = hikari.UNDEFINED,
|
|
174
178
|
user_mentions: t.Sequence[hikari.Snowflakeish | hikari.PartialUser]
|
|
175
179
|
| bool
|
|
@@ -254,6 +258,7 @@ class Context(t.Generic[ClientT]):
|
|
|
254
258
|
"_created_at",
|
|
255
259
|
"_has_command_failed",
|
|
256
260
|
"_options",
|
|
261
|
+
"_injection_ctx",
|
|
257
262
|
)
|
|
258
263
|
|
|
259
264
|
def __init__(
|
|
@@ -261,6 +266,7 @@ class Context(t.Generic[ClientT]):
|
|
|
261
266
|
) -> None:
|
|
262
267
|
self._client = client
|
|
263
268
|
self._command = command
|
|
269
|
+
self._injection_ctx = alluka.OverridingContext.from_client(client.injector)
|
|
264
270
|
self._interaction: hikari.CommandInteraction = interaction
|
|
265
271
|
self._options: t.Sequence[hikari.CommandInteractionOption] | None = None
|
|
266
272
|
self._responses: t.MutableSequence[InteractionResponse] = []
|
|
@@ -413,40 +419,39 @@ class Context(t.Generic[ClientT]):
|
|
|
413
419
|
return self._interaction.get_channel()
|
|
414
420
|
|
|
415
421
|
@t.overload
|
|
416
|
-
def get_option(self, name: str, opt_type: t.Literal[OptionType.
|
|
417
|
-
...
|
|
422
|
+
def get_option(self, name: str, opt_type: t.Literal[OptionType.COLOR]) -> hikari.Color | None: ...
|
|
418
423
|
|
|
419
424
|
@t.overload
|
|
420
|
-
def get_option(self, name: str, opt_type: t.Literal[OptionType.
|
|
421
|
-
...
|
|
425
|
+
def get_option(self, name: str, opt_type: t.Literal[OptionType.MEMBER]) -> hikari.Member | None: ...
|
|
422
426
|
|
|
423
427
|
@t.overload
|
|
424
|
-
def get_option(self, name: str, opt_type: t.Literal[OptionType.
|
|
425
|
-
...
|
|
428
|
+
def get_option(self, name: str, opt_type: t.Literal[OptionType.ATTACHMENT]) -> hikari.Attachment | None: ...
|
|
426
429
|
|
|
427
430
|
@t.overload
|
|
428
|
-
def get_option(
|
|
429
|
-
|
|
431
|
+
def get_option(
|
|
432
|
+
self, name: str, opt_type: t.Literal[OptionType.MENTIONABLE]
|
|
433
|
+
) -> hikari.User | hikari.Role | None: ...
|
|
430
434
|
|
|
431
435
|
@t.overload
|
|
432
|
-
def get_option(self, name: str, opt_type: t.Literal[OptionType.
|
|
433
|
-
...
|
|
436
|
+
def get_option(self, name: str, opt_type: t.Literal[OptionType.USER]) -> hikari.User | None: ...
|
|
434
437
|
|
|
435
438
|
@t.overload
|
|
436
|
-
def get_option(self, name: str, opt_type: t.Literal[OptionType.
|
|
437
|
-
...
|
|
439
|
+
def get_option(self, name: str, opt_type: t.Literal[OptionType.ROLE]) -> hikari.Role | None: ...
|
|
438
440
|
|
|
439
441
|
@t.overload
|
|
440
|
-
def get_option(self, name: str, opt_type: t.Literal[OptionType.
|
|
441
|
-
...
|
|
442
|
+
def get_option(self, name: str, opt_type: t.Literal[OptionType.CHANNEL]) -> hikari.PartialChannel | None: ...
|
|
442
443
|
|
|
443
444
|
@t.overload
|
|
444
|
-
def get_option(self, name: str, opt_type: t.Literal[OptionType.
|
|
445
|
-
...
|
|
445
|
+
def get_option(self, name: str, opt_type: t.Literal[OptionType.STRING]) -> str | None: ...
|
|
446
446
|
|
|
447
447
|
@t.overload
|
|
448
|
-
def get_option(self, name: str, opt_type: t.Literal[OptionType.
|
|
449
|
-
|
|
448
|
+
def get_option(self, name: str, opt_type: t.Literal[OptionType.BOOLEAN]) -> bool | None: ...
|
|
449
|
+
|
|
450
|
+
@t.overload
|
|
451
|
+
def get_option(self, name: str, opt_type: t.Literal[OptionType.FLOAT]) -> float | None: ...
|
|
452
|
+
|
|
453
|
+
@t.overload
|
|
454
|
+
def get_option(self, name: str, opt_type: t.Literal[OptionType.INTEGER]) -> int | None: ...
|
|
450
455
|
|
|
451
456
|
def get_option(self, name: str, opt_type: OptionType) -> t.Any | None:
|
|
452
457
|
"""Get the value of an option by name.
|
|
@@ -530,6 +535,40 @@ class Context(t.Generic[ClientT]):
|
|
|
530
535
|
request = CustomLocaleRequest(self.command, locale, self, key)
|
|
531
536
|
return self._client._custom_locale_provider(request).format(**kwargs)
|
|
532
537
|
|
|
538
|
+
@t.overload
|
|
539
|
+
def get_type_dependency(self, type_: type[T]) -> T: ...
|
|
540
|
+
|
|
541
|
+
@t.overload
|
|
542
|
+
def get_type_dependency(self, type_: type[T], *, default: DefaultT) -> T | DefaultT: ...
|
|
543
|
+
|
|
544
|
+
def get_type_dependency(
|
|
545
|
+
self, type_: type[T], *, default: DefaultT | hikari.UndefinedType = hikari.UNDEFINED
|
|
546
|
+
) -> T | DefaultT:
|
|
547
|
+
"""Get a type dependency for the current context.
|
|
548
|
+
|
|
549
|
+
Parameters
|
|
550
|
+
----------
|
|
551
|
+
type_ : type[T]
|
|
552
|
+
The type of the dependency.
|
|
553
|
+
default : DefaultT
|
|
554
|
+
The default value to return if the dependency does not exist.
|
|
555
|
+
If not provided, this will raise an exception if the dependency does not exist.
|
|
556
|
+
|
|
557
|
+
Returns
|
|
558
|
+
-------
|
|
559
|
+
T | DefaultT
|
|
560
|
+
The instance of the dependency, if it exists, otherwise `default`.
|
|
561
|
+
|
|
562
|
+
Raises
|
|
563
|
+
------
|
|
564
|
+
KeyError
|
|
565
|
+
If the dependency does not exist and `default` was not provided.
|
|
566
|
+
"""
|
|
567
|
+
if default is hikari.UNDEFINED:
|
|
568
|
+
return self._injection_ctx.get_type_dependency(type_)
|
|
569
|
+
else:
|
|
570
|
+
return self._injection_ctx.get_type_dependency(type_, default=default)
|
|
571
|
+
|
|
533
572
|
async def get_last_response(self) -> InteractionResponse:
|
|
534
573
|
"""Get the last response issued to the interaction this context is proxying.
|
|
535
574
|
|
|
@@ -652,14 +691,12 @@ class Context(t.Generic[ClientT]):
|
|
|
652
691
|
return response
|
|
653
692
|
|
|
654
693
|
@t.overload
|
|
655
|
-
async def respond_with_builder(self, builder: hikari.api.InteractionModalBuilder) -> None:
|
|
656
|
-
...
|
|
694
|
+
async def respond_with_builder(self, builder: hikari.api.InteractionModalBuilder) -> None: ...
|
|
657
695
|
|
|
658
696
|
@t.overload
|
|
659
697
|
async def respond_with_builder(
|
|
660
698
|
self, builder: hikari.api.InteractionMessageBuilder | hikari.api.InteractionDeferredBuilder
|
|
661
|
-
) -> InteractionResponse:
|
|
662
|
-
...
|
|
699
|
+
) -> InteractionResponse: ...
|
|
663
700
|
|
|
664
701
|
async def respond_with_builder(self, builder: ResponseBuilderT) -> InteractionResponse | None:
|
|
665
702
|
"""Respond to the interaction with a builder. This method will try to turn the builder into a valid
|
arc/errors.py
CHANGED
|
@@ -7,6 +7,7 @@ if t.TYPE_CHECKING:
|
|
|
7
7
|
|
|
8
8
|
from arc.abc.concurrency_limiting import ConcurrencyLimiterProto
|
|
9
9
|
from arc.abc.limiter import LimiterProto
|
|
10
|
+
from arc.abc.option import ConverterOption
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class ArcError(Exception):
|
|
@@ -162,6 +163,23 @@ class GuildCommandPublishFailedError(CommandPublishFailedError):
|
|
|
162
163
|
super().__init__(*args)
|
|
163
164
|
|
|
164
165
|
|
|
166
|
+
class OptionConverterFailureError(ArcError):
|
|
167
|
+
"""Raised when an option converter fails to convert a value.
|
|
168
|
+
|
|
169
|
+
Attributes
|
|
170
|
+
----------
|
|
171
|
+
option : arc.abc.option.ConverterOption
|
|
172
|
+
The option that failed to convert the value.
|
|
173
|
+
value : t.Any
|
|
174
|
+
The value that failed to be converted.
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
def __init__(self, option: ConverterOption[t.Any, t.Any, t.Any, t.Any], value: t.Any, *args: t.Any) -> None:
|
|
178
|
+
self.option = option
|
|
179
|
+
self.value = value
|
|
180
|
+
super().__init__(*args)
|
|
181
|
+
|
|
182
|
+
|
|
165
183
|
# MIT License
|
|
166
184
|
#
|
|
167
185
|
# Copyright (c) 2023-present hypergonial
|
arc/extension.py
CHANGED
|
@@ -8,13 +8,11 @@ if t.TYPE_CHECKING:
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
@t.overload
|
|
11
|
-
def loader() -> t.Callable[[t.Callable[[ClientT], None]], t.Callable[[ClientT], None]]:
|
|
12
|
-
...
|
|
11
|
+
def loader() -> t.Callable[[t.Callable[[ClientT], None]], t.Callable[[ClientT], None]]: ...
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
@t.overload
|
|
16
|
-
def loader(callback: t.Callable[[ClientT], None]) -> t.Callable[[ClientT], None]:
|
|
17
|
-
...
|
|
15
|
+
def loader(callback: t.Callable[[ClientT], None]) -> t.Callable[[ClientT], None]: ...
|
|
18
16
|
|
|
19
17
|
|
|
20
18
|
def loader(
|
|
@@ -51,13 +49,11 @@ def loader(
|
|
|
51
49
|
|
|
52
50
|
|
|
53
51
|
@t.overload
|
|
54
|
-
def unloader() -> t.Callable[[t.Callable[[ClientT], None]], t.Callable[[ClientT], None]]:
|
|
55
|
-
...
|
|
52
|
+
def unloader() -> t.Callable[[t.Callable[[ClientT], None]], t.Callable[[ClientT], None]]: ...
|
|
56
53
|
|
|
57
54
|
|
|
58
55
|
@t.overload
|
|
59
|
-
def unloader(callback: t.Callable[[ClientT], None]) -> t.Callable[[ClientT], None]:
|
|
60
|
-
...
|
|
56
|
+
def unloader(callback: t.Callable[[ClientT], None]) -> t.Callable[[ClientT], None]: ...
|
|
61
57
|
|
|
62
58
|
|
|
63
59
|
def unloader(
|
arc/internal/about.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import typing as t
|
|
2
2
|
|
|
3
3
|
__author__: t.Final[str] = "hypergonial"
|
|
4
|
-
__author_email__: t.Final[str] = "
|
|
4
|
+
__author_email__: t.Final[str] = "git@hypergonial.com"
|
|
5
5
|
__maintainer__: t.Final[str] = "hypergonial"
|
|
6
6
|
__license__: t.Final[str] = "MIT"
|
|
7
7
|
__url__: t.Final[str] = "https://github.com/hypergonial/hikari-arc"
|
|
8
|
-
__version__: t.Final[str] = "1.
|
|
8
|
+
__version__: t.Final[str] = "1.3.0"
|
|
9
9
|
|
|
10
10
|
# MIT License
|
|
11
11
|
#
|
arc/internal/options.py
CHANGED
|
@@ -4,7 +4,7 @@ import typing as t
|
|
|
4
4
|
|
|
5
5
|
import hikari
|
|
6
6
|
|
|
7
|
-
from arc.abc.option import OptionType
|
|
7
|
+
from arc.abc.option import ConverterOption, OptionType
|
|
8
8
|
|
|
9
9
|
if t.TYPE_CHECKING:
|
|
10
10
|
from arc.abc.option import CommandOptionBase
|
|
@@ -21,6 +21,8 @@ OPTIONTYPE_TO_TYPE: dict[OptionType, type[t.Any]] = {
|
|
|
21
21
|
OptionType.MENTIONABLE: hikari.Unique,
|
|
22
22
|
OptionType.FLOAT: float,
|
|
23
23
|
OptionType.ATTACHMENT: hikari.Attachment,
|
|
24
|
+
OptionType.COLOR: hikari.Color,
|
|
25
|
+
OptionType.MEMBER: hikari.Member,
|
|
24
26
|
}
|
|
25
27
|
"""Used for runtime type checking in Context.get_option, not much else at the moment."""
|
|
26
28
|
|
|
@@ -89,18 +91,21 @@ def resolve_options(
|
|
|
89
91
|
"""
|
|
90
92
|
option_kwargs: dict[str, t.Any] = {}
|
|
91
93
|
|
|
92
|
-
for
|
|
94
|
+
for opt in local_options.values():
|
|
93
95
|
inter_opt = next((o for o in incoming_options if o.name == opt.name), None)
|
|
94
96
|
|
|
95
97
|
if inter_opt is None:
|
|
96
98
|
continue
|
|
97
99
|
|
|
98
100
|
if isinstance(inter_opt.value, hikari.Snowflake) and resolved:
|
|
99
|
-
option_kwargs[arg_name] = resolve_snowflake_value(inter_opt.value, inter_opt.type, resolved)
|
|
101
|
+
option_kwargs[opt.arg_name] = resolve_snowflake_value(inter_opt.value, inter_opt.type, resolved)
|
|
100
102
|
|
|
101
103
|
elif isinstance(inter_opt.value, hikari.Snowflake):
|
|
102
104
|
raise ValueError(f"Missing resolved option data for '{inter_opt.name}'.")
|
|
103
105
|
else:
|
|
104
|
-
option_kwargs[arg_name] = inter_opt.value
|
|
106
|
+
option_kwargs[opt.arg_name] = inter_opt.value
|
|
107
|
+
|
|
108
|
+
if isinstance(opt, ConverterOption):
|
|
109
|
+
option_kwargs[opt.arg_name] = opt._convert_value(option_kwargs[opt.arg_name]) # pyright: ignore
|
|
105
110
|
|
|
106
111
|
return option_kwargs
|
arc/internal/sigparse.py
CHANGED
|
@@ -15,10 +15,14 @@ from arc.command.option import (
|
|
|
15
15
|
BoolParams,
|
|
16
16
|
ChannelOption,
|
|
17
17
|
ChannelParams,
|
|
18
|
+
ColorOption,
|
|
19
|
+
ColorParams,
|
|
18
20
|
FloatOption,
|
|
19
21
|
FloatParams,
|
|
20
22
|
IntOption,
|
|
21
23
|
IntParams,
|
|
24
|
+
MemberOption,
|
|
25
|
+
MemberParams,
|
|
22
26
|
MentionableOption,
|
|
23
27
|
MentionableParams,
|
|
24
28
|
RoleOption,
|
|
@@ -46,6 +50,9 @@ TYPE_TO_OPTION_MAPPING: dict[type[t.Any], type[CommandOptionBase[t.Any, t.Any, t
|
|
|
46
50
|
float: FloatOption,
|
|
47
51
|
hikari.Role: RoleOption,
|
|
48
52
|
hikari.Attachment: AttachmentOption,
|
|
53
|
+
hikari.Member: MemberOption,
|
|
54
|
+
hikari.InteractionMember: MemberOption,
|
|
55
|
+
hikari.Color: ColorOption,
|
|
49
56
|
hikari.User: UserOption,
|
|
50
57
|
}
|
|
51
58
|
|
|
@@ -59,6 +66,8 @@ OPT_TO_PARAMS_MAPPING: dict[type[CommandOptionBase[t.Any, t.Any, t.Any]], type[t
|
|
|
59
66
|
MentionableOption: MentionableParams,
|
|
60
67
|
RoleOption: RoleParams,
|
|
61
68
|
AttachmentOption: AttachmentParams,
|
|
69
|
+
MemberOption: MemberParams,
|
|
70
|
+
ColorOption: ColorParams,
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
BASE_CHANNEL_TYPE_MAP: dict[type[hikari.PartialChannel], hikari.ChannelType] = {
|
|
@@ -305,15 +314,20 @@ def parse_command_signature( # noqa: C901
|
|
|
305
314
|
# If it's a union of channel types, we need to parse all channel types
|
|
306
315
|
if union is not None and any(arg in CHANNEL_TYPES_MAPPING for arg in t.get_args(union)):
|
|
307
316
|
channel_types = _parse_channel_union_type_hint(union)
|
|
308
|
-
options[arg_name] = ChannelOption._from_params(
|
|
309
|
-
name=params.name or arg_name,
|
|
317
|
+
options[params.name or arg_name] = ChannelOption._from_params(
|
|
318
|
+
name=params.name or arg_name,
|
|
319
|
+
arg_name=arg_name,
|
|
320
|
+
is_required=not is_optional,
|
|
321
|
+
params=params,
|
|
322
|
+
channel_types=channel_types,
|
|
310
323
|
)
|
|
311
324
|
continue
|
|
312
325
|
|
|
313
326
|
# If it's a single channel type, just pass the channel type
|
|
314
327
|
elif type_ in CHANNEL_TYPES_MAPPING:
|
|
315
|
-
options[arg_name] = ChannelOption._from_params(
|
|
328
|
+
options[params.name or arg_name] = ChannelOption._from_params(
|
|
316
329
|
name=params.name or arg_name,
|
|
330
|
+
arg_name=arg_name,
|
|
317
331
|
is_required=not is_optional,
|
|
318
332
|
params=params,
|
|
319
333
|
channel_types=_channels_to_channel_types([type_]),
|
|
@@ -321,8 +335,8 @@ def parse_command_signature( # noqa: C901
|
|
|
321
335
|
continue
|
|
322
336
|
|
|
323
337
|
# Otherwise just build the option
|
|
324
|
-
options[arg_name] = opt_type._from_params(
|
|
325
|
-
name=params.name or arg_name, is_required=not is_optional, params=params
|
|
338
|
+
options[params.name or arg_name] = opt_type._from_params(
|
|
339
|
+
name=params.name or arg_name, arg_name=arg_name, is_required=not is_optional, params=params
|
|
326
340
|
)
|
|
327
341
|
|
|
328
342
|
return options
|
arc/internal/sync.py
CHANGED
|
@@ -127,9 +127,9 @@ def _get_all_commands(
|
|
|
127
127
|
A mapping of guilds to command types to command names to commands that should be registered.
|
|
128
128
|
"""
|
|
129
129
|
# The big daddy of all mappings
|
|
130
|
-
mapping: dict[
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
mapping: dict[hikari.Snowflake | None, dict[hikari.CommandType, dict[str, CommandBase[t.Any, t.Any]]]] = (
|
|
131
|
+
defaultdict(lambda: defaultdict(lambda: defaultdict(dict))) # type: ignore
|
|
132
|
+
)
|
|
133
133
|
|
|
134
134
|
for command in itertools.chain(
|
|
135
135
|
client._slash_commands.values(), client._message_commands.values(), client._user_commands.values()
|
arc/internal/types.py
CHANGED
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import typing as t
|
|
4
4
|
|
|
5
5
|
if t.TYPE_CHECKING:
|
|
6
|
+
import alluka
|
|
6
7
|
import hikari
|
|
7
8
|
|
|
8
9
|
from arc.abc import Client, Hookable, HookResult, OptionParams
|
|
@@ -34,12 +35,13 @@ SlashCommandLike: t.TypeAlias = "SlashCommand[ClientT] | SlashGroup[ClientT]"
|
|
|
34
35
|
CommandCallbackT: t.TypeAlias = "t.Callable[t.Concatenate[Context[ClientT], ...], t.Awaitable[None]]"
|
|
35
36
|
MessageCommandCallbackT: t.TypeAlias = "t.Callable[[Context[ClientT], hikari.Message], t.Awaitable[None]]"
|
|
36
37
|
UserCommandCallbackT: t.TypeAlias = "t.Callable[[Context[ClientT], hikari.User], t.Awaitable[None]]"
|
|
37
|
-
AutocompleteCallbackT: t.TypeAlias = "t.Callable[[AutocompleteData[ClientT, ChoiceT]], t.Awaitable[t.Sequence[ChoiceT]]] | t.Callable[[AutocompleteData[ClientT, ChoiceT]], t.Awaitable[t.Sequence[hikari.api.AutocompleteChoiceBuilder]]]"
|
|
38
|
+
AutocompleteCallbackT: t.TypeAlias = "t.Callable[[AutocompleteData[ClientT, ChoiceT]], t.Awaitable[t.Sequence[ChoiceT]]] | t.Callable[[AutocompleteData[ClientT, ChoiceT]], t.Awaitable[t.Mapping[str, ChoiceT]]] | t.Callable[[AutocompleteData[ClientT, ChoiceT]], t.Awaitable[t.Sequence[hikari.api.AutocompleteChoiceBuilder]]]"
|
|
38
39
|
ResponseBuilderT: t.TypeAlias = (
|
|
39
40
|
"hikari.api.InteractionMessageBuilder | hikari.api.InteractionDeferredBuilder | hikari.api.InteractionModalBuilder"
|
|
40
41
|
)
|
|
41
42
|
HookT: t.TypeAlias = "t.Callable[[Context[ClientT]], t.Awaitable[HookResult]] | t.Callable[[Context[ClientT]], HookResult] | t.Callable[[Context[ClientT]], None] | t.Callable[[Context[ClientT]], t.Awaitable[None]]"
|
|
42
43
|
PostHookT: t.TypeAlias = "t.Callable[[Context[ClientT]], None] | t.Callable[[Context[ClientT]], t.Awaitable[None]]"
|
|
44
|
+
InjectionHookT: t.TypeAlias = "t.Callable[[Context[ClientT], alluka.OverridingContext], None] | t.Callable[[Context[ClientT], alluka.OverridingContext], t.Awaitable[None]]"
|
|
43
45
|
LifeCycleHookT: t.TypeAlias = "t.Callable[[ClientT], t.Awaitable[None]]"
|
|
44
46
|
CommandLocaleRequestT: t.TypeAlias = "t.Callable[[CommandLocaleRequest], LocaleResponse]"
|
|
45
47
|
OptionLocaleRequestT: t.TypeAlias = "t.Callable[[OptionLocaleRequest], LocaleResponse]"
|
arc/utils/concurrency_limiter.py
CHANGED
|
@@ -166,7 +166,7 @@ class ConcurrencyLimiter(t.Generic[KeyT]):
|
|
|
166
166
|
This will block until a slot is available.
|
|
167
167
|
"""
|
|
168
168
|
key = self._get_key(item)
|
|
169
|
-
bucket = self._buckets.setdefault(key, _Bucket.for_limiter(key, self))
|
|
169
|
+
bucket = self._buckets.setdefault(key, _Bucket.for_limiter(key, self)) # pyright: ignore reportUnknowMemberType
|
|
170
170
|
await bucket.semaphore.acquire()
|
|
171
171
|
|
|
172
172
|
def release(self, item: KeyT) -> None:
|
|
@@ -243,9 +243,14 @@ class CommandConcurrencyLimiter(ConcurrencyLimiter[Context[ClientT]], Concurrenc
|
|
|
243
243
|
return super().__call__(item)
|
|
244
244
|
|
|
245
245
|
|
|
246
|
-
def global_concurrency() -> CommandConcurrencyLimiter[t.Any]:
|
|
246
|
+
def global_concurrency(limit: int) -> CommandConcurrencyLimiter[t.Any]:
|
|
247
247
|
"""Limit a command to a certain amount of concurrent instances globally.
|
|
248
248
|
|
|
249
|
+
Parameters
|
|
250
|
+
----------
|
|
251
|
+
limit : int
|
|
252
|
+
The maximum amount of concurrently running command instances.
|
|
253
|
+
|
|
249
254
|
Returns
|
|
250
255
|
-------
|
|
251
256
|
CommandConcurrencyLimiter[t.Any]
|
|
@@ -254,10 +259,10 @@ def global_concurrency() -> CommandConcurrencyLimiter[t.Any]:
|
|
|
254
259
|
Examples
|
|
255
260
|
--------
|
|
256
261
|
```py
|
|
257
|
-
@arc.with_concurrency_limit(arc.global_concurrency())
|
|
262
|
+
@arc.with_concurrency_limit(arc.global_concurrency(1))
|
|
258
263
|
```
|
|
259
264
|
"""
|
|
260
|
-
return CommandConcurrencyLimiter(
|
|
265
|
+
return CommandConcurrencyLimiter(limit, get_key_with=lambda _: "amongus")
|
|
261
266
|
|
|
262
267
|
|
|
263
268
|
def guild_concurrency(limit: int) -> CommandConcurrencyLimiter[t.Any]:
|
arc/utils/ratelimiter.py
CHANGED
|
@@ -184,7 +184,7 @@ class RateLimiter(t.Generic[KeyT]):
|
|
|
184
184
|
|
|
185
185
|
key = self.get_key(item)
|
|
186
186
|
# Get existing or insert new bucket
|
|
187
|
-
bucket = self._buckets.setdefault(key, _Bucket.for_limiter(key, self))
|
|
187
|
+
bucket = self._buckets.setdefault(key, _Bucket.for_limiter(key, self)) # pyright: ignore reportUnknowMemberType
|
|
188
188
|
|
|
189
189
|
if bucket.is_exhausted and not wait:
|
|
190
190
|
raise RateLimiterExhaustedError(
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hikari-arc
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: A command handler for hikari with a focus on type-safety and correctness.
|
|
5
5
|
Home-page: https://github.com/hypergonial/hikari-arc
|
|
6
6
|
Author: hypergonial
|
|
7
|
-
Author-email:
|
|
7
|
+
Author-email: git@hypergonial.com
|
|
8
8
|
Maintainer: hypergonial
|
|
9
9
|
License: MIT
|
|
10
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
@@ -24,27 +24,27 @@ Requires-Python: >=3.10.0,<3.13
|
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
26
26
|
Requires-Dist: hikari >=2.0.0.dev122
|
|
27
|
-
Requires-Dist: alluka
|
|
27
|
+
Requires-Dist: alluka <0.4,>=0.3.0
|
|
28
28
|
Requires-Dist: attrs >=23.1
|
|
29
29
|
Requires-Dist: colorama ; sys_platform=="win32"
|
|
30
30
|
Provides-Extra: cron
|
|
31
|
-
Requires-Dist: croniter ==2.0.
|
|
32
|
-
Requires-Dist: types-croniter ==2.0.0.
|
|
31
|
+
Requires-Dist: croniter ==2.0.5 ; extra == 'cron'
|
|
32
|
+
Requires-Dist: types-croniter ==2.0.0.20240423 ; extra == 'cron'
|
|
33
33
|
Provides-Extra: dev
|
|
34
|
-
Requires-Dist: ruff ==0.
|
|
35
|
-
Requires-Dist: pyright ==1.1.
|
|
36
|
-
Requires-Dist: nox ==
|
|
37
|
-
Requires-Dist: typing-extensions ==4.
|
|
38
|
-
Requires-Dist: pytest ==
|
|
39
|
-
Requires-Dist: pytest-asyncio ==0.23.
|
|
40
|
-
Requires-Dist: slotscheck ==0.
|
|
34
|
+
Requires-Dist: ruff ==0.4.4 ; extra == 'dev'
|
|
35
|
+
Requires-Dist: pyright ==1.1.362 ; extra == 'dev'
|
|
36
|
+
Requires-Dist: nox ==2024.4.15 ; extra == 'dev'
|
|
37
|
+
Requires-Dist: typing-extensions ==4.11.0 ; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest ==8.2.0 ; extra == 'dev'
|
|
39
|
+
Requires-Dist: pytest-asyncio ==0.23.6 ; extra == 'dev'
|
|
40
|
+
Requires-Dist: slotscheck ==0.19.0 ; extra == 'dev'
|
|
41
41
|
Provides-Extra: docs
|
|
42
|
-
Requires-Dist: mkdocs-material[imaging] ~=9.5.
|
|
43
|
-
Requires-Dist: mkdocs ~=1.
|
|
44
|
-
Requires-Dist: mkdocstrings-python ~=1.
|
|
45
|
-
Requires-Dist: black ~=
|
|
42
|
+
Requires-Dist: mkdocs-material[imaging] ~=9.5.21 ; extra == 'docs'
|
|
43
|
+
Requires-Dist: mkdocs ~=1.6.0 ; extra == 'docs'
|
|
44
|
+
Requires-Dist: mkdocstrings-python ~=1.10.0 ; extra == 'docs'
|
|
45
|
+
Requires-Dist: black ~=24.4.2 ; extra == 'docs'
|
|
46
46
|
Requires-Dist: griffe-inherited-docstrings ~=1.0.0 ; extra == 'docs'
|
|
47
|
-
Requires-Dist: mkdocs-glightbox ~=0.
|
|
47
|
+
Requires-Dist: mkdocs-glightbox ~=0.4.0 ; extra == 'docs'
|
|
48
48
|
Provides-Extra: rest
|
|
49
49
|
Requires-Dist: hikari[server] >=2.0.0.dev122 ; extra == 'rest'
|
|
50
50
|
|