We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
multiple-type arg option is beak
### Summary

Cannot set multiple type for arg in slash command

### Reproduction Steps

```python
@slash_command()
async def test(self, ctx, channel: Option([discord.TextChannel, discord.VoiceChannel])):
    print(channel)
```

### Minimal Reproducible Code

```python
Traceback (most recent call last):
  File "C:\Users\Andrew\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\cog.py", line 705, in _load_from_module_spec
    spec.loader.exec_module(lib)  # type: ignore
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "c:\Users\Andrew\Documents\tuflya\cogs\sendmsg.py", line 8, in <module>
    class sendmsg(commands.Cog):
  File "c:\Users\Andrew\Documents\tuflya\cogs\sendmsg.py", line 14, in sendmsg
    channel: Option([discord.TextChannel, discord.VoiceChannel], "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043a\u0430\u043d\u0430\u043b"),
  File "C:\Users\Andrew\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\commands\options.py", line 72, in __init__
    _type = SlashCommandOptionType.from_datatype(input_type)
  File "C:\Users\Andrew\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\enums.py", line 670, in from_datatype
    if datatype.__name__ in ["Member", "User"]:
AttributeError: 'list' object has no attribute '__name__'. Did you mean: '__ne__'?
```


### Expected Results

channel arg should accept both types

### Actual Results

can't use multiple-type in slash command

### Intents

default, members

### System Information

Python Version: 3.10
Pycord Version: 2.0.0b4

### Checklist

- [X] I have searched the open issues for duplicates.
- [X] I have shown the entire traceback, if possible.
- [X] I have removed my token from display, if visible.

### Additional Context

