hikari-arc 1.2.1__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 CHANGED
@@ -9,6 +9,7 @@ https://arc.hypergonial.com
9
9
  """
10
10
 
11
11
  from alluka import Client as Injector
12
+ from alluka import OverridingContext as InjectorOverridingContext
12
13
  from alluka import inject
13
14
 
14
15
  from arc import abc, command, ext, utils
@@ -28,8 +29,11 @@ from .command import (
28
29
  AttachmentParams,
29
30
  BoolParams,
30
31
  ChannelParams,
32
+ ColorParams,
33
+ ColourParams,
31
34
  FloatParams,
32
35
  IntParams,
36
+ MemberParams,
33
37
  MentionableParams,
34
38
  MessageCommand,
35
39
  RoleParams,
@@ -65,6 +69,7 @@ from .errors import (
65
69
  MaxConcurrencyReachedError,
66
70
  NoResponseIssuedError,
67
71
  NotOwnerError,
72
+ OptionConverterFailureError,
68
73
  ResponseAlreadyIssuedError,
69
74
  UnderCooldownError,
70
75
  )
@@ -113,7 +118,7 @@ __all__ = (
113
118
  "AutocompleteData",
114
119
  "Option",
115
120
  "Context",
116
- "Context",
121
+ "InjectorOverridingContext",
117
122
  "BoolParams",
118
123
  "IntParams",
119
124
  "StrParams",
@@ -123,6 +128,9 @@ __all__ = (
123
128
  "RoleParams",
124
129
  "MentionableParams",
125
130
  "AttachmentParams",
131
+ "MemberParams",
132
+ "ColorParams",
133
+ "ColourParams",
126
134
  "SlashCommand",
127
135
  "SlashGroup",
128
136
  "SlashSubCommand",
@@ -158,6 +166,7 @@ __all__ = (
158
166
  "ExtensionUnloadError",
159
167
  "HookAbortError",
160
168
  "InteractionResponseError",
169
+ "OptionConverterFailureError",
161
170
  "PluginBase",
162
171
  "RESTPluginBase",
163
172
  "GatewayPluginBase",
arc/__main__.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """CLI entry point for arc."""
2
+
2
3
  import os
3
4
  import platform
4
5
  import sys
arc/abc/__init__.py CHANGED
@@ -8,6 +8,7 @@ from .hookable import Hookable, HookResult, with_hook, with_post_hook
8
8
  from .limiter import LimiterProto
9
9
  from .option import (
10
10
  CommandOptionBase,
11
+ ConverterOption,
11
12
  Option,
12
13
  OptionBase,
13
14
  OptionParams,
@@ -29,6 +30,7 @@ __all__ = (
29
30
  "OptionBase",
30
31
  "OptionType",
31
32
  "CommandOptionBase",
33
+ "ConverterOption",
32
34
  "OptionParams",
33
35
  "OptionWithChoices",
34
36
  "OptionWithChoicesParams",
arc/abc/client.py CHANGED
@@ -22,6 +22,7 @@ from arc.command.slash import SlashCommand, SlashGroup, SlashSubCommand, SlashSu
22
22
  from arc.command.user import UserCommand
23
23
  from arc.context import AutodeferMode, Context
24
24
  from arc.errors import ExtensionLoadError, ExtensionUnloadError
25
+ from arc.internal.deprecation import warn_deprecate
25
26
  from arc.internal.sync import _sync_commands
26
27
  from arc.internal.types import (
27
28
  AppT,
@@ -30,11 +31,13 @@ from arc.internal.types import (
30
31
  CustomLocaleRequestT,
31
32
  ErrorHandlerCallbackT,
32
33
  HookT,
34
+ InjectionHookT,
33
35
  LifeCycleHookT,
34
36
  OptionLocaleRequestT,
35
37
  PostHookT,
36
38
  ResponseBuilderT,
37
39
  )
40
+ from arc.internal.version import Version
38
41
  from arc.locale import CommandLocaleRequest, LocaleResponse, OptionLocaleRequest
39
42
 
40
43
  if t.TYPE_CHECKING:
@@ -98,10 +101,11 @@ class Client(t.Generic[AppT], abc.ABC):
98
101
  "_loaded_extensions",
99
102
  "_hooks",
100
103
  "_post_hooks",
104
+ "_injection_hooks",
101
105
  "_owner_ids",
102
106
  "_error_handler",
103
- "_startup_hook",
104
- "_shutdown_hook",
107
+ "_startup_hooks",
108
+ "_shutdown_hooks",
105
109
  "_provided_locales",
106
110
  "_command_locale_provider",
107
111
  "_option_locale_provider",
@@ -149,14 +153,15 @@ class Client(t.Generic[AppT], abc.ABC):
149
153
  self._loaded_extensions: list[str] = []
150
154
  self._hooks: list[HookT[te.Self]] = []
151
155
  self._post_hooks: list[PostHookT[te.Self]] = []
156
+ self._injection_hooks: list[InjectionHookT[te.Self]] = []
152
157
  self._owner_ids: list[hikari.Snowflake] = []
153
158
  self._tasks: set[asyncio.Task[t.Any]] = set()
154
159
  self._started: asyncio.Event = asyncio.Event()
155
160
  self._application: hikari.Application | None = None
156
161
  self._error_handler: ErrorHandlerCallbackT[te.Self] | None = None
157
162
  self._concurrency_limiter: ConcurrencyLimiterProto[te.Self] | None = None
158
- self._startup_hook: LifeCycleHookT[te.Self] | None = None
159
- self._shutdown_hook: LifeCycleHookT[te.Self] | None = None
163
+ self._startup_hooks: list[LifeCycleHookT[te.Self] | None] = [None]
164
+ self._shutdown_hooks: list[LifeCycleHookT[te.Self] | None] = [None]
160
165
  self._command_locale_provider: CommandLocaleRequestT | None = None
161
166
  self._option_locale_provider: OptionLocaleRequestT | None = None
162
167
  self._custom_locale_provider: CustomLocaleRequestT | None = None
@@ -285,8 +290,13 @@ class Client(t.Generic[AppT], abc.ABC):
285
290
  await _sync_commands(self)
286
291
 
287
292
  try:
288
- if self._startup_hook:
289
- await self._startup_hook(self)
293
+ for hook in self._startup_hooks:
294
+ if hook:
295
+ try:
296
+ await hook(self)
297
+ except Exception as e:
298
+ logger.error(f"Error in startup hook '{hook.__name__}': {e}")
299
+ traceback.print_exc()
290
300
  finally:
291
301
  self._started.set()
292
302
 
@@ -294,8 +304,16 @@ class Client(t.Generic[AppT], abc.ABC):
294
304
  """Called when the client is shutting down.
