Repository: Pycord-Development/pycord

Issue:
Inconsistent default arguments in bridge commands
### Summary

Bridge commands do not always handle default arguments in the same way

### Reproduction Steps

1. Create a bridge command with non-required argument (via Option kwargs)
2. Try to run it without the argument in question

### Minimal Reproducible Code

```python
import os

import discord
from discord.ext import bridge
# Option MUST be imported after ext.bridge
# otherwise it won't work with bridge commands
from discord import Option


bot = bridge.Bot()


@bot.bridge_command()
async def test_default1(ctx, text: Option(str) = "hello"):
    await ctx.respond(text)


@bot.bridge_command()
async def test_default2(ctx, text: Option(str, default="hello")):
    await ctx.respond(text)


@bot.bridge_command()
async def test_no_default(ctx, text: Option(str, required=False)):
    await ctx.respond(text or "hello")


bot.run(os.getenv("TOKEN"))
```


### Expected Results

I'd expect all three commands from the above code to produce the same output when the argument isn't provided, like it does for slash variants:
![Screenshot_20230528-133333989 (1)](https://github.com/Pycord-Development/pycord/assets/60041069/f6a5901f-0493-49af-a8ef-642a6be0882e)


### Actual Results

However, only the first one works:
![Screenshot_20230528-133607047 (1)](https://github.com/Pycord-Development/pycord/assets/60041069/61027cfa-9b12-476b-af99-28bad240b33f)
Others are throwing an error:
```
Traceback (most recent call last):
  File "/data/data/com.termux/files/home/tests/lib/python3.11/site-packages/discord/ext/bridge/bot.py", line 143, in invoke
    await ctx.command.invoke(ctx)
  File "/data/data/com.termux/files/home/tests/lib/python3.11/site-packages/discord/ext/commands/core.py", line 942, in invoke
    await self.prepare(ctx)
  File "/data/data/com.termux/files/home/tests/lib/python3.11/site-packages/discord/ext/commands/core.py", line 872, in prepare
    await self._parse_arguments(ctx)
  File "/data/data/com.termux/files/home/tests/lib/python3.11/site-packages/discord/ext/commands/core.py", line 774, in _parse_arguments
    transformed = await self.transform(ctx, param)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/data/data/com.termux/files/home/tests/lib/python3.11/site-packages/discord/ext/bridge/core.py", line 105, in transform
    return await super().transform(ctx, param)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/data/data/com.termux/files/home/tests/lib/python3.11/site-packages/discord/ext/commands/core.py", line 601, in transform
    raise MissingRequiredArgument(param)
discord.ext.commands.errors.MissingRequiredArgument: text is a required argument that is missing.
```

### Intents

None

### System Information

- Python v3.11.2-final
- py-cord v2.4.1-final
- aiohttp v3.8.4
- system info: `Linux 4.14.232-QuicksilveR™-ReloadedOS-Edition #1 SMP PREEMPT Wed May 26 07:08:17 UTC 2021`


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

Not related to this particular issue, but I don't quite like how Option works with bridge commands. Relying on the order of imports is something very non-obvious, confusing and, iirc, not documented.


Discussion:
Not sure when but it was fixed, but testing your code seems to work fine on latest (927f8cefb0a5ba8ed5f2c7ccad3f734852bef62e).
![image](https://github.com/Pycord-Development/pycord/assets/78228142/ca835718-7cf4-4b0f-8ad5-62aea3dd1944)

I also think modifying Option on import is a bit hacky, and the solution seems to just force people to use BridgeOption, so that's what I'll do.
@Middledot your screenshot shows slash invocation, have you tried prefix invocation?

Also, `BridgeOption` is not documented and can only be accessed as `bridge.core.BridgeOption` which suggests that it's part of internal API.

Resolving patch:
diff --git a/discord/ext/commands/core.py b/discord/ext/commands/core.py
--- a/discord/ext/commands/core.py
+++ b/discord/ext/commands/core.py
@@ -45,6 +45,7 @@
 
 from ...commands import (
     ApplicationCommand,
+    Option,
     _BaseCommand,
     message_command,
     slash_command,
@@ -562,7 +563,13 @@ async def dispatch_error(self, ctx: Context, error: Exception) -> None:
             ctx.bot.dispatch("command_error", ctx, error)
 
     async def transform(self, ctx: Context, param: inspect.Parameter) -> Any:
-        required = param.default is param.empty
+        if isinstance(param.annotation, Option):
+            default = param.annotation.default
+            required = param.annotation.required or default is None
+        else:
+            default = param.default
+            required = default is param.empty
+
         converter = get_converter(param)
         consume_rest_is_special = (
             param.kind == param.KEYWORD_ONLY and not self.rest_is_raw
@@ -599,7 +606,7 @@ async def transform(self, ctx: Context, param: inspect.Parameter) -> Any:
                 ):
                     return await converter._construct_default(ctx)
                 raise MissingRequiredArgument(param)
-            return param.default
+            return default
 
         previous = view.index
         if consume_rest_is_special:


Test patch: