|
26 | 26 | from __future__ import annotations
|
27 | 27 |
|
28 | 28 | import asyncio
|
29 |
| -import types |
30 | 29 | import functools
|
31 | 30 | import inspect
|
| 31 | +import re |
| 32 | +import types |
32 | 33 | from collections import OrderedDict
|
33 | 34 | from typing import Any, Callable, Dict, List, Optional, Union, TYPE_CHECKING
|
34 | 35 |
|
| 36 | +from .context import ApplicationContext, AutocompleteContext |
| 37 | +from .errors import ApplicationCommandError, CheckFailure, ApplicationCommandInvokeError |
| 38 | +from .permissions import Permission |
35 | 39 | from ..enums import SlashCommandOptionType, ChannelType
|
| 40 | +from ..errors import ValidationError, ClientException |
36 | 41 | from ..member import Member
|
37 |
| -from ..user import User |
38 | 42 | from ..message import Message
|
39 |
| -from .context import ApplicationContext, AutocompleteContext |
| 43 | +from ..user import User |
40 | 44 | from ..utils import find, get_or_fetch, async_all
|
41 |
| -from ..errors import ValidationError, ClientException |
42 |
| -from .errors import ApplicationCommandError, CheckFailure, ApplicationCommandInvokeError |
43 |
| -from .permissions import Permission |
44 | 45 |
|
45 | 46 | __all__ = (
|
46 | 47 | "_BaseCommand",
|
|
60 | 61 | "MessageCommand",
|
61 | 62 | )
|
62 | 63 |
|
63 |
| -if TYPE_CHECKING: |
64 |
| - from ..interactions import Interaction |
| 64 | +if TYPE_CHECKING: |
| 65 | + pass |
65 | 66 |
|
66 | 67 | def wrap_callback(coro):
|
67 | 68 | @functools.wraps(coro)
|
@@ -459,6 +460,9 @@ def _parse_options(self, params) -> List[Option]:
|
459 | 460 | option.name = p_name
|
460 | 461 | option._parameter_name = p_name
|
461 | 462 |
|
| 463 | + validate_chat_input_name(option.name) |
| 464 | + validate_chat_input_description(option.description) |
| 465 | + |
462 | 466 | final_options.append(option)
|
463 | 467 |
|
464 | 468 | return final_options
|
@@ -640,7 +644,7 @@ def __init__(
|
640 | 644 | minmax_types = (int, float, type(None))
|
641 | 645 | else:
|
642 | 646 | minmax_types = (type(None),)
|
643 |
| - minmax_typehint = Optional[Union[minmax_types]] # type: ignore |
| 647 | + minmax_typehint = Optional[Union[minmax_types]] # type: ignore |
644 | 648 |
|
645 | 649 | self.min_value: minmax_typehint = kwargs.pop("min_value", None)
|
646 | 650 | self.max_value: minmax_typehint = kwargs.pop("max_value", None)
|
@@ -1123,24 +1127,33 @@ def command(**kwargs):
|
1123 | 1127 | """
|
1124 | 1128 | return application_command(**kwargs)
|
1125 | 1129 |
|
| 1130 | + |
| 1131 | +docs = "https://discord.com/developers/docs" |
| 1132 | + |
| 1133 | + |
1126 | 1134 | # Validation
|
1127 | 1135 | def validate_chat_input_name(name: Any):
|
| 1136 | + # Must meet the regex ^[\w-]{1,32}$ |
1128 | 1137 | if not isinstance(name, str):
|
1129 |
| - raise TypeError("Name of a command must be a string.") |
1130 |
| - if " " in name: |
1131 |
| - raise ValidationError("Name of a chat input command cannot have spaces.") |
1132 |
| - if not name.islower(): |
1133 |
| - raise ValidationError("Name of a chat input command must be lowercase.") |
1134 |
| - if len(name) > 32 or len(name) < 1: |
| 1138 | + raise TypeError(f"Chat input command names and options must be of type str. Recieved {name}") |
| 1139 | + if not re.match(r"^[\w-]{1,32}$", name): |
| 1140 | + raise ValidationError( |
| 1141 | + r'Chat input command names and options must follow the regex "^[\w-]{1,32}$". For more information, see ' |
| 1142 | + f"{docs}/interactions/application-commands#application-command-object-application-command-naming. Recieved " |
| 1143 | + f"{name}" |
| 1144 | + ) |
| 1145 | + if not 1 <= len(name) <= 32: |
1135 | 1146 | raise ValidationError(
|
1136 |
| - "Name of a chat input command must be less than 32 characters and non empty." |
| 1147 | + f"Chat input command names and options must be 1-32 characters long. Recieved {name}" |
1137 | 1148 | )
|
| 1149 | + if not name.lower() == name: # Can't use islower() as it fails if none of the chars can be lower. See #512. |
| 1150 | + raise ValidationError(f"Chat input command names and options must be lowercase. Recieved {name}") |
1138 | 1151 |
|
1139 | 1152 |
|
1140 | 1153 | def validate_chat_input_description(description: Any):
|
1141 | 1154 | if not isinstance(description, str):
|
1142 |
| - raise TypeError("Description of a command must be a string.") |
1143 |
| - if len(description) > 100 or len(description) < 1: |
| 1155 | + raise TypeError(f"Command description must be of type str. Recieved {description}") |
| 1156 | + if not 1 <= len(description) <= 100: |
1144 | 1157 | raise ValidationError(
|
1145 |
| - "Description of a chat input command must be less than 100 characters and non empty." |
| 1158 | + f"Command description must be 1-100 characters long. Recieved {description}" |
1146 | 1159 | )
|
0 commit comments