mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-07-11 04:17:58 +00:00
[commands] Require number of parameters at instantiation time
This allows it to bypass annotation evaluation for arguments that don't matter like self and context.
This commit is contained in:
parent
0b5c3cf256
commit
8226f0df2c
@ -129,7 +129,15 @@ def get_signature_parameters(function: Callable[..., Any], globalns: Dict[str, A
|
|||||||
params = {}
|
params = {}
|
||||||
cache: Dict[str, Any] = {}
|
cache: Dict[str, Any] = {}
|
||||||
eval_annotation = discord.utils.evaluate_annotation
|
eval_annotation = discord.utils.evaluate_annotation
|
||||||
for name, parameter in signature.parameters.items():
|
required_params = discord.utils.is_inside_class(function) + 1
|
||||||
|
if len(signature.parameters) < required_params:
|
||||||
|
raise TypeError(f'Command signature requires at least {required_params - 1} parameter(s)')
|
||||||
|
|
||||||
|
iterator = iter(signature.parameters.items())
|
||||||
|
for _ in range(0, required_params):
|
||||||
|
next(iterator)
|
||||||
|
|
||||||
|
for name, parameter in iterator:
|
||||||
annotation = parameter.annotation
|
annotation = parameter.annotation
|
||||||
if annotation is parameter.empty:
|
if annotation is parameter.empty:
|
||||||
params[name] = parameter
|
params[name] = parameter
|
||||||
@ -638,21 +646,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
|||||||
|
|
||||||
Useful for inspecting signature.
|
Useful for inspecting signature.
|
||||||
"""
|
"""
|
||||||
result = self.params.copy()
|
return self.params.copy()
|
||||||
if self.cog is not None:
|
|
||||||
# first parameter is self
|
|
||||||
try:
|
|
||||||
del result[next(iter(result))]
|
|
||||||
except StopIteration:
|
|
||||||
raise ValueError("missing 'self' parameter") from None
|
|
||||||
|
|
||||||
try:
|
|
||||||
# first/second parameter is context
|
|
||||||
del result[next(iter(result))]
|
|
||||||
except StopIteration:
|
|
||||||
raise ValueError("missing 'context' parameter") from None
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def full_parent_name(self) -> str:
|
def full_parent_name(self) -> str:
|
||||||
@ -727,20 +721,6 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
|||||||
view = ctx.view
|
view = ctx.view
|
||||||
iterator = iter(self.params.items())
|
iterator = iter(self.params.items())
|
||||||
|
|
||||||
if self.cog is not None:
|
|
||||||
# we have 'self' as the first parameter so just advance
|
|
||||||
# the iterator and resume parsing
|
|
||||||
try:
|
|
||||||
next(iterator)
|
|
||||||
except StopIteration:
|
|
||||||
raise discord.ClientException(f'Callback for {self.name} command is missing "self" parameter.')
|
|
||||||
|
|
||||||
# next we have the 'ctx' as the next parameter
|
|
||||||
try:
|
|
||||||
next(iterator)
|
|
||||||
except StopIteration:
|
|
||||||
raise discord.ClientException(f'Callback for {self.name} command is missing "ctx" parameter.')
|
|
||||||
|
|
||||||
for name, param in iterator:
|
for name, param in iterator:
|
||||||
ctx.current_parameter = param
|
ctx.current_parameter = param
|
||||||
if param.kind in (param.POSITIONAL_OR_KEYWORD, param.POSITIONAL_ONLY):
|
if param.kind in (param.POSITIONAL_OR_KEYWORD, param.POSITIONAL_ONLY):
|
||||||
|
@ -1061,6 +1061,21 @@ def resolve_annotation(
|
|||||||
return evaluate_annotation(annotation, globalns, locals, cache)
|
return evaluate_annotation(annotation, globalns, locals, cache)
|
||||||
|
|
||||||
|
|
||||||
|
def is_inside_class(func: Callable[..., Any]) -> bool:
|
||||||
|
# For methods defined in a class, the qualname has a dotted path
|
||||||
|
# denoting which class it belongs to. So, e.g. for A.foo the qualname
|
||||||
|
# would be A.foo while a global foo() would just be foo.
|
||||||
|
#
|
||||||
|
# Unfortuately, for nested functions this breaks. So inside an outer
|
||||||
|
# function named outer, those two would end up having a qualname with
|
||||||
|
# outer.<locals>.A.foo and outer.<locals>.foo
|
||||||
|
|
||||||
|
if func.__qualname__ == func.__name__:
|
||||||
|
return False
|
||||||
|
(remaining, _, _) = func.__qualname__.rpartition('.')
|
||||||
|
return not remaining.endswith('<locals>')
|
||||||
|
|
||||||
|
|
||||||
TimestampStyle = Literal['f', 'F', 'd', 'D', 't', 'T', 'R']
|
TimestampStyle = Literal['f', 'F', 'd', 'D', 't', 'T', 'R']
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user