Skip to content

Commit

Permalink
Merge pull request #183 from YousefEZ/allowWrappingQalibInteractions
Browse files Browse the repository at this point in the history
✨ Allow for passing QalibInteractions into another QalibInteraction
  • Loading branch information
YousefEZ authored Sep 23, 2024
2 parents 142e4b5 + c01c173 commit 803dcb4
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 54 deletions.
39 changes: 29 additions & 10 deletions qalib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
:copyright: (c) 2022-present YousefEZ
:license: MIT, see LICENSE for more details.
"""

from __future__ import annotations

from functools import wraps
Expand Down Expand Up @@ -40,14 +41,20 @@ def qalib_context(
Returns (QalibContext): decorated function that takes the Context object and using the extended QalibContext object
"""
renderer_instance: Renderer[str] = Renderer(template_engine, filename, *renderer_options)
renderer_instance: Renderer[str] = Renderer(
template_engine, filename, *renderer_options
)

def command(func: Callable[..., Coro[T]]) -> Callable[..., Coro[T]]:
if discord.utils.is_inside_class(func):

@wraps(func)
async def method(self: commands.Cog, ctx: commands.Context, *args: Any, **kwargs: Any) -> T:
return await func(self, QalibContext(ctx, renderer_instance), *args, **kwargs)
async def method(
self: commands.Cog, ctx: commands.Context, *args: Any, **kwargs: Any
) -> T:
return await func(
self, QalibContext(ctx, renderer_instance), *args, **kwargs
)

return method