295
305
  Reserved for internal shutdown logic.
296
306
  """
297
- if self._shutdown_hook:
298
- await self._shutdown_hook(self)
307
+ for hook in self._shutdown_hooks:
308
+ if hook:
309
+ try:
310
+ await hook(self)
311
+ except Exception as e:
312
+ logger.error(f"Error in shutdown hook '{hook.__name__}': {e}")
313
+ traceback.print_exc()
314
+
315
+ for task in self._tasks:
316
+ task.cancel()
299
317
 
300
318
  async def _on_error(self, ctx: Context[te.Self], exception: Exception) -> None:
301
319
  if self._error_handler is not None:
@@ -311,6 +329,16 @@ class Client(t.Generic[AppT], abc.ABC):
311
329
  if ctx.is_valid:
312
330
  await ctx.respond("❌ Something went wrong. Please contact the bot developer.")
313
331
 
332
+ async def _create_overriding_ctx_for_command(self, ctx: Context[te.Self]) -> alluka.OverridingContext:
333
+ inj_ctx = alluka.OverridingContext.from_client(self.injector)
334
+
335
+ for hook in self._injection_hooks:
336
+ if inspect.iscoroutinefunction(hook):
337
+ await hook(ctx, inj_ctx)
338
+ else:
339
+ hook(ctx, inj_ctx)
340
+ return inj_ctx
341
+
314
342
  def _provide_command_locale(self, request: CommandLocaleRequest) -> LocaleResponse:
315
343
  """Provide a locale for a command."""
316
344
  if self._command_locale_provider is None:
@@ -417,26 +445,24 @@ class Client(t.Generic[AppT], abc.ABC):
417
445
  @t.overload
418
446
  def walk_commands(
419
447
  self, command_type: t.Literal[hikari.CommandType.USER], *, callable_only: bool = False
420
- ) -> t.Iterator[UserCommand[te.Self]]:
421
- ...
448
+ ) -> t.Iterator[UserCommand[te.Self]]: ...
422
449
 
423
450
  @t.overload
424
451
  def walk_commands(
425
452
  self, command_type: t.Literal[hikari.CommandType.MESSAGE], *, callable_only: bool = False
426
- ) -> t.Iterator[MessageCommand[te.Self]]:
427
- ...
453
+ ) -> t.Iterator[MessageCommand[te.Self]]: ...
428
454
 
429
455
  @t.overload
430
456
  def walk_commands(
431
457
  self, command_type: t.Literal[hikari.CommandType.SLASH], *, callable_only: t.Literal[False] = False
432
- ) -> t.Iterator[SlashCommand[te.Self] | SlashSubCommand[te.Self] | SlashGroup[te.Self] | SlashSubGroup[te.Self]]:
433
- ...
458
+ ) -> t.Iterator[
459
+ SlashCommand[te.Self] | SlashSubCommand[te.Self] | SlashGroup[te.Self] | SlashSubGroup[te.Self]
460
+ ]: ...
434
461
 
435
462
  @t.overload
436
463
  def walk_commands(
437
464
  self, command_type: t.Literal[hikari.CommandType.SLASH], *, callable_only: t.Literal[True] = True
438
- ) -> t.Iterator[SlashCommand[te.Self] | SlashSubCommand[te.Self]]:
439
- ...
465
+ ) -> t.Iterator[SlashCommand[te.Self] | SlashSubCommand[te.Self]]: ...
440
466
 
441
467
  def walk_commands( # noqa: C901
442
468
  self, command_type: hikari.CommandType, *, callable_only: bool = False
@@ -507,12 +533,12 @@ class Client(t.Generic[AppT], abc.ABC):
507
533
  yield command
508
534
 
509
535
  @t.overload
510
- def include(self) -> t.Callable[[CallableCommandBase[te.Self, BuilderT]], CallableCommandBase[te.Self, BuilderT]]:
511
- ...
536
+ def include(
537
+ self,
538
+ ) -> t.Callable[[CallableCommandBase[te.Self, BuilderT]], CallableCommandBase[te.Self, BuilderT]]: ...
512
539
 
513
540
  @t.overload
514
- def include(self, command: CallableCommandBase[te.Self, BuilderT]) -> CallableCommandBase[te.Self, BuilderT]:
515
- ...
541
+ def include(self, command: CallableCommandBase[te.Self, BuilderT]) -> CallableCommandBase[te.Self, BuilderT]: ...
516
542
 
517
543
  def include(
518
544
  self, command: CallableCommandBase[te.Self, BuilderT] | None = None
@@ -703,12 +729,10 @@ class Client(t.Generic[AppT], abc.ABC):
703
729
  return self
704
730
 
705
731
  @t.overload
706
- def add_hook(self, hook: HookT[te.Self]) -> te.Self:
707
- ...
732
+ def add_hook(self, hook: HookT[te.Self]) -> te.Self: ...
708
733
 
709
734
  @t.overload
710
- def add_hook(self) -> t.Callable[[HookT[te.Self]], HookT[te.Self]]:
711
- ...
735
+ def add_hook(self) -> t.Callable[[HookT[te.Self]], HookT[te.Self]]: ...
712
736
 
713
737
  def add_hook(self, hook: HookT[te.Self] | None = None) -> te.Self | t.Callable[[HookT[te.Self]], HookT[te.Self]]:
714
738
  """Add a pre-execution hook to this client.