_No response_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `discord/commands/options.py`
Content:
```
1 """
2 The MIT License (MIT)
3 
4 Copyright (c) 2021-present Pycord Development
5 
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23 """
24 
25 from typing import Any, Dict, List, Literal, Optional, Union
26 
27 from ..enums import ChannelType, SlashCommandOptionType
28 
29 __all__ = (
30     "ThreadOption",
31     "Option",
32     "OptionChoice",
33     "option",
34 )
35 
36 channel_type_map = {
37     "TextChannel": ChannelType.text,
38     "VoiceChannel": ChannelType.voice,
39     "StageChannel": ChannelType.stage_voice,
40     "CategoryChannel": ChannelType.category,
41     "Thread": ChannelType.public_thread,
42 }
43 
44 
45 class ThreadOption:
46     def __init__(self, thread_type: Literal["public", "private", "news"]):
47         type_map = {
48             "public": ChannelType.public_thread,
49             "private": ChannelType.private_thread,
50             "news": ChannelType.news_thread,
51         }
52         self._type = type_map[thread_type]
53 
54     @property
55     def __name__(self):
56         return "ThreadOption"
57 
58 
59 class Option:
60     """Represents a selectable option for a slash command.
61 
62     Examples
63     --------
64     Basic usage: ::
65 
66         @bot.slash_command(guild_ids=[...])
67         async def hello(
68             ctx: discord.ApplicationContext,
69             name: Option(str, "Enter your name"),
70             age: Option(int, "Enter your age", min_value=1, max_value=99, default=18)
71             # passing the default value makes an argument optional
72             # you also can create optional argument using:
73             # age: Option(int, "Enter your age") = 18
74         ):
75             await ctx.respond(f"Hello! Your name is {name} and you are {age} years old.")
76 
77     .. versionadded:: 2.0
78 
79     Attributes
80     ----------
81     input_type: :class:`Any`
82         The type of input that is expected for this option.
83     description: :class:`str`
84         The description of this option.
85         Must be 100 characters or fewer.
86     name: :class:`str`
87         The name of this option visible in the UI.
88         Inherits from the variable name if not provided as a parameter.
89     choices: Optional[List[Union[:class:`Any`, :class:`OptionChoice`]]]
90         The list of available choices for this option.
91         Can be a list of values or :class:`OptionChoice` objects (which represent a name:value pair).
92         If provided, the input from the user must match one of the choices in the list.
93     required: Optional[:class:`bool`]
94         Whether this option is required.
95     default: Optional[:class:`Any`]
96         The default value for this option. If provided, ``required`` will be considered ``False``.
97     min_value: Optional[:class:`int`]
98         The minimum value that can be entered.
99         Only applies to Options with an input_type of ``int`` or ``float``.
100     max_value: Optional[:class:`int`]
101         The maximum value that can be entered.
102         Only applies to Options with an input_type of ``int`` or ``float``.
103     autocomplete: Optional[:class:`Any`]
104         The autocomplete handler for the option. Accepts an iterable of :class:`str`, a callable (sync or async) that takes a
105         single argument of :class:`AutocompleteContext`, or a coroutine. Must resolve to an iterable of :class:`str`.
106 
107         .. note::
108 
109             Does not validate the input value against the autocomplete results.
110     name_localizations: Optional[Dict[:class:`str`, :class:`str`]]
111         The name localizations for this option. The values of this should be ``"locale": "name"``.
112         See `here <https://discord.com/developers/docs/reference#locales>`_ for a list of valid locales.
113     description_localizations: Optional[Dict[:class:`str`, :class:`str`]]
114         The description localizations for this option. The values of this should be ``"locale": "description"``.
115         See `here <https://discord.com/developers/docs/reference#locales>`_ for a list of valid locales.
116     """
117 
118     def __init__(self, input_type: Any, /, description: str = None, **kwargs) -> None:
119         self.name: Optional[str] = kwargs.pop("name", None)
120         if self.name is not None:
121             self.name = str(self.name)
122         self.description = description or "No description provided"
123         self.converter = None
124         self._raw_type = input_type
125         self.channel_types: List[ChannelType] = kwargs.pop("channel_types", [])
126         if not isinstance(input_type, SlashCommandOptionType):
127             if hasattr(input_type, "convert"):
128                 self.converter = input_type
129                 input_type = SlashCommandOptionType.string
130             else:
131                 try:
132                     _type = SlashCommandOptionType.from_datatype(input_type)
133                 except TypeError as exc:
134                     from ..ext.commands.converter import CONVERTER_MAPPING
135 
136                     if input_type not in CONVERTER_MAPPING:
137                         raise exc
138                     self.converter = CONVERTER_MAPPING[input_type]
139                     input_type = SlashCommandOptionType.string
140                 else:
141                     if _type == SlashCommandOptionType.channel:
142                         if not isinstance(input_type, tuple):
143                             input_type = (input_type,)
144                         for i in input_type:
145                             if i.__name__ == "GuildChannel":
146                                 continue
147                             if isinstance(i, ThreadOption):
148                                 self.channel_types.append(i._type)
149                                 continue
150 
151                             channel_type = channel_type_map[i.__name__]
152                             self.channel_types.append(channel_type)
153                     input_type = _type
154         self.input_type = input_type
155         self.required: bool = kwargs.pop("required", True) if "default" not in kwargs else False
156         self.default = kwargs.pop("default", None)
157         self.choices: List[OptionChoice] = [
158             o if isinstance(o, OptionChoice) else OptionChoice(o) for o in kwargs.pop("choices", list())
159         ]
160 
161         if self.input_type == SlashCommandOptionType.integer:
162             minmax_types = (int, type(None))
163         elif self.input_type == SlashCommandOptionType.number:
164             minmax_types = (int, float, type(None))
165         else:
166             minmax_types = (type(None),)
167         minmax_typehint = Optional[Union[minmax_types]]  # type: ignore
168 
169         self.min_value: minmax_typehint = kwargs.pop("min_value", None)
170         self.max_value: minmax_typehint = kwargs.pop("max_value", None)
171 
172         if not isinstance(self.min_value, minmax_types) and self.min_value is not None:
173             raise TypeError(f'Expected {minmax_typehint} for min_value, got "{type(self.min_value).__name__}"')
174         if not (isinstance(self.max_value, minmax_types) or self.min_value is None):
175             raise TypeError(f'Expected {minmax_typehint} for max_value, got "{type(self.max_value).__name__}"')
176 
177         self.autocomplete = kwargs.pop("autocomplete", None)
178 
179         self.name_localizations = kwargs.pop("name_localizations", None)
180         self.description_localizations = kwargs.pop("description_localizations", None)
181 
182     def to_dict(self) -> Dict:
183         as_dict = {
184             "name": self.name,
185             "description": self.description,
186             "type": self.input_type.value,
187             "required": self.required,
188             "choices": [c.to_dict() for c in self.choices],
189             "autocomplete": bool(self.autocomplete),
190         }
191         if self.name_localizations is not None:
192             as_dict["name_localizations"] = self.name_localizations
193         if self.description_localizations is not None:
194             as_dict["description_localizations"] = self.description_localizations
195         if self.channel_types:
196             as_dict["channel_types"] = [t.value for t in self.channel_types]
197         if self.min_value is not None:
198             as_dict["min_value"] = self.min_value
199         if self.max_value is not None:
200             as_dict["max_value"] = self.max_value
201 
202         return as_dict
203 
204     def __repr__(self):
205         return f"<discord.commands.{self.__class__.__name__} name={self.name}>"
206 
207 
208 class OptionChoice:
209     """
210     Represents a name:value pairing for a selected :class:`Option`.
211 
212     .. versionadded:: 2.0
213 
214     Attributes
215     ----------
216     name: :class:`str`
217         The name of the choice. Shown in the UI when selecting an option.
218     value: Optional[Union[:class:`str`, :class:`int`, :class:`float`]]
219         The value of the choice. If not provided, will use the value of ``name``.
220     name_localizations: Optional[Dict[:class:`str`, :class:`str`]]
221         The name localizations for this choice. The values of this should be ``"locale": "name"``.
222         See `here <https://discord.com/developers/docs/reference#locales>`_ for a list of valid locales.
223     """
224 
225     def __init__(
226         self,
227         name: str,
228         value: Optional[Union[str, int, float]] = None,
229         name_localizations: Optional[Dict[str, str]] = None,
230     ):
231         self.name = str(name)
232         self.value = value if value is not None else name
233         self.name_localizations = name_localizations
234 
235     def to_dict(self) -> Dict[str, Union[str, int, float]]:
236         as_dict = {"name": self.name, "value": self.value}
237         if self.name_localizations is not None:
238             as_dict["name_localizations"] = self.name_localizations
239 
240         return as_dict
241 
242 
243 def option(name, type=None, **kwargs):
244     """A decorator that can be used instead of typehinting Option"""
245 
246     def decorator(func):
247         nonlocal type
248         type = type or func.__annotations__.get(name, str)
249         func.__annotations__[name] = Option(type, **kwargs)
250         return func
251 
252     return decorator
253
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/discord/commands/options.py b/discord/commands/options.py
--- a/discord/commands/options.py
+++ b/discord/commands/options.py
@@ -139,7 +139,7 @@
                     input_type = SlashCommandOptionType.string
                 else:
                     if _type == SlashCommandOptionType.channel:
-                        if not isinstance(input_type, tuple):
+                        if not isinstance(input_type, list):
                             input_type = (input_type,)
                         for i in input_type:
                             if i.__name__ == "GuildChannel":

{"golden_diff": "diff --git a/discord/commands/options.py b/discord/commands/options.py\n--- a/discord/commands/options.py\n+++ b/discord/commands/options.py\n@@ -139,7 +139,7 @@\n                     input_type = SlashCommandOptionType.string\n                 else:\n                     if _type == SlashCommandOptionType.channel:\n-                        if not isinstance(input_type, tuple):\n+                        if not isinstance(input_type, list):\n                             input_type = (input_type,)\n                         for i in input_type:\n                             if i.__name__ == \"GuildChannel\":\n", "issue": "multiple-type arg option is beak\n### Summary\r\n\r\nCannot set multiple type for arg in slash command\r\n\r\n### Reproduction Steps\r\n\r\n```python\r\n@slash_command()\r\nasync def test(self, ctx, channel: Option([discord.TextChannel, discord.VoiceChannel])):\r\n    print(channel)\r\n```\r\n\r\n### Minimal Reproducible Code\r\n\r\n```python\r\nTraceback (most recent call last):\r\n  File \"C:\\Users\\Andrew\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\discord\\cog.py\", line 705, in _load_from_module_spec\r\n    spec.loader.exec_module(lib)  # type: ignore\r\n  File \"<frozen importlib._bootstrap_external>\", line 883, in exec_module\r\n  File \"<frozen importlib._bootstrap>\", line 241, in _call_with_frames_removed\r\n  File \"c:\\Users\\Andrew\\Documents\\tuflya\\cogs\\sendmsg.py\", line 8, in <module>\r\n    class sendmsg(commands.Cog):\r\n  File \"c:\\Users\\Andrew\\Documents\\tuflya\\cogs\\sendmsg.py\", line 14, in sendmsg\r\n    channel: Option([discord.TextChannel, discord.VoiceChannel], \"\\u0412\\u044b\\u0431\\u0435\\u0440\\u0438\\u0442\\u0435 \\u043a\\u0430\\u043d\\u0430\\u043b\"),\r\n  File \"C:\\Users\\Andrew\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\discord\\commands\\options.py\", line 72, in __init__\r\n    _type = SlashCommandOptionType.from_datatype(input_type)\r\n  File \"C:\\Users\\Andrew\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\discord\\enums.py\", line 670, in from_datatype\r\n    if datatype.__name__ in [\"Member\", \"User\"]:\r\nAttributeError: 'list' object has no attribute '__name__'. Did you mean: '__ne__'?\r\n```\r\n\r\n\r\n### Expected Results\r\n\r\nchannel arg should accept both types\r\n\r\n### Actual Results\r\n\r\ncan't use multiple-type in slash command\r\n\r\n### Intents\r\n\r\ndefault, members\r\n\r\n### System Information\r\n\r\nPython Version: 3.10\r\nPycord Version: 2.0.0b4\r\n\r\n### Checklist\r\n\r\n- [X] I have searched the open issues for duplicates.\r\n- [X] I have shown the entire traceback, if possible.\r\n- [X] I have removed my token from display, if visible.\r\n\r\n### Additional Context\r\n\r\n_No response_\n", "before_files": [{"content": "\"\"\"\nThe MIT License (MIT)\n\nCopyright (c) 2021-present Pycord Development\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n\"\"\"\n\nfrom typing import Any, Dict, List, Literal, Optional, Union\n\nfrom ..enums import ChannelType, SlashCommandOptionType\n\n__all__ = (\n    \"ThreadOption\",\n    \"Option\",\n    \"OptionChoice\",\n    \"option\",\n)\n\nchannel_type_map = {\n    \"TextChannel\": ChannelType.text,\n    \"VoiceChannel\": ChannelType.voice,\n    \"StageChannel\": ChannelType.stage_voice,\n    \"CategoryChannel\": ChannelType.category,\n    \"Thread\": ChannelType.public_thread,\n}\n\n\nclass ThreadOption:\n    def __init__(self, thread_type: Literal[\"public\", \"private\", \"news\"]):\n        type_map = {\n            \"public\": ChannelType.public_thread,\n            \"private\": ChannelType.private_thread,\n            \"news\": ChannelType.news_thread,\n        }\n        self._type = type_map[thread_type]\n\n    @property\n    def __name__(self):\n        return \"ThreadOption\"\n\n\nclass Option:\n    \"\"\"Represents a selectable option for a slash command.\n\n    Examples\n    --------\n    Basic usage: ::\n\n        @bot.slash_command(guild_ids=[...])\n        async def hello(\n            ctx: discord.ApplicationContext,\n            name: Option(str, \"Enter your name\"),\n            age: Option(int, \"Enter your age\", min_value=1, max_value=99, default=18)\n            # passing the default value makes an argument optional\n            # you also can create optional argument using:\n            # age: Option(int, \"Enter your age\") = 18\n        ):\n            await ctx.respond(f\"Hello! Your name is {name} and you are {age} years old.\")\n\n    .. versionadded:: 2.0\n\n    Attributes\n    ----------\n    input_type: :class:`Any`\n        The type of input that is expected for this option.\n    description: :class:`str`\n        The description of this option.\n        Must be 100 characters or fewer.\n    name: :class:`str`\n        The name of this option visible in the UI.\n        Inherits from the variable name if not provided as a parameter.\n    choices: Optional[List[Union[:class:`Any`, :class:`OptionChoice`]]]\n        The list of available choices for this option.\n        Can be a list of values or :class:`OptionChoice` objects (which represent a name:value pair).\n        If provided, the input from the user must match one of the choices in the list.\n    required: Optional[:class:`bool`]\n        Whether this option is required.\n    default: Optional[:class:`Any`]\n        The default value for this option. If provided, ``required`` will be considered ``False``.\n    min_value: Optional[:class:`int`]\n        The minimum value that can be entered.\n        Only applies to Options with an input_type of ``int`` or ``float``.\n    max_value: Optional[:class:`int`]\n        The maximum value that can be entered.\n        Only applies to Options with an input_type of ``int`` or ``float``.\n    autocomplete: Optional[:class:`Any`]\n        The autocomplete handler for the option. Accepts an iterable of :class:`str`, a callable (sync or async) that takes a\n        single argument of :class:`AutocompleteContext`, or a coroutine. Must resolve to an iterable of :class:`str`.\n\n        .. note::\n\n            Does not validate the input value against the autocomplete results.\n    name_localizations: Optional[Dict[:class:`str`, :class:`str`]]\n        The name localizations for this option. The values of this should be ``\"locale\": \"name\"``.\n        See `here <https://discord.com/developers/docs/reference#locales>`_ for a list of valid locales.\n    description_localizations: Optional[Dict[:class:`str`, :class:`str`]]\n        The description localizations for this option. The values of this should be ``\"locale\": \"description\"``.\n        See `here <https://discord.com/developers/docs/reference#locales>`_ for a list of valid locales.\n    \"\"\"\n\n    def __init__(self, input_type: Any, /, description: str = None, **kwargs) -> None:\n        self.name: Optional[str] = kwargs.pop(\"name\", None)\n        if self.name is not None:\n            self.name = str(self.name)\n        self.description = description or \"No description provided\"\n        self.converter = None\n        self._raw_type = input_type\n        self.channel_types: List[ChannelType] = kwargs.pop(\"channel_types\", [])\n        if not isinstance(input_type, SlashCommandOptionType):\n            if hasattr(input_type, \"convert\"):\n                self.converter = input_type\n                input_type = SlashCommandOptionType.string\n            else:\n                try:\n                    _type = SlashCommandOptionType.from_datatype(input_type)\n                except TypeError as exc:\n                    from ..ext.commands.converter import CONVERTER_MAPPING\n\n                    if input_type not in CONVERTER_MAPPING:\n                        raise exc\n                    self.converter = CONVERTER_MAPPING[input_type]\n                    input_type = SlashCommandOptionType.string\n                else:\n                    if _type == SlashCommandOptionType.channel:\n                        if not isinstance(input_type, tuple):\n                            input_type = (input_type,)\n                        for i in input_type:\n                            if i.__name__ == \"GuildChannel\":\n                                continue\n                            if isinstance(i, ThreadOption):\n                                self.channel_types.append(i._type)\n                                continue\n\n                            channel_type = channel_type_map[i.__name__]\n                            self.channel_types.append(channel_type)\n                    input_type = _type\n        self.input_type = input_type\n        self.required: bool = kwargs.pop(\"required\", True) if \"default\" not in kwargs else False\n        self.default = kwargs.pop(\"default\", None)\n        self.choices: List[OptionChoice] = [\n            o if isinstance(o, OptionChoice) else OptionChoice(o) for o in kwargs.pop(\"choices\", list())\n        ]\n\n        if self.input_type == SlashCommandOptionType.integer:\n            minmax_types = (int, type(None))\n        elif self.input_type == SlashCommandOptionType.number:\n            minmax_types = (int, float, type(None))\n        else:\n            minmax_types = (type(None),)\n        minmax_typehint = Optional[Union[minmax_types]]  # type: ignore\n\n        self.min_value: minmax_typehint = kwargs.pop(\"min_value\", None)\n        self.max_value: minmax_typehint = kwargs.pop(\"max_value\", None)\n\n        if not isinstance(self.min_value, minmax_types) and self.min_value is not None:\n            raise TypeError(f'Expected {minmax_typehint} for min_value, got \"{type(self.min_value).__name__}\"')\n        if not (isinstance(self.max_value, minmax_types) or self.min_value is None):\n            raise TypeError(f'Expected {minmax_typehint} for max_value, got \"{type(self.max_value).__name__}\"')\n\n        self.autocomplete = kwargs.pop(\"autocomplete\", None)\n\n        self.name_localizations = kwargs.pop(\"name_localizations\", None)\n        self.description_localizations = kwargs.pop(\"description_localizations\", None)\n\n    def to_dict(self) -> Dict:\n        as_dict = {\n            \"name\": self.name,\n            \"description\": self.description,\n            \"type\": self.input_type.value,\n            \"required\": self.required,\n            \"choices\": [c.to_dict() for c in self.choices],\n            \"autocomplete\": bool(self.autocomplete),\n        }\n        if self.name_localizations is not None:\n            as_dict[\"name_localizations\"] = self.name_localizations\n        if self.description_localizations is not None:\n            as_dict[\"description_localizations\"] = self.description_localizations\n        if self.channel_types:\n            as_dict[\"channel_types\"] = [t.value for t in self.channel_types]\n        if self.min_value is not None:\n            as_dict[\"min_value\"] = self.min_value\n        if self.max_value is not None:\n            as_dict[\"max_value\"] = self.max_value\n\n        return as_dict\n\n    def __repr__(self):\n        return f\"<discord.commands.{self.__class__.__name__} name={self.name}>\"\n\n\nclass OptionChoice:\n    \"\"\"\n    Represents a name:value pairing for a selected :class:`Option`.\n\n    .. versionadded:: 2.0\n\n    Attributes\n    ----------\n    name: :class:`str`\n        The name of the choice. Shown in the UI when selecting an option.\n    value: Optional[Union[:class:`str`, :class:`int`, :class:`float`]]\n        The value of the choice. If not provided, will use the value of ``name``.\n    name_localizations: Optional[Dict[:class:`str`, :class:`str`]]\n        The name localizations for this choice. The values of this should be ``\"locale\": \"name\"``.\n        See `here <https://discord.com/developers/docs/reference#locales>`_ for a list of valid locales.\n    \"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        value: Optional[Union[str, int, float]] = None,\n        name_localizations: Optional[Dict[str, str]] = None,\n    ):\n        self.name = str(name)\n        self.value = value if value is not None else name\n        self.name_localizations = name_localizations\n\n    def to_dict(self) -> Dict[str, Union[str, int, float]]:\n        as_dict = {\"name\": self.name, \"value\": self.value}\n        if self.name_localizations is not None:\n            as_dict[\"name_localizations\"] = self.name_localizations\n\n        return as_dict\n\n\ndef option(name, type=None, **kwargs):\n    \"\"\"A decorator that can be used instead of typehinting Option\"\"\"\n\n    def decorator(func):\n        nonlocal type\n        type = type or func.__annotations__.get(name, str)\n        func.__annotations__[name] = Option(type, **kwargs)\n        return func\n\n    return decorator\n", "path": "discord/commands/options.py"}], "after_files": [{"content": "\"\"\"\nThe MIT License (MIT)\n\nCopyright (c) 2021-present Pycord Development\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n\"\"\"\n\nfrom typing import Any, Dict, List, Literal, Optional, Union\n\nfrom ..enums import ChannelType, SlashCommandOptionType\n\n__all__ = (\n    \"ThreadOption\",\n    \"Option\",\n    \"OptionChoice\",\n    \"option\",\n)\n\nchannel_type_map = {\n    \"TextChannel\": ChannelType.text,\n    \"VoiceChannel\": ChannelType.voice,\n    \"StageChannel\": ChannelType.stage_voice,\n    \"CategoryChannel\": ChannelType.category,\n    \"Thread\": ChannelType.public_thread,\n}\n\n\nclass ThreadOption:\n    def __init__(self, thread_type: Literal[\"public\", \"private\", \"news\"]):\n        type_map = {\n            \"public\": ChannelType.public_thread,\n            \"private\": ChannelType.private_thread,\n            \"news\": ChannelType.news_thread,\n        }\n        self._type = type_map[thread_type]\n\n    @property\n    def __name__(self):\n        return \"ThreadOption\"\n\n\nclass Option:\n    \"\"\"Represents a selectable option for a slash command.\n\n    Examples\n    --------\n    Basic usage: ::\n\n        @bot.slash_command(guild_ids=[...])\n        async def hello(\n            ctx: discord.ApplicationContext,\n            name: Option(str, \"Enter your name\"),\n            age: Option(int, \"Enter your age\", min_value=1, max_value=99, default=18)\n            # passing the default value makes an argument optional\n            # you also can create optional argument using:\n            # age: Option(int, \"Enter your age\") = 18\n        ):\n            await ctx.respond(f\"Hello! Your name is {name} and you are {age} years old.\")\n\n    .. versionadded:: 2.0\n\n    Attributes\n    ----------\n    input_type: :class:`Any`\n        The type of input that is expected for this option.\n    description: :class:`str`\n        The description of this option.\n        Must be 100 characters or fewer.\n    name: :class:`str`\n        The name of this option visible in the UI.\n        Inherits from the variable name if not provided as a parameter.\n    choices: Optional[List[Union[:class:`Any`, :class:`OptionChoice`]]]\n        The list of available choices for this option.\n        Can be a list of values or :class:`OptionChoice` objects (which represent a name:value pair).\n        If provided, the input from the user must match one of the choices in the list.\n    required: Optional[:class:`bool`]\n        Whether this option is required.\n    default: Optional[:class:`Any`]\n        The default value for this option. If provided, ``required`` will be considered ``False``.\n    min_value: Optional[:class:`int`]\n        The minimum value that can be entered.\n        Only applies to Options with an input_type of ``int`` or ``float``.\n    max_value: Optional[:class:`int`]\n        The maximum value that can be entered.\n        Only applies to Options with an input_type of ``int`` or ``float``.\n    autocomplete: Optional[:class:`Any`]\n        The autocomplete handler for the option. Accepts an iterable of :class:`str`, a callable (sync or async) that takes a\n        single argument of :class:`AutocompleteContext`, or a coroutine. Must resolve to an iterable of :class:`str`.\n\n        .. note::\n\n            Does not validate the input value against the autocomplete results.\n    name_localizations: Optional[Dict[:class:`str`, :class:`str`]]\n        The name localizations for this option. The values of this should be ``\"locale\": \"name\"``.\n        See `here <https://discord.com/developers/docs/reference#locales>`_ for a list of valid locales.\n    description_localizations: Optional[Dict[:class:`str`, :class:`str`]]\n        The description localizations for this option. The values of this should be ``\"locale\": \"description\"``.\n        See `here <https://discord.com/developers/docs/reference#locales>`_ for a list of valid locales.\n    \"\"\"\n\n    def __init__(self, input_type: Any, /, description: str = None, **kwargs) -> None:\n        self.name: Optional[str] = kwargs.pop(\"name\", None)\n        if self.name is not None:\n            self.name = str(self.name)\n        self.description = description or \"No description provided\"\n        self.converter = None\n        self._raw_type = input_type\n        self.channel_types: List[ChannelType] = kwargs.pop(\"channel_types\", [])\n        if not isinstance(input_type, SlashCommandOptionType):\n            if hasattr(input_type, \"convert\"):\n                self.converter = input_type\n                input_type = SlashCommandOptionType.string\n            else:\n                try:\n                    _type = SlashCommandOptionType.from_datatype(input_type)\n                except TypeError as exc:\n                    from ..ext.commands.converter import CONVERTER_MAPPING\n\n                    if input_type not in CONVERTER_MAPPING:\n                        raise exc\n                    self.converter = CONVERTER_MAPPING[input_type]\n                    input_type = SlashCommandOptionType.string\n                else:\n                    if _type == SlashCommandOptionType.channel:\n                        if not isinstance(input_type, list):\n                            input_type = (input_type,)\n                        for i in input_type:\n                            if i.__name__ == \"GuildChannel\":\n                                continue\n                            if isinstance(i, ThreadOption):\n                                self.channel_types.append(i._type)\n                                continue\n\n                            channel_type = channel_type_map[i.__name__]\n                            self.channel_types.append(channel_type)\n                    input_type = _type\n        self.input_type = input_type\n        self.required: bool = kwargs.pop(\"required\", True) if \"default\" not in kwargs else False\n        self.default = kwargs.pop(\"default\", None)\n        self.choices: List[OptionChoice] = [\n            o if isinstance(o, OptionChoice) else OptionChoice(o) for o in kwargs.pop(\"choices\", list())\n        ]\n\n        if self.input_type == SlashCommandOptionType.integer:\n            minmax_types = (int, type(None))\n        elif self.input_type == SlashCommandOptionType.number:\n            minmax_types = (int, float, type(None))\n        else:\n            minmax_types = (type(None),)\n        minmax_typehint = Optional[Union[minmax_types]]  # type: ignore\n\n        self.min_value: minmax_typehint = kwargs.pop(\"min_value\", None)\n        self.max_value: minmax_typehint = kwargs.pop(\"max_value\", None)\n\n        if not isinstance(self.min_value, minmax_types) and self.min_value is not None:\n            raise TypeError(f'Expected {minmax_typehint} for min_value, got \"{type(self.min_value).__name__}\"')\n        if not (isinstance(self.max_value, minmax_types) or self.min_value is None):\n            raise TypeError(f'Expected {minmax_typehint} for max_value, got \"{type(self.max_value).__name__}\"')\n\n        self.autocomplete = kwargs.pop(\"autocomplete\", None)\n\n        self.name_localizations = kwargs.pop(\"name_localizations\", None)\n        self.description_localizations = kwargs.pop(\"description_localizations\", None)\n\n    def to_dict(self) -> Dict:\n        as_dict = {\n            \"name\": self.name,\n            \"description\": self.description,\n            \"type\": self.input_type.value,\n            \"required\": self.required,\n            \"choices\": [c.to_dict() for c in self.choices],\n            \"autocomplete\": bool(self.autocomplete),\n        }\n        if self.name_localizations is not None:\n            as_dict[\"name_localizations\"] = self.name_localizations\n        if self.description_localizations is not None:\n            as_dict[\"description_localizations\"] = self.description_localizations\n        if self.channel_types:\n            as_dict[\"channel_types\"] = [t.value for t in self.channel_types]\n        if self.min_value is not None:\n            as_dict[\"min_value\"] = self.min_value\n        if self.max_value is not None:\n            as_dict[\"max_value\"] = self.max_value\n\n        return as_dict\n\n    def __repr__(self):\n        return f\"<discord.commands.{self.__class__.__name__} name={self.name}>\"\n\n\nclass OptionChoice:\n    \"\"\"\n    Represents a name:value pairing for a selected :class:`Option`.\n\n    .. versionadded:: 2.0\n\n    Attributes\n    ----------\n    name: :class:`str`\n        The name of the choice. Shown in the UI when selecting an option.\n    value: Optional[Union[:class:`str`, :class:`int`, :class:`float`]]\n        The value of the choice. If not provided, will use the value of ``name``.\n    name_localizations: Optional[Dict[:class:`str`, :class:`str`]]\n        The name localizations for this choice. The values of this should be ``\"locale\": \"name\"``.\n        See `here <https://discord.com/developers/docs/reference#locales>`_ for a list of valid locales.\n    \"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        value: Optional[Union[str, int, float]] = None,\n        name_localizations: Optional[Dict[str, str]] = None,\n    ):\n        self.name = str(name)\n        self.value = value if value is not None else name\n        self.name_localizations = name_localizations\n\n    def to_dict(self) -> Dict[str, Union[str, int, float]]:\n        as_dict = {\"name\": self.name, \"value\": self.value}\n        if self.name_localizations is not None:\n            as_dict[\"name_localizations\"] = self.name_localizations\n\n        return as_dict\n\n\ndef option(name, type=None, **kwargs):\n    \"\"\"A decorator that can be used instead of typehinting Option\"\"\"\n\n    def decorator(func):\n        nonlocal type\n        type = type or func.__annotations__.get(name, str)\n        func.__annotations__[name] = Option(type, **kwargs)\n        return func\n\n    return decorator\n", "path": "discord/commands/options.py"}]}