Expand All @@ -74,25 +81,31 @@ def qalib_interaction(
Returns (Callable): decorated function that takes the Interaction object and using the extended
QalibInteraction object
"""
renderer_instance: Renderer[str] = Renderer(template_engine, filename, *renderer_options)
renderer_instance: Renderer[str] = Renderer(
template_engine, filename, *renderer_options
)

def command(func: Callable[..., Coro[T]]) -> Callable[..., Coro[T]]:
if discord.utils.is_inside_class(func):

@wraps(func)
async def method(
self: commands.Cog,
inter: discord.Interaction,
inter: discord.Interaction | QalibInteraction[Any],
*args: Any,
**kwargs: Any,
) -> T:
return await func(self, QalibInteraction(inter, renderer_instance), *args, **kwargs)
return await func(
self, QalibInteraction(inter, renderer_instance), *args, **kwargs
)

return method

@wraps(func)
async def function(inter: discord.Interaction, *args: Any, **kwargs: Any) -> T:
return await func(QalibInteraction(inter, renderer_instance), *args, **kwargs)
return await func(
QalibInteraction(inter, renderer_instance), *args, **kwargs
)

return function

Expand All @@ -112,12 +125,18 @@ def qalib_item_interaction(
Returns (Callable): decorated function that takes the Interaction object and using the extended
QalibInteraction object
"""
renderer_instance: Renderer[str] = Renderer(template_engine, filename, *renderer_options)
renderer_instance: Renderer[str] = Renderer(
template_engine, filename, *renderer_options
)

def command(func: Callable[..., Coro[T]]) -> Callable[..., Coro[T]]:
@wraps(func)
async def function(item: discord.ui.Item, inter: discord.Interaction, *args: Any, **kwargs: Any) -> T:
return await func(item, QalibInteraction(inter, renderer_instance), *args, **kwargs)
async def function(
item: discord.ui.Item, inter: discord.Interaction, *args: Any, **kwargs: Any
) -> T:
return await func(
item, QalibInteraction(inter, renderer_instance), *args, **kwargs
)

return function

Expand Down
21 changes: 16 additions & 5 deletions qalib/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
class QalibContext(discord.ext.commands.context.Context, Generic[K_contra]):
"""QalibContext object is responsible for handling messages that are to be sent to the client."""

def __init__(self, ctx: discord.ext.commands.context.Context, renderer: Renderer[K_contra]):
def __init__(
self, ctx: discord.ext.commands.context.Context, renderer: Renderer[K_contra]
):
"""Constructor for the QalibContext object
Args:
Expand Down Expand Up @@ -51,11 +53,16 @@ def verify(self, message: discord.message.Message) -> bool:
Returns:
bool: true of false that indicates whether the data is valid.
"""
return message.author == self.message.author and message.channel == self.message.channel
return (
message.author == self.message.author
and message.channel == self.message.channel
)

async def get_message(self) -> Optional[str]:
"""This method waits for a message to be sent by the user"""
confirm: Optional[discord.message.Message] = await self.bot.wait_for("message", timeout=59.0, check=self.verify)
confirm: Optional[discord.message.Message] = await self.bot.wait_for(
"message", timeout=59.0, check=self.verify
)
return confirm.content if confirm is not None else None

async def rendered_send(
Expand Down Expand Up @@ -85,7 +92,9 @@ async def rendered_send(
message = message.front

assert isinstance(message, Message)
return await self.send(**{**message.convert_to_context_message().dict(), **kwargs})
return await self.send(
**{**message.convert_to_context_message().dict(), **kwargs}
)

async def display(
self,
Expand Down Expand Up @@ -114,7 +123,9 @@ async def display(

assert isinstance(message, Message)
if self._displayed:
await self._display(**{**message.convert_to_context_message().as_edit().dict(), **kwargs})
await self._display(
**{**message.convert_to_context_message().as_edit().dict(), **kwargs}
)
return
await self._display(**{**message.convert_to_context_message().dict(), **kwargs})

Expand Down
68 changes: 29 additions & 39 deletions qalib/interaction.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

import warnings
from typing import TYPE_CHECKING, Any, Dict, Generic, Optional, cast
from typing import Any, Dict, Generic, Optional, Union

import discord
from deprecated import deprecated
Expand All @@ -12,48 +14,29 @@
from qalib.translators.events import EventCallbacks
from qalib.translators.menu import Menu

if TYPE_CHECKING:
from discord.types.interactions import Interaction as InteractionPayload


def create_interaction_payload(interaction: discord.Interaction) -> Dict[str, Any]:
# pylint: disable=protected-access
# noinspection PyProtectedMember
return {
"id": interaction.id,
"type": int(interaction.type.value),
"data": interaction.data,
"token": interaction.token,
"version": interaction.version,
"channel_id": interaction.channel_id,
"guild_id": interaction.guild_id,
"application_id": interaction.application_id,
"locale": interaction.locale,
"guild_locale": interaction.guild_locale,
"app_permissions": interaction._app_permissions,
}


class QalibInteraction(discord.Interaction, Generic[K_contra]):
"""The QalibInteraction class is a subclass of discord.Interaction, and is used to add additional functionality to
the interaction. It is meant to be used in the on_interaction event, and is responsible for deserializing the
requested modal and sending it to the user."""

def __init__(self, interaction: discord.Interaction, renderer: Renderer[K_contra]):
"""Constructor method for the QalibInteraction class."""
data = create_interaction_payload(interaction)
if TYPE_CHECKING:
super().__init__(
data=(cast(InteractionPayload, data)),
state=interaction._state,
)
else:
super().__init__(
data=data,
state=interaction._state,
)
self.message = interaction.message
self.user = interaction.user
__slots__ = discord.Interaction.__slots__ + ("_renderer", "_displayed", "_wrapped")

def __init__(
self,
interaction: Union[QalibInteraction[Any], discord.Interaction],
renderer: Renderer[K_contra],
):
for attr in discord.Interaction.__slots__:
try:
setattr(self, attr, getattr(interaction, attr))
except AttributeError:
pass
self._wrapped = (
interaction._wrapped
if isinstance(interaction, QalibInteraction)
else interaction
)
self._renderer = renderer
self._displayed = False

Expand Down Expand Up @@ -121,9 +104,16 @@ async def display(

assert isinstance(message, Message)
if self._displayed:
await self._display(**{**message.convert_to_interaction_message().as_edit().dict(), **kwargs})
await self._display(
**{
**message.convert_to_interaction_message().as_edit().dict(),
**kwargs,
}
)
return
await self._display(**{**message.convert_to_interaction_message().dict(), **kwargs})
await self._display(
**{**message.convert_to_interaction_message().dict(), **kwargs}
)

async def _display(self, **kwargs: Any) -> None:
"""This method is responsible for sending the message to the client, and editing the message if there is one
Expand Down

0 comments on commit 803dcb4

Please sign in to comment.