@@ -202,7 +202,7 @@ def replace_parameters(parameters: Dict[str, Parameter], signature: inspect.Sign
202202
203203
204204class HybridAppCommand (discord .app_commands .Command [CogT , P , T ]):
205- def __init__ (self , wrapped : HybridCommand [CogT , Any , T ]) -> None :
205+ def __init__ (self , wrapped : Command [CogT , Any , T ]) -> None :
206206 signature = inspect .signature (wrapped .callback )
207207 params = replace_parameters (wrapped .params , signature )
208208 wrapped .callback .__signature__ = signature .replace (parameters = params )
@@ -216,7 +216,7 @@ def __init__(self, wrapped: HybridCommand[CogT, Any, T]) -> None:
216216 finally :
217217 del wrapped .callback .__signature__
218218
219- self .wrapped : HybridCommand [CogT , Any , T ] = wrapped
219+ self .wrapped : Command [CogT , Any , T ] = wrapped
220220 self .binding = wrapped .cog
221221
222222 def _copy_with (self , ** kwargs ) -> Self :
@@ -435,11 +435,19 @@ class HybridGroup(Group[CogT, P, T]):
435435 decorator or functional interface.
436436
437437 .. versionadded:: 2.0
438+
439+ Parameters
440+ -----------
441+ fallback: Optional[:class:`str`]
442+ The command name to use as a fallback for the application command. Since
443+ application command groups cannot be invoked, this creates a subcommand within
444+ the group that can be invoked with the given group callback. If ``None``
445+ then no fallback command is given. Defaults to ``None``.
438446 """
439447
440448 __commands_is_hybrid__ : ClassVar [bool ] = True
441449
442- def __init__ (self , * args : Any , ** attrs : Any ) -> None :
450+ def __init__ (self , * args : Any , fallback : Optional [ str ] = None , ** attrs : Any ) -> None :
443451 super ().__init__ (* args , ** attrs )
444452 self .invoke_without_command = True
445453 parent = None
@@ -458,6 +466,83 @@ def __init__(self, *args: Any, **attrs: Any) -> None:
458466
459467 # This prevents the group from re-adding the command at __init__
460468 self .app_command .parent = parent
469+ self .fallback : Optional [str ] = fallback
470+
471+ if fallback is not None :
472+ command = HybridAppCommand (self )
473+ command .name = fallback
474+ self .app_command .add_command (command )
475+
476+ @property
477+ def _fallback_command (self ) -> Optional [HybridAppCommand [CogT , ..., T ]]:
478+ return self .app_command .get_command (self .fallback ) # type: ignore
479+
480+ @property
481+ def cog (self ) -> CogT :
482+ return self ._cog
483+
484+ @cog .setter
485+ def cog (self , value : CogT ) -> None :
486+ self ._cog = value
487+ fallback = self ._fallback_command
488+ if fallback :
489+ fallback .binding = value
490+
491+ async def can_run (self , ctx : Context [BotT ], / ) -> bool :
492+ fallback = self ._fallback_command
493+ if ctx .interaction is not None and fallback :
494+ return await fallback ._check_can_run (ctx .interaction )
495+ else :
496+ return await super ().can_run (ctx )
497+
498+ async def _parse_arguments (self , ctx : Context [BotT ]) -> None :
499+ interaction = ctx .interaction
500+ fallback = self ._fallback_command
501+ if interaction is not None and fallback :
502+ ctx .kwargs = await fallback ._transform_arguments (interaction , interaction .namespace )
503+ else :
504+ return await super ()._parse_arguments (ctx )
505+
506+ def _ensure_assignment_on_copy (self , other : Self ) -> Self :
507+ copy = super ()._ensure_assignment_on_copy (other )
508+ copy .fallback = self .fallback
509+ return copy
510+
511+ def autocomplete (
512+ self , name : str
513+ ) -> Callable [[AutocompleteCallback [CogT , ChoiceT ]], AutocompleteCallback [CogT , ChoiceT ]]:
514+ """A decorator that registers a coroutine as an autocomplete prompt for a parameter.
515+
516+ This is the same as :meth:`~discord.app_commands.Command.autocomplete`. It is only
517+ applicable for the application command and doesn't do anything if the command is
518+ a regular command.
519+
520+ This is only available if the group has a fallback application command registered.
521+
522+ .. note::
523+
524+ Similar to the :meth:`~discord.app_commands.Command.autocomplete` method, this
525+ takes :class:`~discord.Interaction` as a parameter rather than a :class:`Context`.
526+
527+ Parameters
528+ -----------
529+ name: :class:`str`
530+ The parameter name to register as autocomplete.
531+
532+ Raises
533+ -------
534+ TypeError
535+ The coroutine passed is not actually a coroutine or
536+ the parameter is not found or of an invalid type.
537+ """
538+ if self ._fallback_command :
539+ return self ._fallback_command .autocomplete (name )
540+ else :
541+
542+ def decorator (func : AutocompleteCallback [CogT , ChoiceT ]) -> AutocompleteCallback [CogT , ChoiceT ]:
543+ return func
544+
545+ return decorator
461546
462547 def add_command (self , command : Union [HybridGroup [CogT , ..., Any ], HybridCommand [CogT , ..., Any ]], / ) -> None :
463548 """Adds a :class:`.HybridCommand` into the internal list of commands.
0 commit comments