feat: allow passing autocompleters that take a cog as first argument to commands.Param
Summary
Currently, commands.Param assumes the provided autocompleter does not take a cog and is typehinted as such, despite somewhat working with alternative autocomplete options such as a simple sequence.
This PR ensures cog-based autocompleters work with commands.Param.
The typehint is changed to work with any valid autocompleter (callback without cog, callback with cog, sequence), and callbacks are internally marked so that slash commands handle them correctly.
Checklist
- [ ] If code changes were made, then they have been tested
- [ ] I have updated the documentation to reflect the changes
- [ ] I have formatted the code properly by running
pdm lint - [ ] I have type-checked the code by running
pdm pyright
- [ ] 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, ...)
This technically solves the original issue (ref); however, and correct me if i'm wrong, at least in that case, it just happens to work out as both cogs have a bot member. If we consider:
class Autocompleters(commands.Cog):
def __init__(self, bot) -> None:
self.bot: commands.Bot = bot
async def category(self, inter: disnake.CommandInteraction, query: str):
print(type(self)) # <<<<<
categories = ["things", "more", "stuff"]
return [c for c in categories if query.lower() in c]
class Misc(commands.Cog):
def __init__(self, bot) -> None:
self.bot: commands.Bot = bot
@commands.slash_command()
async def test(
self,
inter: disnake.GuildCommandInteraction,
cat: str = commands.Param(autocomplete=Autocompleters.category),
) -> None:
await inter.send(cat)
The print in this case shows the self parameter being a Misc instance, since autocompleters (at least those marked as requiring a cog parameter) receive the application command's cog.
It's fairly reasonable for the library to assume the command and autocomplete callback are defined in the same cog imho, there isn't really a way to guarantee the existence of a class instance otherwise.
(EDIT: forgot the cog in the code example mmlol)
Absolutely valid concern. I personally don't think "inter-cog" autocompleters really make sense either, but I could see a more top-level approach work fine:
async def some_autocompleter(
self: commands.Cog, # Or a protocol
inter: disnake.CommandInteraction,
data: str,
):
# if need be can isinstance(self, ...) with a cog class or a protocol
return ...
class Misc(commands.Cog):
@commands.slash_command()
async def test(
self,
inter: disnake.GuildCommandInteraction,
cat: str = commands.Param(autocomplete=some_autocompleter),
) -> None:
await inter.send(cat)
I personally don't think "inter-cog" autocompleters really make sense either, but I could see a more top-level approach work fine
Yea, fair point. In any case, I suppose adding the classify_autocompleter call here won't hurt, so, lgtm. thank you!