3232import re
3333import types
3434from collections import OrderedDict
35- from typing import Any , Callable , Dict , Generator , Generic , List , Optional , Type , TypeVar , Union , TYPE_CHECKING
35+ from typing import (
36+ Any ,
37+ Callable ,
38+ Dict ,
39+ List ,
40+ Optional ,
41+ Union ,
42+ TYPE_CHECKING ,
43+ Awaitable ,
44+ overload ,
45+ TypeVar ,
46+ Generic ,
47+ Type ,
48+ Generator ,
49+ Coroutine ,
50+ )
3651
3752from .context import ApplicationContext , AutocompleteContext
3853from .errors import ApplicationCommandError , CheckFailure , ApplicationCommandInvokeError
6176)
6277
6378if TYPE_CHECKING :
64- from typing_extensions import ParamSpec
79+ from typing_extensions import ParamSpec , Concatenate
6580
6681 from ..cog import Cog
6782
6883T = TypeVar ('T' )
69- CogT = TypeVar ('CogT' , bound = 'Cog' )
84+ CogT = TypeVar ("CogT" , bound = "Cog" )
85+ Coro = TypeVar ('Coro' , bound = Callable [..., Coroutine [Any , Any , Any ]])
7086
7187if TYPE_CHECKING :
7288 P = ParamSpec ('P' )
@@ -105,6 +121,16 @@ async def wrapped(arg):
105121 return ret
106122 return wrapped
107123
124+ def unwrap_function (function : Callable [..., Any ]) -> Callable [..., Any ]:
125+ partial = functools .partial
126+ while True :
127+ if hasattr (function , '__wrapped__' ):
128+ function = function .__wrapped__
129+ elif isinstance (function , partial ):
130+ function = function .func
131+ else :
132+ return function
133+
108134class _BaseCommand :
109135 __slots__ = ()
110136
@@ -118,7 +144,7 @@ def __init__(self, func: Callable, **kwargs) -> None:
118144 cooldown = func .__commands_cooldown__
119145 except AttributeError :
120146 cooldown = kwargs .get ('cooldown' )
121-
147+
122148 if cooldown is None :
123149 buckets = CooldownMapping (cooldown , BucketType .default )
124150 elif isinstance (cooldown , CooldownMapping ):
@@ -134,7 +160,10 @@ def __init__(self, func: Callable, **kwargs) -> None:
134160
135161 self ._max_concurrency : Optional [MaxConcurrency ] = max_concurrency
136162
137- def __repr__ (self ):
163+ self ._callback = None
164+ self .module = None
165+
166+ def __repr__ (self ) -> str :
138167 return f"<discord.commands.{ self .__class__ .__name__ } name={ self .name } >"
139168
140169 def __eq__ (self , other ) -> bool :
@@ -161,6 +190,22 @@ async def __call__(self, ctx, *args, **kwargs):
161190 """
162191 return await self .callback (ctx , * args , ** kwargs )
163192
193+ @property
194+ def callback (self ) -> Union [
195+ Callable [Concatenate [CogT , ApplicationContext , P ], Coro [T ]],
196+ Callable [Concatenate [ApplicationContext , P ], Coro [T ]],
197+ ]:
198+ return self ._callback
199+
200+ @callback .setter
201+ def callback (self , function : Union [
202+ Callable [Concatenate [CogT , ApplicationContext , P ], Coro [T ]],
203+ Callable [Concatenate [ApplicationContext , P ], Coro [T ]],
204+ ]) -> None :
205+ self ._callback = function
206+ unwrap = unwrap_function (function )
207+ self .module = unwrap .__module__
208+
164209 def _prepare_cooldowns (self , ctx : ApplicationContext ):
165210 if self ._buckets .valid :
166211 current = datetime .datetime .now ().timestamp ()
@@ -640,7 +685,7 @@ def _match_option_param_names(self, params, options):
640685 )
641686 p_obj = p_obj .annotation
642687
643- if not any (c (o , p_obj ) for c in check_annotations ):
688+ if not any (c (o , p_obj ) for c in check_annotations ):
644689 raise TypeError (f"Parameter { p_name } does not match input type of { o .name } ." )
645690 o ._parameter_name = p_name
646691
@@ -743,7 +788,7 @@ async def invoke_autocomplete_callback(self, ctx: AutocompleteContext):
743788
744789 if asyncio .iscoroutinefunction (option .autocomplete ):
745790 result = await result
746-
791+
747792 choices = [
748793 o if isinstance (o , OptionChoice ) else OptionChoice (o )
749794 for o in result
@@ -863,13 +908,18 @@ def __init__(
863908 self ._before_invoke = None
864909 self ._after_invoke = None
865910 self .cog = None
911+ self .id = None
866912
867913 # Permissions
868914 self .default_permission = kwargs .get ("default_permission" , True )
869915 self .permissions : List [CommandPermission ] = kwargs .get ("permissions" , [])
870916 if self .permissions and self .default_permission :
871917 self .default_permission = False
872918
919+ @property
920+ def module (self ) -> Optional [str ]:
921+ return self .__module__
922+
873923 def to_dict (self ) -> Dict :
874924 as_dict = {
875925 "name" : self .name ,
@@ -989,7 +1039,7 @@ def _ensure_assignment_on_copy(self, other):
9891039
9901040 if self .subcommands != other .subcommands :
9911041 other .subcommands = self .subcommands .copy ()
992-
1042+
9931043 if self .checks != other .checks :
9941044 other .checks = self .checks .copy ()
9951045
@@ -1069,6 +1119,7 @@ def __init__(self, func: Callable, *args, **kwargs) -> None:
10691119 raise TypeError ("Name of a command must be a string." )
10701120
10711121 self .cog = None
1122+ self .id = None
10721123
10731124 try :
10741125 checks = func .__commands_checks__
@@ -1189,7 +1240,7 @@ async def _invoke(self, ctx: ApplicationContext) -> None:
11891240
11901241 if self .cog is not None :
11911242 await self .callback (self .cog , ctx , target )
1192- else :
1243+ else :
11931244 await self .callback (ctx , target )
11941245
11951246 def copy (self ):
0 commit comments