Repository: Pycord-Development/pycord

Issue:
slash command option input type "mentionable" issue
### Summary

When you mention role in slash command, exception occures

### Reproduction Steps

run code below and try to mention a role in slash command

### Minimal Reproducible Code

```python
bot = discord.Bot()
@bot.slash_command(guild_ids=["id"])
async def command(
    ctx,
    var: discord.Option((discord.Role, discord.User))
):
    print(var)

bot.run("token")
```


### Expected Results

- if user mentioned in slash command, prints user object. ✅

- if role mentioned in slash command, prints role object. ❌


### Actual Results

- The following traceback is printed:

```
Ignoring exception in command <discord.commands.SlashCommand name=command>:
Traceback (most recent call last):
  File "C:\Users\{username}\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\commands\core.py", line 110, in wrapped
  File "C:\Users\{username}\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\http.py", line 334, in request
    raise NotFound(response, data)
discord.errors.NotFound: 404 Not Found (error code: 10013): Unknown User

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\{username}\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\bot.py", line 520, in process_application_commands
    await ctx.command.invoke(ctx)
  File "C:\Users\{username}\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\commands\core.py", line 306, in invoke
    await injected(ctx)
  File "C:\Users\{username}\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\commands\core.py", line 116, in wrapped
    raise ApplicationCommandInvokeError(exc) from exc
discord.commands.errors.ApplicationCommandInvokeError: Application Command raised an exception: NotFound: 404 Not Found (error code: 10013): Unknown User
```

### Intents

all

### System Information

- Python v3.10.2-final
- py-cord v2.0.0-beta
    - py-cord pkg_resources: v2.0.0b4897+g4dadb69d
- aiohttp v3.8.1
- system info: Windows 10 10.0.22000

### 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_


Discussion:
use `Union[discord.Member, discord.Role]`
This still seems to be an issue, trying to use the `discord.Role` option type and am getting 
```
Traceback (most recent call last):
  File "C:\Users\\Desktop\wolfy-bot\test\venv\lib\site-packages\discord\commands\core.py", line 113, in wrapped
    ret = await coro(arg)
  File "C:\Users\\Desktop\wolfy-bot\test\venv\lib\site-packages\discord\commands\core.py", line 775, in _invoke
    arg = await get_or_fetch(
  File "C:\Users\\Desktop\wolfy-bot\test\venv\lib\site-packages\discord\utils.py", line 483, in get_or_fetch
    getter = await getattr(obj, f"fetch_{attr}")(id)
AttributeError: 'Guild' object has no attribute 'fetch_role'
```
https://canary.discord.com/channels/881207955029110855/881735314987708456/946771231569481768
that is a link to the discussion with more information.

if this is a different problem tell me to create a new issue



Resolving patch:
diff --git a/discord/commands/core.py b/discord/commands/core.py
--- a/discord/commands/core.py
+++ b/discord/commands/core.py
@@ -50,7 +50,7 @@
 )
 
 from ..enums import ChannelType, SlashCommandOptionType
-from ..errors import ClientException, ValidationError
+from ..errors import ClientException, ValidationError, NotFound
 from ..member import Member
 from ..message import Attachment, Message
 from ..user import User
@@ -744,9 +744,10 @@ async def _invoke(self, ctx: ApplicationContext) -> None:
 
             elif op.input_type == SlashCommandOptionType.mentionable:
                 arg_id = int(arg)
-                arg = await get_or_fetch(ctx.guild, "member", arg_id)
-                if arg is None:
-                    arg = ctx.guild.get_role(arg_id) or arg_id
+                try:
+                    arg = await get_or_fetch(ctx.guild, "member", arg_id)
+                except NotFound:
+                    arg = await get_or_fetch(ctx.guild, "role", arg_id)
 
             elif op.input_type == SlashCommandOptionType.string and (converter := op.converter) is not None:
                 arg = await converter.convert(converter, ctx, arg)
diff --git a/discord/guild.py b/discord/guild.py
--- a/discord/guild.py
+++ b/discord/guild.py
@@ -2474,6 +2474,38 @@ async def fetch_roles(self) -> List[Role]:
         data = await self._state.http.get_roles(self.id)
         return [Role(guild=self, state=self._state, data=d) for d in data]
 
+    async def _fetch_role(self, role_id: int) -> Role:
+        """|coro|
+
+        Retrieves a :class:`Role` that the guild has.
+
+        .. note::
+
+            This method is an API call. For general usage, consider using :attr:`get_role` instead.
+
+        .. versionadded:: 2.0
+
+        Parameters
+        -----------
+        role_id: :class:`int`
+            The role ID to fetch from the guild.
+
+        Raises
+        -------
+        HTTPException
+            Retrieving the role failed.
+
+        Returns
+        -------
+        Optional[:class:`Role`]
+            The role in the guild with the specified ID.
+            Returns ``None`` if not found.
+        """
+        roles = await self.fetch_roles()
+        for role in roles:
+            if role.id == role_id:
+                return role
+
     @overload
     async def create_role(
         self,
diff --git a/discord/utils.py b/discord/utils.py
--- a/discord/utils.py
+++ b/discord/utils.py
@@ -377,7 +377,7 @@ def time_snowflake(dt: datetime.datetime, high: bool = False) -> int:
         The snowflake representing the time given.
     """
     discord_millis = int(dt.timestamp() * 1000 - DISCORD_EPOCH)
-    return (discord_millis << 22) + (2**22 - 1 if high else 0)
+    return (discord_millis << 22) + (2 ** 22 - 1 if high else 0)
 
 
 def find(predicate: Callable[[T], Any], seq: Iterable[T]) -> Optional[T]:
@@ -477,6 +477,8 @@ async def get_or_fetch(obj, attr: str, id: int, *, default: Any = MISSING):
     if getter is None:
         try:
             getter = await getattr(obj, f"fetch_{attr}")(id)
+        except AttributeError:
+            getter = await getattr(obj, f"_fetch_{attr}")(id)
         except HTTPException:
             if default is not MISSING:
                 return default


Test patch: