mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-04-18 23:15:48 +00:00
Implement app_commands.rename decorator
This commit is contained in:
parent
def035bf9a
commit
c6d0c82d66
@ -75,6 +75,7 @@ __all__ = (
|
||||
'command',
|
||||
'describe',
|
||||
'check',
|
||||
'rename',
|
||||
'choices',
|
||||
'autocomplete',
|
||||
'guilds',
|
||||
@ -217,6 +218,29 @@ def _populate_descriptions(params: Dict[str, CommandParameter], descriptions: Di
|
||||
raise TypeError(f'unknown parameter given: {first}')
|
||||
|
||||
|
||||
def _populate_renames(params: Dict[str, CommandParameter], renames: Dict[str, str]) -> None:
|
||||
rename_map: Dict[str, str] = {}
|
||||
|
||||
# original name to renamed name
|
||||
|
||||
for name in params.keys():
|
||||
new_name = renames.pop(name, MISSING)
|
||||
|
||||
if new_name is MISSING:
|
||||
rename_map[name] = name
|
||||
continue
|
||||
|
||||
if name in rename_map:
|
||||
raise ValueError(f'{new_name} is already used')
|
||||
|
||||
rename_map[name] = new_name
|
||||
params[name]._rename = new_name
|
||||
|
||||
if renames:
|
||||
first = next(iter(renames))
|
||||
raise ValueError(f'unknown parameter given: {first}')
|
||||
|
||||
|
||||
def _populate_choices(params: Dict[str, CommandParameter], all_choices: Dict[str, List[Choice]]) -> None:
|
||||
for name, param in params.items():
|
||||
choices = all_choices.pop(name, MISSING)
|
||||
@ -298,6 +322,13 @@ def _extract_parameters_from_callback(func: Callable[..., Any], globalns: Dict[s
|
||||
else:
|
||||
_populate_descriptions(result, descriptions)
|
||||
|
||||
try:
|
||||
renames = func.__discord_app_commands_param_rename__
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
_populate_renames(result, renames)
|
||||
|
||||
try:
|
||||
choices = func.__discord_app_commands_param_choices__
|
||||
except AttributeError:
|
||||
@ -475,23 +506,29 @@ class Command(Generic[GroupT, P, T]):
|
||||
raise CheckFailure(f'The check functions for command {self.name!r} failed.')
|
||||
|
||||
values = namespace.__dict__
|
||||
for name, param in self._params.items():
|
||||
transformed_values = {}
|
||||
# get parameters mapped to their renamed names
|
||||
params = {param.display_name: param for param in self._params.values()}
|
||||
|
||||
for name, param in params.items():
|
||||
try:
|
||||
value = values[name]
|
||||
except KeyError:
|
||||
if not param.required:
|
||||
values[name] = param.default
|
||||
transformed_values[name] = param.default
|
||||
else:
|
||||
raise CommandSignatureMismatch(self) from None
|
||||
else:
|
||||
values[name] = await param.transform(interaction, value)
|
||||
if param._rename is not MISSING:
|
||||
name = param.name
|
||||
transformed_values[name] = await param.transform(interaction, value)
|
||||
|
||||
# These type ignores are because the type checker doesn't quite understand the narrowing here
|
||||
# Likewise, it thinks we're missing positional arguments when there aren't any.
|
||||
try:
|
||||
if self.binding is not None:
|
||||
return await self._callback(self.binding, interaction, **values) # type: ignore
|
||||
return await self._callback(interaction, **values) # type: ignore
|
||||
return await self._callback(self.binding, interaction, **transformed_values) # type: ignore
|
||||
return await self._callback(interaction, **transformed_values) # type: ignore
|
||||
except TypeError as e:
|
||||
# In order to detect mismatch from the provided signature and the Discord data,
|
||||
# there are many ways it can go wrong yet all of them eventually lead to a TypeError
|
||||
@ -1280,6 +1317,46 @@ def describe(**parameters: str) -> Callable[[T], T]:
|
||||
return decorator
|
||||
|
||||
|
||||
def rename(**parameters: str) -> Callable[[T], T]:
|
||||
r"""Renames the given parameters by their name using the key of the keyword argument
|
||||
as the name.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python3
|
||||
|
||||
@app_commands.command()
|
||||
@app_commands.rename(the_member_to_ban='member')
|
||||
async def ban(interaction: discord.Interaction, the_member_to_ban: discord.Member):
|
||||
await interaction.response.send_message(f'Banned {the_member_to_ban}')
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
\*\*parameters
|
||||
The name of the parameters.
|
||||
|
||||
Raises
|
||||
--------
|
||||
ValueError
|
||||
The parameter name is already used by another parameter.
|
||||
TypeError
|
||||
The parameter name is not found.
|
||||
"""
|
||||
|
||||
def decorator(inner: T) -> T:
|
||||
if isinstance(inner, Command):
|
||||
_populate_renames(inner._params, parameters)
|
||||
else:
|
||||
try:
|
||||
inner.__discord_app_commands_param_rename__.update(parameters) # type: ignore - Runtime attribute access
|
||||
except AttributeError:
|
||||
inner.__discord_app_commands_param_rename__ = parameters # type: ignore - Runtime attribute assignment
|
||||
|
||||
return inner
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def choices(**parameters: List[Choice[ChoiceT]]) -> Callable[[T], T]:
|
||||
r"""Instructs the given parameters by their name to use the given choices for their choices.
|
||||
|
||||
|
@ -101,12 +101,13 @@ class CommandParameter:
|
||||
min_value: Optional[Union[int, float]] = None
|
||||
max_value: Optional[Union[int, float]] = None
|
||||
autocomplete: Optional[Callable[..., Coroutine[Any, Any, Any]]] = None
|
||||
_rename: str = MISSING
|
||||
_annotation: Any = MISSING
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
base = {
|
||||
'type': self.type.value,
|
||||
'name': self.name,
|
||||
'name': self.display_name,
|
||||
'description': self.description,
|
||||
'required': self.required,
|
||||
}
|
||||
@ -146,6 +147,11 @@ class CommandParameter:
|
||||
|
||||
return value
|
||||
|
||||
@property
|
||||
def display_name(self) -> str:
|
||||
""":class:`str`: The name of the parameter as it should be displayed to the user."""
|
||||
return self.name if self._rename is MISSING else self._rename
|
||||
|
||||
|
||||
class Transformer:
|
||||
"""The base class that allows a type annotation in an application command parameter
|
||||
|
@ -462,6 +462,9 @@ Decorators
|
||||
.. autofunction:: discord.app_commands.describe
|
||||
:decorator:
|
||||
|
||||
.. autofunction:: discord.app_commands.rename
|
||||
:decorator:
|
||||
|
||||
.. autofunction:: discord.app_commands.choices
|
||||
:decorator:
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user