32
32
import re
33
33
import types
34
34
from 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
+ )
36
51
37
52
from .context import ApplicationContext , AutocompleteContext
38
53
from .errors import ApplicationCommandError , CheckFailure , ApplicationCommandInvokeError
61
76
)
62
77
63
78
if TYPE_CHECKING :
64
- from typing_extensions import ParamSpec
79
+ from typing_extensions import ParamSpec , Concatenate
65
80
66
81
from ..cog import Cog
67
82
68
83
T = TypeVar ('T' )
69
- CogT = TypeVar ('CogT' , bound = 'Cog' )
84
+ CogT = TypeVar ("CogT" , bound = "Cog" )
85
+ Coro = TypeVar ('Coro' , bound = Callable [..., Coroutine [Any , Any , Any ]])
70
86
71
87
if TYPE_CHECKING :
72
88
P = ParamSpec ('P' )
@@ -105,6 +121,16 @@ async def wrapped(arg):
105
121
return ret
106
122
return wrapped
107
123
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
+
108
134
class _BaseCommand :
109
135
__slots__ = ()
110
136
@@ -118,7 +144,7 @@ def __init__(self, func: Callable, **kwargs) -> None:
118
144
cooldown = func .__commands_cooldown__
119
145
except AttributeError :
120
146
cooldown = kwargs .get ('cooldown' )
121
-
147
+
122
148
if cooldown is None :
123
149
buckets = CooldownMapping (cooldown , BucketType .default )
124
150
elif isinstance (cooldown , CooldownMapping ):
@@ -134,7 +160,10 @@ def __init__(self, func: Callable, **kwargs) -> None:
134
160
135
161
self ._max_concurrency : Optional [MaxConcurrency ] = max_concurrency
136
162
137
- def __repr__ (self ):
163
+ self ._callback = None
164
+ self .module = None
165
+
166
+ def __repr__ (self ) -> str :
138
167
return f"<discord.commands.{ self .__class__ .__name__ } name={ self .name } >"
139
168
140
169
def __eq__ (self , other ) -> bool :
@@ -161,6 +190,22 @@ async def __call__(self, ctx, *args, **kwargs):
161
190
"""
162
191
return await self .callback (ctx , * args , ** kwargs )
163
192
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
+
164
209
def _prepare_cooldowns (self , ctx : ApplicationContext ):
165
210
if self ._buckets .valid :
166
211
current = datetime .datetime .now ().timestamp ()
@@ -640,7 +685,7 @@ def _match_option_param_names(self, params, options):
640
685
)
641
686
p_obj = p_obj .annotation
642
687
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 ):
644
689
raise TypeError (f"Parameter { p_name } does not match input type of { o .name } ." )
645
690
o ._parameter_name = p_name
646
691
@@ -743,7 +788,7 @@ async def invoke_autocomplete_callback(self, ctx: AutocompleteContext):
743
788
744
789
if asyncio .iscoroutinefunction (option .autocomplete ):
745
790
result = await result
746
-
791
+
747
792
choices = [
748
793
o if isinstance (o , OptionChoice ) else OptionChoice (o )
749
794
for o in result
@@ -863,13 +908,18 @@ def __init__(
863
908
self ._before_invoke = None
864
909
self ._after_invoke = None
865
910
self .cog = None
911
+ self .id = None
866
912
867
913
# Permissions
868
914
self .default_permission = kwargs .get ("default_permission" , True )
869
915
self .permissions : List [CommandPermission ] = kwargs .get ("permissions" , [])
870
916
if self .permissions and self .default_permission :
871
917
self .default_permission = False
872
918
919
+ @property
920
+ def module (self ) -> Optional [str ]:
921
+ return self .__module__
922
+
873
923
def to_dict (self ) -> Dict :
874
924
as_dict = {
875
925
"name" : self .name ,
@@ -989,7 +1039,7 @@ def _ensure_assignment_on_copy(self, other):
989
1039
990
1040
if self .subcommands != other .subcommands :
991
1041
other .subcommands = self .subcommands .copy ()
992
-
1042
+
993
1043
if self .checks != other .checks :
994
1044
other .checks = self .checks .copy ()
995
1045
@@ -1069,6 +1119,7 @@ def __init__(self, func: Callable, *args, **kwargs) -> None:
1069
1119
raise TypeError ("Name of a command must be a string." )
1070
1120
1071
1121
self .cog = None
1122
+ self .id = None
1072
1123
1073
1124
try :
1074
1125
checks = func .__commands_checks__
@@ -1189,7 +1240,7 @@ async def _invoke(self, ctx: ApplicationContext) -> None:
1189
1240
1190
1241
if self .cog is not None :
1191
1242
await self .callback (self .cog , ctx , target )
1192
- else :
1243
+ else :
1193
1244
await self .callback (ctx , target )
1194
1245
1195
1246
def copy (self ):
0 commit comments