@@ -739,12 +763,10 @@ class Client(t.Generic[AppT], abc.ABC):
739
763
  return decorator
740
764
 
741
765
  @t.overload
742
- def add_post_hook(self, hook: PostHookT[te.Self]) -> te.Self:
743
- ...
766
+ def add_post_hook(self, hook: PostHookT[te.Self]) -> te.Self: ...
744
767
 
745
768
  @t.overload
746
- def add_post_hook(self) -> t.Callable[[PostHookT[te.Self]], PostHookT[te.Self]]:
747
- ...
769
+ def add_post_hook(self) -> t.Callable[[PostHookT[te.Self]], PostHookT[te.Self]]: ...
748
770
 
749
771
  def add_post_hook(
750
772
  self, hook: PostHookT[te.Self] | None = None
@@ -780,12 +802,76 @@ class Client(t.Generic[AppT], abc.ABC):
780
802
  return decorator
781
803
 
782
804
  @t.overload
783
- def set_error_handler(self, handler: ErrorHandlerCallbackT[te.Self]) -> te.Self:
784
- ...
805
+ def add_injection_hook(self, hook: InjectionHookT[te.Self]) -> te.Self: ...
785
806
 
786
807
  @t.overload
787
- def set_error_handler(self) -> t.Callable[[ErrorHandlerCallbackT[te.Self]], te.Self]:
788
- ...
808
+ def add_injection_hook(self) -> t.Callable[[InjectionHookT[te.Self]], InjectionHookT[te.Self]]: ...
809
+
810
+ def add_injection_hook(
811
+ self, hook: InjectionHookT[te.Self] | None = None
812
+ ) -> te.Self | t.Callable[[InjectionHookT[te.Self]], InjectionHookT[te.Self]]:
813
+ """Add an injection hook to this client.
814
+ This hook will be called when a command is called, and an OverridingContext is passed, allowing you to inject dependencies for the command call.
815
+
816
+ Parameters
817
+ ----------
818
+ hook : InjectionHookT[te.Self]
819
+ The hook to add.
820
+
821
+ Returns
822
+ -------
823
+ te.Self
824
+ The client for chaining calls.
825
+
826
+ Example
827
+ -------
828
+ ```py
829
+ @client.add_injection_hook
830
+ async def inject(ctx: arc.GatewayContext, inj_ctx: arc.InjectorOverridingContext) -> None:
831
+ foo: MyType = example_data[ctx.guild_id]
832
+ inj_ctx.set_type_dependency(MyType, foo)
833
+ ```
834
+
835
+ See Also
836
+ --------
837
+ - [`Client.set_type_dependency`][arc.client.Client.set_type_dependency]
838
+ """
839
+ if hook is not None:
840
+ self._injection_hooks.append(hook)
841
+ return self
842
+
843
+ def decorator(hook: InjectionHookT[te.Self]) -> InjectionHookT[te.Self]:
844
+ self._injection_hooks.append(hook)
845
+ return hook
846
+
847
+ return decorator
848
+
849
+ def remove_injection_hook(self, hook: InjectionHookT[te.Self]) -> te.Self:
850
+ """Remove an injection hook from this client.
851
+
852
+ Parameters
853
+ ----------
854
+ hook : InjectionHookT[te.Self]
855
+ The hook to remove.
856
+
857
+ Returns
858
+ -------
859
+ te.Self
860
+ The client for chaining calls.
861
+
862
+ Raises
863
+ ------
864
+ ValueError
865
+ If the hook is not registered with this client.
866
+ """
867
+ self._injection_hooks.remove(hook)
868
+ return self
869
+
870
+ @t.overload
871
+ def set_error_handler(self, handler: ErrorHandlerCallbackT[te.Self]) -> te.Self: ...
872
+
873
+ @t.overload
874
+ def set_error_handler(self) -> t.Callable[[ErrorHandlerCallbackT[te.Self]], te.Self]: ...
789
875
 
790
876
  def set_error_handler(
791
877
  self, handler: ErrorHandlerCallbackT[te.Self] | None = None
@@ -834,12 +920,104 @@ class Client(t.Generic[AppT], abc.ABC):
834
920
  return decorator
835
921
 
836
922
  @t.overload
837
- def set_startup_hook(self, hook: LifeCycleHookT[te.Self]) -> te.Self:
838
- ...
923
+ def add_startup_hook(self, hook: LifeCycleHookT[te.Self]) -> te.Self: ...
924
+
925
+ @t.overload
926
+ def add_startup_hook(self) -> t.Callable[[LifeCycleHookT[te.Self]], te.Self]: ...
927
+
928
+ def add_startup_hook(
929
+ self, hook: LifeCycleHookT[te.Self] | None = None
930
+ ) -> te.Self | t.Callable[[LifeCycleHookT[te.Self]], te.Self]:
931
+ """Decorator to add a startup hook for this client.
932
+
933
+ This will be called when the client starts up.
934
+
935
+ Parameters
936
+ ----------
937
+ hook : LifeCycleHookT[te.Self]
938
+ The startup hook to add.
939
+
940
+ Returns
941
+ -------
942
+ te.Self
943
+ The client for chaining calls.
944
+
945
+ Examples
946
+ --------
947
+ ```py
948
+ @client.add_startup_hook
949
+ async def startup_hook(client: arc.GatewayClient) -> None:
950
+ print("Client started up!")
951
+ ```
952
+
953
+ Or, as a function:
954
+
955
+ ```py
956
+ client.add_startup_hook(startup_hook)
957
+ ```
958
+ """
959
+
960
+ def decorator(handler: LifeCycleHookT[te.Self]) -> te.Self:
961
+ self._startup_hooks.append(handler)
962
+ return self
963
+
964
+ if hook is not None:
965
+ return decorator(hook)
966
+
967
+ return decorator
968
+
969
+ @t.overload
970
+ def add_shutdown_hook(self, hook: LifeCycleHookT[te.Self]) -> te.Self: ...
839
971
 
840
972
  @t.overload
841
- def set_startup_hook(self) -> t.Callable[[LifeCycleHookT[te.Self]], te.Self]:
842
- ...
973
+ def add_shutdown_hook(self) -> t.Callable[[LifeCycleHookT[te.Self]], te.Self]: ...
974
+
975
+ def add_shutdown_hook(
976
+ self, hook: LifeCycleHookT[te.Self] | None = None
977
+ ) -> te.Self | t.Callable[[LifeCycleHookT[te.Self]], te.Self]:
978
+ """Decorator to add a shutdown hook for this client.
979
+
980
+ This will be called when the client shuts down.
981
+
982
+ Parameters
983
+ ----------
984
+ hook : LifeCycleHookT[te.Self]
985
+ The shutdown hook to add.
986
+
987
+ Returns
988
+ -------
989
+ te.Self
990
+ The client for chaining calls.
991
+
992
+ Examples
993
+ --------
994
+ ```py
995
+ @client.add_shutdown_hook
996
+ async def shutdown_hook(client: arc.GatewayClient) -> None:
997
+ print("Client shut down!")
998
+ ```
999
+
1000
+ Or, as a function:
1001
+
1002
+ ```py
1003
+ client.add_shutdown_hook(shutdown_hook)
1004
+ ```
1005
+ """
1006
+
1007
+ def decorator(handler: LifeCycleHookT[te.Self]) -> te.Self:
1008
+ self._shutdown_hooks.append(handler)
1009
+ return self
1010
+
1011
+ if hook is not None:
1012
+ return decorator(hook)
1013
+
1014
+ return decorator
1015
+
1016
+ @t.overload
1017
+ def set_startup_hook(self, hook: LifeCycleHookT[te.Self]) -> te.Self: ...
1018
+
1019
+ @t.overload
1020
+ def set_startup_hook(self) -> t.Callable[[LifeCycleHookT[te.Self]], te.Self]: ...
843
1021
 
844
1022
  def set_startup_hook(
845
1023
  self, hook: LifeCycleHookT[te.Self] | None = None
@@ -848,6 +1026,10 @@ class Client(t.Generic[AppT], abc.ABC):
848
1026
 
849
1027
  This will be called when the client starts up.
850
1028
 
1029
+ !!! warning "Deprecation Notice"
1030
+ This method is deprecated and will be removed in version `2.0.0`.
1031
+ Use [`Client.add_startup_hook`][arc.client.Client.add_startup_hook] instead.
1032
+
851
1033
  Parameters
852
1034
  ----------
853
1035
  hook : LifeCycleHookT[te.Self]
@@ -872,9 +1054,10 @@ class Client(t.Generic[AppT], abc.ABC):
872
1054
  client.set_startup_hook(startup_hook)
873
1055
  ```
874
1056
  """
1057
+ warn_deprecate(what="set_startup_hook", when=Version(2, 0, 0), use_instead="add_startup_hook")
875
1058
 
876
1059
  def decorator(handler: LifeCycleHookT[te.Self]) -> te.Self:
877
- self._startup_hook = handler
1060
+ self._startup_hooks[0] = handler
878
1061
  return self
879
1062
 
880
1063
  if hook is not None:
@@ -883,12 +1066,10 @@ class Client(t.Generic[AppT], abc.ABC):
883
1066
  return decorator
884
1067
 
885
1068
  @t.overload
886
- def set_shutdown_hook(self, hook: LifeCycleHookT[te.Self]) -> te.Self:
887
- ...
1069
+ def set_shutdown_hook(self, hook: LifeCycleHookT[te.Self]) -> te.Self: ...
888
1070
 
889
1071
  @t.overload
890
- def set_shutdown_hook(self) -> t.Callable[[LifeCycleHookT[te.Self]], te.Self]:
891
- ...
1072
+ def set_shutdown_hook(self) -> t.Callable[[LifeCycleHookT[te.Self]], te.Self]: ...
892
1073
 
893
1074
  def set_shutdown_hook(
894
1075
  self, hook: LifeCycleHookT[te.Self] | None = None
@@ -897,6 +1078,10 @@ class Client(t.Generic[AppT], abc.ABC):
897
1078
 
898
1079
  This will be called when the client shuts down.
899
1080
 
1081
+ !!! warning "Deprecation Notice"
1082
+ This method is deprecated and will be removed in version `2.0.0`.
1083
+ Use [`Client.add_shutdown_hook`][arc.client.Client.add_shutdown_hook] instead.
1084
+
900
1085
  Parameters
901
1086
  ----------
902
1087
  hook : LifeCycleHookT[te.Self]
@@ -921,9 +1106,10 @@ class Client(t.Generic[AppT], abc.ABC):
921
1106
  client.set_shutdown_hook(shutdown_hook)
922
1107
  ```
923
1108
  """
1109
+ warn_deprecate(what="set_shutdown_hook", when=Version(2, 0, 0), use_instead="add_shutdown_hook")
924
1110
 
925
1111
  def decorator(handler: LifeCycleHookT[te.Self]) -> te.Self:
926
- self._shutdown_hook = handler
1112
+ self._shutdown_hooks[0] = handler
927
1113
  return self
928
1114
 
929
1115
  if hook is not None:
@@ -932,12 +1118,10 @@ class Client(t.Generic[AppT], abc.ABC):
932
1118
  return decorator
933
1119
 
934
1120
  @t.overload
935
- def set_command_locale_provider(self, provider: CommandLocaleRequestT) -> te.Self:
936
- ...
1121
+ def set_command_locale_provider(self, provider: CommandLocaleRequestT) -> te.Self: ...
937
1122
 
938
1123
  @t.overload
939
- def set_command_locale_provider(self) -> t.Callable[[CommandLocaleRequestT], te.Self]:
940
- ...
1124
+ def set_command_locale_provider(self) -> t.Callable[[CommandLocaleRequestT], te.Self]: ...
941
1125
 
942
1126
  def set_command_locale_provider(
943
1127
  self, provider: CommandLocaleRequestT | None = None
@@ -981,12 +1165,10 @@ class Client(t.Generic[AppT], abc.ABC):
981
1165
  return decorator
982
1166
 
983
1167
  @t.overload
984
- def set_option_locale_provider(self, provider: OptionLocaleRequestT) -> te.Self:
985
- ...
1168
+ def set_option_locale_provider(self, provider: OptionLocaleRequestT) -> te.Self: ...
986
1169
 
987
1170
  @t.overload
988
- def set_option_locale_provider(self) -> t.Callable[[OptionLocaleRequestT], te.Self]:
989
- ...
1171
+ def set_option_locale_provider(self) -> t.Callable[[OptionLocaleRequestT], te.Self]: ...
990
1172
 
991
1173
  def set_option_locale_provider(
992
1174
  self, provider: OptionLocaleRequestT | None = None
@@ -1030,12 +1212,10 @@ class Client(t.Generic[AppT], abc.ABC):
1030
1212
  return decorator
1031
1213
 
1032
1214
  @t.overload
1033
- def set_custom_locale_provider(self, provider: CustomLocaleRequestT) -> te.Self:
1034
- ...
1215
+ def set_custom_locale_provider(self, provider: CustomLocaleRequestT) -> te.Self: ...
1035
1216
 
1036
1217
  @t.overload
1037
- def set_custom_locale_provider(self) -> t.Callable[[CustomLocaleRequestT], te.Self]:
1038
- ...
1218
+ def set_custom_locale_provider(self) -> t.Callable[[CustomLocaleRequestT], te.Self]: ...
1039
1219
 
1040
1220
  def set_custom_locale_provider(
1041
1221
  self, provider: CustomLocaleRequestT | None = None
@@ -1285,12 +1465,10 @@ class Client(t.Generic[AppT], abc.ABC):
1285
1465
  return self
1286
1466
 
1287
1467
  @t.overload
1288
- def get_type_dependency(self, type_: type[T]) -> T:
1289
- ...
1468
+ def get_type_dependency(self, type_: type[T]) -> T: ...
1290
1469
 
1291
1470
  @t.overload
1292
- def get_type_dependency(self, type_: type[T], *, default: DefaultT) -> T | DefaultT:
1293
- ...
1471
+ def get_type_dependency(self, type_: type[T], *, default: DefaultT) -> T | DefaultT: ...
1294
1472
 
1295
1473
  def get_type_dependency(
1296
1474
  self, type_: type[T], *, default: DefaultT | hikari.UndefinedType = hikari.UNDEFINED
@@ -1316,20 +1494,15 @@ class Client(t.Generic[AppT], abc.ABC):
1316
1494
  If the dependency does not exist and `default` was not provided.
1317
1495
  """
1318
1496
  if default is hikari.UNDEFINED:
1319
- value = self._injector.get_type_dependency(type_)
1320
- if isinstance(value, alluka.abc.Undefined):
1321
- raise KeyError(f"Could not resolve dependency of type {type_}.")
1322
- return value
1497
+ return self._injector.get_type_dependency(type_)
1323
1498
  else:
1324
1499
  return self._injector.get_type_dependency(type_, default=default)
1325
1500
 
1326
1501
  @t.overload
1327
- def inject_dependencies(self, func: t.Callable[P, T]) -> t.Callable[P, T]:
1328
- ...
1502
+ def inject_dependencies(self, func: t.Callable[P, T]) -> t.Callable[P, T]: ...
1329
1503
 
1330
1504
  @t.overload
1331
- def inject_dependencies(self) -> t.Callable[[t.Callable[P, T]], t.Callable[P, T]]:
1332
- ...
1505
+ def inject_dependencies(self) -> t.Callable[[t.Callable[P, T]], t.Callable[P, T]]: ...
1333
1506
 
1334
1507
  def inject_dependencies(
1335
1508
  self, func: t.Callable[P, T] | None = None
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