Skip to content

Conversation

Paillat-dev
Copy link
Member

@Paillat-dev Paillat-dev commented Mar 2, 2025

Summary

Allow to use a partial as a slash or ext command. See comments for example usage. I might have missed some places where other checks for partial should be used but didn't find any other based on e my testing. I will add them later if needed.

Information

  • This PR fixes an issue.
  • This PR adds something new (e.g. new method or parameters).
  • This PR is a breaking change (e.g. methods or parameters removed/renamed).
  • This PR is not a code change (e.g. documentation, README, typehinting,
    examples, ...).

Checklist

  • I have searched the open pull requests for duplicates.
  • If code changes were made then they have been tested.
    • I have updated the documentation to reflect the changes.
  • If type: ignore comments were used, a comment is also left explaining why.
  • I have updated the changelog to include these changes.

@Paillat-dev Paillat-dev requested a review from a team as a code owner March 2, 2025 21:30
@pullapprove4 pullapprove4 bot requested a review from Middledot March 2, 2025 21:30
@Paillat-dev Paillat-dev changed the title ✨ handle partial functions correctly in command registration feat: ✨ Allow usage of partial as slash or ext command callback Mar 2, 2025
@Paillat-dev
Copy link
Member Author

Here is a usage example:

from typing import final
from dotenv import load_dotenv
import os
import discord
from discord.ext import bridge, commands
from functools import partial
import logging

logging.basicConfig(level=logging.INFO)

load_dotenv()  # pyright: ignore [reportUnusedCallResult]

intents = discord.Intents.default()
intents.message_content = True

bot = bridge.Bot(command_prefix='!', intents=intents)  # pyright: ignore [reportAny]

async def anime_command(self, ctx: bridge.BridgeExtContext |  bridge.BridgeApplicationContext, action: str, member: discord.Member | None= None):
    await ctx.respond(f"You used the {action} command on {member.mention if member else None}!")  # pyright: ignore [reportUnknownMemberType, reportUnusedCallResult]

ACTIONS = [
    "baka",
    "bite",

]

@final
class AnimeSetupCog(commands.Cog):
    def __init__(self, bot):
        self.bot: bridge.Bot = bot
        super().__init__()

    @bridge.bridge_group(name="action")  # pyright: ignore [reportUnknownMemberType]
    async def action_group(self, ctx: bridge.BridgeApplicationContext):
        pass

    for action in ACTIONS:
        func = partial(anime_command, action=action)
        cmd = action_group.command(name=action)(func) # pyright: ignore [reportUnknownMemberType]
        locals()[action] = cmd

bot.add_cog(AnimeSetupCog(bot))

if __name__ == "__main__":
    bot.run(os.getenv("TOKEN_2"))

@Paillat-dev Paillat-dev force-pushed the feat/partial-commands branch from cc96d2a to ff902cd Compare March 2, 2025 21:45
@Paillat-dev Paillat-dev requested a review from a team as a code owner March 2, 2025 21:45
@Paillat-dev Paillat-dev force-pushed the feat/partial-commands branch from ff902cd to 6c62503 Compare March 2, 2025 21:48
@Paillat-dev Paillat-dev changed the title feat: ✨ Allow usage of partial as slash or ext command callback feat: ✨ Allow usage of functools.partial as slash or ext command callback Mar 3, 2025
@Lumabots
Copy link
Contributor

Lumabots commented Mar 3, 2025

i tested it and everything works fine (expect docs but paillat will do it soon)
image

@Dorukyum
Copy link
Member

Dorukyum commented Mar 3, 2025

I'm not a big fan of this. We kept allowing new types for slash command options and it became a mess. While freedom is good, development-wise I think it's better to stick to a very specific command scheme, next major version will hopefully clean this up.

@Lulalaby
Copy link
Member

Lulalaby commented Mar 3, 2025

Tbh I agree with doru

@Paillat-dev
Copy link
Member Author

Fair enough, makes sense. For anyone reading this, if you still for some reason want to do this without this pr, you should use a constrructor instead of partial, below is an example (cc @Lumabots )

async def anime_command(self: "AnimeSetupCog", ctx: bridge.BridgeContext, action: str, member: discord.Member | None= None):
    await ctx.respond(f"You used the {action} command on {member.mention if member else None}!")  # pyright: ignore [reportUnknownMemberType, reportUnusedCallResult]

ACTIONS = [
    "baka",
    "bite",

]

def create_action_func(action_name: str) -> Callable[["AnimeSetupCog", bridge.BridgeContext, discord.Member | None], Coroutine[None, None, None]]:
    async def func(self, ctx: bridge.BridgeContext, member: discord.Member | None = None) -> None:  # pyright: ignore [reportMissingParameterType, reportUnknownParameterType]
        await anime_command(self, ctx, action=action_name, member=member)  # pyright: ignore [reportUnknownArgumentType]
    return func  # pyright: ignore [reportUnknownVariableType]


@final
class AnimeSetupCog(commands.Cog):
    def __init__(self, bot: bridge.Bot) -> None:
        self.bot: bridge.Bot = bot
        super().__init__()

    @bridge.bridge_group(name="action")  # pyright: ignore [reportUnknownMemberType]
    async def action_group(self, ctx: bridge.BridgeApplicationContext):
        pass


    for action in ACTIONS:
        cmd = action_group.command(name=action)(create_action_func(action)) # pyright: ignore [reportUnknownMemberType]
        locals()[action] = cmd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants