|
25 | 25 | from __future__ import annotations
|
26 | 26 |
|
27 | 27 | import inspect
|
| 28 | +import logging |
28 | 29 | from enum import Enum
|
29 | 30 | from typing import TYPE_CHECKING, Literal, Optional, Type, Union
|
30 | 31 |
|
|
41 | 42 | from ..enums import ChannelType
|
42 | 43 | from ..enums import Enum as DiscordEnum
|
43 | 44 | from ..enums import SlashCommandOptionType
|
44 |
| -from ..utils import MISSING |
| 45 | +from ..utils import MISSING, basic_autocomplete |
45 | 46 |
|
46 | 47 | if TYPE_CHECKING:
|
47 | 48 | from ..ext.commands import Converter
|
|
86 | 87 | DMChannel: ChannelType.private,
|
87 | 88 | }
|
88 | 89 |
|
| 90 | +_log = logging.getLogger(__name__) |
| 91 | + |
89 | 92 |
|
90 | 93 | class ThreadOption:
|
91 | 94 | """Represents a class that can be passed as the ``input_type`` for an :class:`Option` class.
|
@@ -115,12 +118,13 @@ class Option:
|
115 | 118 | input_type: Union[Type[:class:`str`], Type[:class:`bool`], Type[:class:`int`], Type[:class:`float`], Type[:class:`.abc.GuildChannel`], Type[:class:`Thread`], Type[:class:`Member`], Type[:class:`User`], Type[:class:`Attachment`], Type[:class:`Role`], Type[:class:`.abc.Mentionable`], :class:`SlashCommandOptionType`, Type[:class:`.ext.commands.Converter`], Type[:class:`enums.Enum`], Type[:class:`Enum`]]
|
116 | 119 | The type of input that is expected for this option. This can be a :class:`SlashCommandOptionType`,
|
117 | 120 | an associated class, a channel type, a :class:`Converter`, a converter class or an :class:`enum.Enum`.
|
| 121 | + If a :class:`enum.Enum` is used and it has up to 25 values, :attr:`choices` will be automatically filled. If the :class:`enum.Enum` has more than 25 values, :attr:`autocomplete` will be implemented with :func:`discord.utils.basic_autocomplete` instead. |
118 | 122 | name: :class:`str`
|
119 | 123 | The name of this option visible in the UI.
|
120 | 124 | Inherits from the variable name if not provided as a parameter.
|
121 | 125 | description: Optional[:class:`str`]
|
122 | 126 | The description of this option.
|
123 |
| - Must be 100 characters or fewer. |
| 127 | + Must be 100 characters or fewer. If :attr:`input_type` is a :class:`enum.Enum` and :attr:`description` is not specified, :attr:`input_type`'s docstring will be used. |
124 | 128 | choices: Optional[List[Union[:class:`Any`, :class:`OptionChoice`]]]
|
125 | 129 | The list of available choices for this option.
|
126 | 130 | Can be a list of values or :class:`OptionChoice` objects (which represent a name:value pair).
|
@@ -195,7 +199,14 @@ def __init__(
|
195 | 199 | input_type_is_class = isinstance(input_type, type)
|
196 | 200 | if input_type_is_class and issubclass(input_type, (Enum, DiscordEnum)):
|
197 | 201 | if description is None:
|
198 |
| - description = inspect.getdoc(input_type) |
| 202 | + description = inspect.cleandoc(input_type.__doc__) |
| 203 | + if description and len(description) > 100: |
| 204 | + description = description[:97] + "..." |
| 205 | + _log.warning( |
| 206 | + "Option %s's description was truncated due to Enum %s's docstring exceeding 100 characters.", |
| 207 | + self.name, |
| 208 | + input_type, |
| 209 | + ) |
199 | 210 | enum_choices = [OptionChoice(e.name, e.value) for e in input_type]
|
200 | 211 | value_class = enum_choices[0].value.__class__
|
201 | 212 | if all(isinstance(elem.value, value_class) for elem in enum_choices):
|
@@ -250,10 +261,19 @@ def __init__(
|
250 | 261 | kwargs.pop("required", True) if "default" not in kwargs else False
|
251 | 262 | )
|
252 | 263 | self.default = kwargs.pop("default", None)
|
253 |
| - self.choices: list[OptionChoice] = enum_choices or [ |
254 |
| - o if isinstance(o, OptionChoice) else OptionChoice(o) |
255 |
| - for o in kwargs.pop("choices", []) |
256 |
| - ] |
| 264 | + |
| 265 | + self.autocomplete = kwargs.pop("autocomplete", None) |
| 266 | + if len(enum_choices) > 25: |
| 267 | + self.choices: list[OptionChoice] = [] |
| 268 | + for e in enum_choices: |
| 269 | + e.value = str(e.value) |
| 270 | + self.autocomplete = basic_autocomplete(enum_choices) |
| 271 | + self.input_type = SlashCommandOptionType.string |
| 272 | + else: |
| 273 | + self.choices: list[OptionChoice] = enum_choices or [ |
| 274 | + o if isinstance(o, OptionChoice) else OptionChoice(o) |
| 275 | + for o in kwargs.pop("choices", []) |
| 276 | + ] |
257 | 277 |
|
258 | 278 | if self.input_type == SlashCommandOptionType.integer:
|
259 | 279 | minmax_types = (int, type(None))
|
@@ -323,8 +343,6 @@ def __init__(
|
323 | 343 | if self.max_length < 1 or self.max_length > 6000:
|
324 | 344 | raise AttributeError("max_length must between 1 and 6000 (inclusive)")
|
325 | 345 |
|
326 |
| - self.autocomplete = kwargs.pop("autocomplete", None) |
327 |
| - |
328 | 346 | self.name_localizations = kwargs.pop("name_localizations", MISSING)
|
329 | 347 | self.description_localizations = kwargs.pop(
|
330 | 348 | "description_localizations", MISSING
|
|
0 commit comments