Repository: interactions-py/interactions.py

Issue:
[BUG] stacking extension_component() not working
### Describe the bug.

When trying to stack extension_component decorators, only the first one is reacting.
Stacking of @bot.component(..) works with the same custom_ids as expected.

Don´t work whether in latest nor unstable

Code Main:
```
import interactions
bot = interactions.Client(...)
bot.load("responsefilename")

if __name__ == "__main__":
    bot.start()
```

Code Ext:
```
import interactions
class Response(interactions.Extension):
    def __init__(self, client: interactions.Client) -> None:
        self.client=client

    @interactions.extension_component("resp_1")
    @interactions.extension_component("resp_2")
    ....
    @interactions.extension_component("resp_9")
    async def boost_col_response(self, ctx: interactions.ComponentContext):
       #dostuff

def setup(client):
    Response(client)
```


### List the steps.

1. import interactions in external file and main
2. load ext
3. stack interactions.extension_component("")

### What you expected.

It should react to all custom_ids which defined in the decorators.

### What you saw.

It only react to the custom_id of the very first decorator.

### What version of the library did you use?

release

### Version specification

_No response_

### Code of Conduct

- [X] I agree to follow the contribution requirements.


Discussion:

Resolving patch:
diff --git a/interactions/client/bot.py b/interactions/client/bot.py
--- a/interactions/client/bot.py
+++ b/interactions/client/bot.py
@@ -1806,38 +1806,40 @@ def __new__(cls, client: Client, *args, **kwargs) -> "Extension":
         for name, func in getmembers(self, predicate=iscoroutinefunction):
             # TODO we can make these all share the same list, might make it easier to load/unload
             if hasattr(func, "__listener_name__"):  # set by extension_listener
-                func = client.event(
-                    func, name=func.__listener_name__
-                )  # capture the return value for friendlier ext-ing
+                all_listener_names: List[str] = func.__listener_name__
+                for listener_name in all_listener_names:
+                    func = client.event(
+                        func, name=listener_name
+                    )  # capture the return value for friendlier ext-ing
 
-                listeners = self._listeners.get(func.__listener_name__, [])
-                listeners.append(func)
-                self._listeners[func.__listener_name__] = listeners
+                    listeners = self._listeners.get(listener_name, [])
+                    listeners.append(func)
+                    self._listeners[listener_name] = listeners
 
             if hasattr(func, "__component_data__"):
-                args, kwargs = func.__component_data__
-                func = client.component(*args, **kwargs)(func)
-
-                component = kwargs.get("component") or args[0]
-                comp_name = (
-                    _component(component).custom_id
-                    if isinstance(component, (Button, SelectMenu))
-                    else component
-                )
-                comp_name = f"component_{comp_name}"
+                all_component_data: List[Tuple[tuple, dict]] = func.__component_data__
+                for args, kwargs in all_component_data:
+                    func = client.component(*args, **kwargs)(func)
+
+                    component = kwargs.get("component") or args[0]
+                    comp_name = (
+                        _component(component).custom_id
+                        if isinstance(component, (Button, SelectMenu))
+                        else component
+                    )
+                    comp_name = f"component_{comp_name}"
 
-                listeners = self._listeners.get(comp_name, [])
-                listeners.append(func)
-                self._listeners[comp_name] = listeners
+                    listeners = self._listeners.get(comp_name, [])
+                    listeners.append(func)
+                    self._listeners[comp_name] = listeners
 
             if hasattr(func, "__autocomplete_data__"):
                 all_args_kwargs = func.__autocomplete_data__
-                for _ in all_args_kwargs:
-                    args, kwargs = _[0], _[1]
+                for args, kwargs in all_args_kwargs:
                     func = client.autocomplete(*args, **kwargs)(func)
 
-                    name = kwargs.get("name") or args[0]
-                    _command = kwargs.get("command") or args[1]
+                    _command = kwargs.get("command") or args[0]
+                    name = kwargs.get("name") or args[1]
 
                     _command: Union[Snowflake, int] = (
                         _command.id if isinstance(_command, ApplicationCommand) else _command
@@ -1850,16 +1852,17 @@ def __new__(cls, client: Client, *args, **kwargs) -> "Extension":
                     self._listeners[auto_name] = listeners
 
             if hasattr(func, "__modal_data__"):
-                args, kwargs = func.__modal_data__
-                func = client.modal(*args, **kwargs)(func)
+                all_modal_data: List[Tuple[tuple, dict]] = func.__modal_data__
+                for args, kwargs in all_modal_data:
+                    func = client.modal(*args, **kwargs)(func)
 
-                modal = kwargs.get("modal") or args[0]
-                _modal_id: str = modal.custom_id if isinstance(modal, Modal) else modal
-                modal_name = f"modal_{_modal_id}"
+                    modal = kwargs.get("modal") or args[0]
+                    _modal_id: str = modal.custom_id if isinstance(modal, Modal) else modal
+                    modal_name = f"modal_{_modal_id}"
 
-                listeners = self._listeners.get(modal_name, [])
-                listeners.append(func)
-                self._listeners[modal_name] = listeners
+                    listeners = self._listeners.get(modal_name, [])
+                    listeners.append(func)
+                    self._listeners[modal_name] = listeners
 
         for _, cmd in getmembers(self, predicate=lambda command: isinstance(command, Command)):
             cmd: Command
@@ -1923,14 +1926,15 @@ def decorator(coro) -> Command:
 
 def extension_listener(func: Optional[Coroutine] = None, name: Optional[str] = None):
     def decorator(func: Coroutine):
-        func.__listener_name__ = name or func.__name__
+        if not hasattr(func, "__listener_name__"):
+            func.__listener_name__ = []
+        func.__listener_name__.append(name or func.__name__)
 
         return func
 
     if func:
         # allows omitting `()` on `@listener`
-        func.__listener_name__ = name or func.__name__
-        return func
+        return decorator(func)
 
     return decorator
 
@@ -1938,7 +1942,10 @@ def decorator(func: Coroutine):
 @wraps(Client.component)
 def extension_component(*args, **kwargs):
     def decorator(func):
-        func.__component_data__ = (args, kwargs)
+        if not hasattr(func, "__component_data__"):
+            func.__component_data__ = []
+        func.__component_data__.append((args, kwargs))
+
         return func
 
     return decorator
@@ -1947,13 +1954,11 @@ def decorator(func):
 @wraps(Client.autocomplete)
 def extension_autocomplete(*args, **kwargs):
     def decorator(func):
-        try:
-            if getattr(func, "__autocomplete_data__"):
-                func.__autocomplete_data__.append((args, kwargs))
-        except AttributeError:
-            func.__autocomplete_data__ = [(args, kwargs)]
-        finally:
-            return func
+        if not hasattr(func, "__autocomplete_data__"):
+            func.__autocomplete_data__ = []
+        func.__autocomplete_data__.append((args, kwargs))
+
+        return func
 
     return decorator
 
@@ -1961,7 +1966,10 @@ def decorator(func):
 @wraps(Client.modal)
 def extension_modal(*args, **kwargs):
     def decorator(func):
-        func.__modal_data__ = (args, kwargs)
+        if not hasattr(func, "__modal_data__"):
+            func.__modal_data__ = []
+        func.__modal_data__.append((args, kwargs))
+
         return func
 
     return decorator


Test patch: