-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Description
Summary
The ordering of @app_commands.allowed_installs and @commands.hybrid_command affects whether the allows_installs decorator will apply.
Reproduction Steps
- Load the minimal reproduction cog below
bot.tree.get_command("beforecom").allowed_installsis the expectedAppInstallationTypeobject with the flags appliedbot.tree.get_command("aftercom").allowed_installsisNone
Minimal Reproducible Code
import discord
from discord.ext import commands
from discord import app_commands
class Test(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.hybrid_command()
@app_commands.allowed_installs(guilds=True, users=True)
async def beforecom(self, ctx: commands.Context) -> None:
await ctx.send("Example")
@app_commands.allowed_installs(guilds=True, users=True)
@commands.hybrid_command()
async def aftercom(self, ctx: commands.Context) -> None:
await ctx.send("Example")
async def setup(bot):
await bot.add_cog(Test(bot))Expected Results
Either orientation of the decorator should apply the allowed_installs setting to the hybrid command.
Actual Results
Only cases where the allowed_installs decorator runs first (ie, is lower in the decorator list) actually cause the decorator to work.
Intents
discord.Intents.all()
System Information
- Python v3.8.5-final
- discord.py v2.4.0-final
- aiohttp v3.9.5
- system info: Windows 10 10.0.19041
Checklist
- I have searched the open issues for duplicates.
- I have shown the entire traceback, if possible.
- I have removed my token from display, if visible.
Additional Context
Also tested with app_commands.guild_only, which has the same issue. I do not know the full scope of decorators affected by this issue, but I would imagine it is all non-check app command decorators.
discord.py/discord/app_commands/commands.py
Lines 2806 to 2811 in 9806aeb
| if isinstance(f, (Command, Group, ContextMenu)): | |
| allowed_installs = f.allowed_installs or AppInstallationType() | |
| f.allowed_installs = allowed_installs | |
| else: | |
| allowed_installs = getattr(f, '__discord_app_commands_installation_types__', None) or AppInstallationType() | |
| f.__discord_app_commands_installation_types__ = allowed_installs # type: ignore # Runtime attribute assignment |
In the decorator logic, the else case handles the currently working case, which is when the decorator is used while the object is still a function. Later, when the app command is initialized, it properly includes the allowed_installs setting.
For hybrid commands specifically, the object that is returned from @commands.hybrid_command is a commands.HybridCommand, which does not inherit from app_commands.Command. Only commands.HybridAppCommand inherits from app_commands.Command, which would require accessing the .app_command attribute of the HybridCommand.
A potential fix is to add a 3rd case to these decorators, which checks for HybridCommands and pulls out the .app_command. I am not familiar enough with the flow of information for app command internals to know if that would be a satisfactory solution.