Repository: Pycord-Development/pycord

Issue:
DeprecationWarning for BridgeOption raised at module level
### Summary

The DeprecationWarning for `bridge.Option` is raised at the module level, and therefore shows when imported

### Reproduction Steps

1. Import discord.ext.bridge
2. Observe the warning in console

### Minimal Reproducible Code

```python
from discord.ext.bridge import *
```


### Expected Results

Only warn if the deprecated class is used

### Actual Results

Always warn, even if the class isn't used

### Intents

N/A

### System Information

- Python v3.12.0-final
- py-cord v2.5.1-final
- aiohttp v3.9.5
- system info: Darwin 23.4.0 Darwin Kernel Version 23.4.0: Wed Feb 21 21:44:06 PST 2024; root:xnu-10063.101.15~2/RELEASE_ARM64_T8103


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

Resolving patch:
diff --git a/discord/ext/bridge/core.py b/discord/ext/bridge/core.py
--- a/discord/ext/bridge/core.py
+++ b/discord/ext/bridge/core.py
@@ -96,6 +96,28 @@ class BridgeExtCommand(Command):
     def __init__(self, func, **kwargs):
         super().__init__(func, **kwargs)
 
+        # TODO: v2.7: Remove backwards support for Option in bridge commands.
+        for name, option in self.params.items():
+            if isinstance(option.annotation, Option) and not isinstance(
+                option.annotation, BridgeOption
+            ):
+                # Warn not to do this
+                warn_deprecated(
+                    "Using Option for bridge commands",
+                    "BridgeOption",
+                    "2.5",
+                    "2.7",
+                    reference="https://github.com/Pycord-Development/pycord/pull/2417",
+                    stacklevel=6,
+                )
+                # Override the convert method of the parameter's annotated Option.
+                # We can use the convert method from BridgeOption, and bind "self"
+                # using a manual invocation of the descriptor protocol.
+                # Definitely not a good approach, but gets the job done until removal.
+                self.params[name].annotation.convert = BridgeOption.convert.__get__(
+                    self.params[name].annotation
+                )
+
     async def dispatch_error(self, ctx: BridgeExtContext, error: Exception) -> None:
         await super().dispatch_error(ctx, error)
         ctx.bot.dispatch("bridge_command_error", ctx, error)
@@ -653,13 +675,3 @@ def decorator(func):
         return func
 
     return decorator
-
-
-discord.commands.options.Option = BridgeOption
-discord.Option = BridgeOption
-warn_deprecated(
-    "Option",
-    "BridgeOption",
-    "2.5",
-    reference="https://github.com/Pycord-Development/pycord/pull/2417",
-)
diff --git a/discord/utils.py b/discord/utils.py
--- a/discord/utils.py
+++ b/discord/utils.py
@@ -296,6 +296,7 @@ def warn_deprecated(
     since: str | None = None,
     removed: str | None = None,
     reference: str | None = None,
+    stacklevel: int = 3,
 ) -> None:
     """Warn about a deprecated function, with the ability to specify details about the deprecation. Emits a
     DeprecationWarning.
@@ -315,6 +316,8 @@ def warn_deprecated(
     reference: Optional[:class:`str`]
         A reference that explains the deprecation, typically a URL to a page such as a changelog entry or a GitHub
         issue/PR.
+    stacklevel: :class:`int`
+        The stacklevel kwarg passed to :func:`warnings.warn`. Defaults to 3.
     """
     warnings.simplefilter("always", DeprecationWarning)  # turn off filter
     message = f"{name} is deprecated"
@@ -328,7 +331,7 @@ def warn_deprecated(
     if reference:
         message += f" See {reference} for more information."
 
-    warnings.warn(message, stacklevel=3, category=DeprecationWarning)
+    warnings.warn(message, stacklevel=stacklevel, category=DeprecationWarning)
     warnings.simplefilter("default", DeprecationWarning)  # reset filter
 
 
@@ -337,6 +340,7 @@ def deprecated(
     since: str | None = None,
     removed: str | None = None,
     reference: str | None = None,
+    stacklevel: int = 3,
     *,
     use_qualname: bool = True,
 ) -> Callable[[Callable[[P], T]], Callable[[P], T]]:
@@ -356,6 +360,8 @@ def deprecated(
     reference: Optional[:class:`str`]
         A reference that explains the deprecation, typically a URL to a page such as a changelog entry or a GitHub
         issue/PR.
+    stacklevel: :class:`int`
+        The stacklevel kwarg passed to :func:`warnings.warn`. Defaults to 3.
     use_qualname: :class:`bool`
         Whether to use the qualified name of the function in the deprecation warning. If ``False``, the short name of
         the function will be used instead. For example, __qualname__ will display as ``Client.login`` while __name__


Test patch: