From bbf7a7981beba14bd4d6c37bc5cb371f888a8109 Mon Sep 17 00:00:00 2001 From: Rapptz Date: Fri, 11 Mar 2022 07:26:25 -0500 Subject: [PATCH] Ensure all choices are the same type as the parameter type Fixes #7625 --- discord/app_commands/commands.py | 6 +++--- discord/app_commands/models.py | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/discord/app_commands/commands.py b/discord/app_commands/commands.py index 47fcf3016..b766c07e4 100644 --- a/discord/app_commands/commands.py +++ b/discord/app_commands/commands.py @@ -223,9 +223,9 @@ def _populate_choices(params: Dict[str, CommandParameter], all_choices: Dict[str if param.type not in (AppCommandOptionType.string, AppCommandOptionType.number, AppCommandOptionType.integer): raise TypeError('choices are only supported for integer, string, or number option types') - # There's a type safety hole if someone does Choice[float] as an annotation - # but the values are actually Choice[int]. Since the input-output is the same this feels - # safe enough to ignore. + if not all(param.type == choice._option_type for choice in choices): + raise TypeError('choices must all have the same inner option type as the parameter choice type') + param.choices = choices if all_choices: diff --git a/discord/app_commands/models.py b/discord/app_commands/models.py index b4654988a..8d0a23285 100644 --- a/discord/app_commands/models.py +++ b/discord/app_commands/models.py @@ -188,6 +188,19 @@ class Choice(Generic[ChoiceT]): def __repr__(self) -> str: return f'{self.__class__.__name__}(name={self.name!r}, value={self.value!r})' + @property + def _option_type(self) -> AppCommandOptionType: + if isinstance(self.value, int): + return AppCommandOptionType.integer + elif isinstance(self.value, float): + return AppCommandOptionType.number + elif isinstance(self.value, str): + return AppCommandOptionType.string + else: + raise TypeError( + f'invalid Choice value type given, expected int, str, or float but received {self.value.__class__!r}' + ) + def to_dict(self) -> ApplicationCommandOptionChoice: return { 'name': self.name,