@@ -386,7 +386,15 @@ def __init__(
386386 ** kwargs : Any ,
387387 ) -> None :
388388 super ().__init__ (func , ** kwargs )
389- self .app_command : HybridAppCommand [CogT , Any , T ] = HybridAppCommand (self )
389+ self .with_app_command : bool = kwargs .pop ('with_app_command' , True )
390+ self .with_command : bool = kwargs .pop ('with_command' , True )
391+
392+ if not self .with_command and not self .with_app_command :
393+ raise TypeError ('cannot set both with_command and with_app_command to False' )
394+
395+ self .app_command : Optional [HybridAppCommand [CogT , Any , T ]] = (
396+ HybridAppCommand (self ) if self .with_app_command else None
397+ )
390398
391399 @property
392400 def cog (self ) -> CogT :
@@ -395,25 +403,29 @@ def cog(self) -> CogT:
395403 @cog .setter
396404 def cog (self , value : CogT ) -> None :
397405 self ._cog = value
398- self .app_command .binding = value
406+ if self .app_command is not None :
407+ self .app_command .binding = value
399408
400409 async def can_run (self , ctx : Context [BotT ], / ) -> bool :
401- if ctx .interaction is None :
402- return await super ().can_run (ctx )
403- else :
410+ if ctx .interaction is not None and self .app_command :
404411 return await self .app_command ._check_can_run (ctx .interaction )
412+ else :
413+ return await super ().can_run (ctx )
405414
406415 async def _parse_arguments (self , ctx : Context [BotT ]) -> None :
407416 interaction = ctx .interaction
408417 if interaction is None :
409418 return await super ()._parse_arguments (ctx )
410- else :
419+ elif self . app_command :
411420 ctx .kwargs = await self .app_command ._transform_arguments (interaction , interaction .namespace )
412421
413422 def _ensure_assignment_on_copy (self , other : Self ) -> Self :
414423 copy = super ()._ensure_assignment_on_copy (other )
415- copy .app_command = self .app_command .copy ()
416- copy .app_command .wrapped = copy
424+ if self .app_command is None :
425+ copy .app_command = None
426+ else :
427+ copy .app_command = self .app_command .copy ()
428+ copy .app_command .wrapped = copy
417429 return copy
418430
419431 def autocomplete (
@@ -441,6 +453,9 @@ def autocomplete(
441453 The coroutine passed is not actually a coroutine or
442454 the parameter is not found or of an invalid type.
443455 """
456+ if self .app_command is None :
457+ raise TypeError ('This command does not have a registered application command' )
458+
444459 return self .app_command .autocomplete (name )
445460
446461
@@ -473,35 +488,47 @@ class HybridGroup(Group[CogT, P, T]):
473488 def __init__ (self , * args : Any , fallback : Optional [str ] = None , ** attrs : Any ) -> None :
474489 super ().__init__ (* args , ** attrs )
475490 self .invoke_without_command = True
491+ self .with_app_command : bool = attrs .pop ('with_app_command' , True )
492+
476493 parent = None
477494 if self .parent is not None :
478495 if isinstance (self .parent , HybridGroup ):
479496 parent = self .parent .app_command
480497 else :
481498 raise TypeError (f'HybridGroup parent must be HybridGroup not { self .parent .__class__ } ' )
482499
483- guild_ids = attrs .pop ('guild_ids' , None ) or getattr (self .callback , '__discord_app_commands_default_guilds__' , None )
484- guild_only = getattr (self .callback , '__discord_app_commands_guild_only__' , False )
485- default_permissions = getattr (self .callback , '__discord_app_commands_default_permissions__' , None )
486- self .app_command : app_commands .Group = app_commands .Group (
487- name = self .name ,
488- description = self .description or self .short_doc or '…' ,
489- guild_ids = guild_ids ,
490- guild_only = guild_only ,
491- default_permissions = default_permissions ,
492- )
493-
494- # This prevents the group from re-adding the command at __init__
495- self .app_command .parent = parent
500+ # I would love for this to be Optional[app_commands.Group]
501+ # However, Python does not have conditional typing so it's very hard to
502+ # make this type depend on the with_app_command bool without a lot of needless repetition
503+ self .app_command : app_commands .Group = MISSING
496504 self .fallback : Optional [str ] = fallback
497505
498- if fallback is not None :
499- command = HybridAppCommand (self )
500- command .name = fallback
501- self .app_command .add_command (command )
506+ if self .with_app_command :
507+ guild_ids = attrs .pop ('guild_ids' , None ) or getattr (
508+ self .callback , '__discord_app_commands_default_guilds__' , None
509+ )
510+ guild_only = getattr (self .callback , '__discord_app_commands_guild_only__' , False )
511+ default_permissions = getattr (self .callback , '__discord_app_commands_default_permissions__' , None )
512+ self .app_command = app_commands .Group (
513+ name = self .name ,
514+ description = self .description or self .short_doc or '…' ,
515+ guild_ids = guild_ids ,
516+ guild_only = guild_only ,
517+ default_permissions = default_permissions ,
518+ )
519+
520+ # This prevents the group from re-adding the command at __init__
521+ self .app_command .parent = parent
522+
523+ if fallback is not None :
524+ command = HybridAppCommand (self )
525+ command .name = fallback
526+ self .app_command .add_command (command )
502527
503528 @property
504529 def _fallback_command (self ) -> Optional [HybridAppCommand [CogT , ..., T ]]:
530+ if self .app_command is MISSING :
531+ return None
505532 return self .app_command .get_command (self .fallback ) # type: ignore
506533
507534 @property
@@ -596,7 +623,9 @@ def add_command(self, command: Union[HybridGroup[CogT, ..., Any], HybridCommand[
596623 if isinstance (command , HybridGroup ) and self .parent is not None :
597624 raise ValueError (f'{ command .qualified_name !r} is too nested, groups can only be nested at most one level' )
598625
599- self .app_command .add_command (command .app_command )
626+ if command .app_command and self .app_command :
627+ self .app_command .add_command (command .app_command )
628+
600629 command .parent = self
601630
602631 if command .name in self .all_commands :
@@ -611,13 +640,15 @@ def add_command(self, command: Union[HybridGroup[CogT, ..., Any], HybridCommand[
611640
612641 def remove_command (self , name : str , / ) -> Optional [Command [CogT , ..., Any ]]:
613642 cmd = super ().remove_command (name )
614- self .app_command .remove_command (name )
643+ if self .app_command :
644+ self .app_command .remove_command (name )
615645 return cmd
616646
617647 def command (
618648 self ,
619649 name : str = MISSING ,
620650 * args : Any ,
651+ with_app_command : bool = True ,
621652 ** kwargs : Any ,
622653 ) -> Callable [[CommandCallback [CogT , ContextT , P2 , U ]], HybridCommand [CogT , P2 , U ]]:
623654 """A shortcut decorator that invokes :func:`~discord.ext.commands.hybrid_command` and adds it to
@@ -631,7 +662,7 @@ def command(
631662
632663 def decorator (func : CommandCallback [CogT , ContextT , P2 , U ]):
633664 kwargs .setdefault ('parent' , self )
634- result = hybrid_command (name = name , * args , ** kwargs )(func )
665+ result = hybrid_command (name = name , * args , with_app_command = with_app_command , ** kwargs )(func )
635666 self .add_command (result )
636667 return result
637668
@@ -641,6 +672,7 @@ def group(
641672 self ,
642673 name : str = MISSING ,
643674 * args : Any ,
675+ with_app_command : bool = True ,
644676 ** kwargs : Any ,
645677 ) -> Callable [[CommandCallback [CogT , ContextT , P2 , U ]], HybridGroup [CogT , P2 , U ]]:
646678 """A shortcut decorator that invokes :func:`~discord.ext.commands.hybrid_group` and adds it to
@@ -654,7 +686,7 @@ def group(
654686
655687 def decorator (func : CommandCallback [CogT , ContextT , P2 , U ]):
656688 kwargs .setdefault ('parent' , self )
657- result = hybrid_group (name = name , * args , ** kwargs )(func )
689+ result = hybrid_group (name = name , * args , with_app_command = with_app_command , ** kwargs )(func )
658690 self .add_command (result )
659691 return result
660692
@@ -663,9 +695,11 @@ def decorator(func: CommandCallback[CogT, ContextT, P2, U]):
663695
664696def hybrid_command (
665697 name : str = MISSING ,
698+ * ,
699+ with_app_command : bool = True ,
666700 ** attrs : Any ,
667701) -> Callable [[CommandCallback [CogT , ContextT , P , T ]], HybridCommand [CogT , P , T ]]:
668- """A decorator that transforms a function into a :class:`.HybridCommand`.
702+ r """A decorator that transforms a function into a :class:`.HybridCommand`.
669703
670704 A hybrid command is one that functions both as a regular :class:`.Command`
671705 and one that is also a :class:`app_commands.Command <discord.app_commands.Command>`.
@@ -690,7 +724,9 @@ def hybrid_command(
690724 name: :class:`str`
691725 The name to create the command with. By default this uses the
692726 function name unchanged.
693- attrs
727+ with_app_command: :class:`bool`
728+ Whether to register the command as an application command.
729+ \*\*attrs
694730 Keyword arguments to pass into the construction of the
695731 hybrid command.
696732
@@ -703,24 +739,36 @@ def hybrid_command(
703739 def decorator (func : CommandCallback [CogT , ContextT , P , T ]):
704740 if isinstance (func , Command ):
705741 raise TypeError ('Callback is already a command.' )
706- return HybridCommand (func , name = name , ** attrs )
742+ return HybridCommand (func , name = name , with_app_command = with_app_command , ** attrs )
707743
708744 return decorator
709745
710746
711747def hybrid_group (
712748 name : str = MISSING ,
749+ * ,
750+ with_app_command : bool = True ,
713751 ** attrs : Any ,
714752) -> Callable [[CommandCallback [CogT , ContextT , P , T ]], HybridGroup [CogT , P , T ]]:
715753 """A decorator that transforms a function into a :class:`.HybridGroup`.
716754
717755 This is similar to the :func:`~discord.ext.commands.group` decorator except it creates
718756 a hybrid group instead.
757+
758+ Parameters
759+ -----------
760+ with_app_command: :class:`bool`
761+ Whether to register the command as an application command.
762+
763+ Raises
764+ -------
765+ TypeError
766+ If the function is not a coroutine or is already a command.
719767 """
720768
721769 def decorator (func : CommandCallback [CogT , ContextT , P , T ]):
722770 if isinstance (func , Command ):
723771 raise TypeError ('Callback is already a command.' )
724- return HybridGroup (func , name = name , ** attrs )
772+ return HybridGroup (func , name = name , with_app_command = with_app_command , ** attrs )
725773
726774 return decorator # type: ignore
0 commit comments