[Core] Make Requires.verify() wait until rules are loaded (#2857)

* Make Requires.verify() wait until rules are loaded

Also ensures `Requires` objects are reset when unloaded, particularly in case a `Command` object manages to stay in memory between cog unload and load, and its permissions rules change between those events.

Also, this PR re-ordered some of the event loop policy stuff, because it was required that the event loop policy be set before creating any `Requires` objects. This may or may not have an effect on other `get_event_loop()` calls elsewhere (either in our code, a dependency's, or asyncio's). Either way, these effects would be a *correction*, and any bugs that arise from it are likely to have been occurring silently beforehand.

Signed-off-by: Toby Harradine <tobyharradine@gmail.com>

* Remove calls to `remove_listener()` in permissions

Signed-off-by: Toby Harradine <tobyharradine@gmail.com>

* Fix adding rules for permissions cog/commands itself

Also addresses feedback

Signed-off-by: Toby Harradine <tobyharradine@gmail.com>

* Clean up indentation when setting uvloop policy

Signed-off-by: Toby Harradine <tobyharradine@gmail.com>

* Use `set(walk_commands())` to traverse `Group` subcommands

Signed-off-by: Toby Harradine <tobyharradine@gmail.com>
This commit is contained in:
Toby Harradine
2019-07-14 10:47:40 +10:00
committed by Michael H
parent 21a6384ebf
commit f83f378528
5 changed files with 88 additions and 45 deletions

View File

@@ -322,6 +322,8 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
super().remove_cog(cogname)
cog.requires.reset()
for meth in self.rpc_handlers.pop(cogname.upper(), ()):
self.unregister_rpc_handler(meth)
@@ -424,21 +426,10 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
self.add_permissions_hook(hook)
added_hooks.append(hook)
for command in cog.__cog_commands__:
if not isinstance(command, commands.Command):
raise RuntimeError(
f"The {cog.__class__.__name__} cog in the {cog.__module__} package,"
" is not using Red's command module, and cannot be added. "
"If this is your cog, please use `from redbot.core import commands`"
"in place of `from discord.ext import commands`. For more details on "
"this requirement, see this page: "
"http://red-discordbot.readthedocs.io/en/v3-develop/framework_commands.html"
)
super().add_cog(cog)
self.dispatch("cog_add", cog)
for command in cog.__cog_commands__:
self.dispatch("command_add", command)
if "permissions" not in self.extensions:
cog.requires.ready_event.set()
except Exception:
for hook in added_hooks:
try:
@@ -452,6 +443,29 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
del cog
raise
def add_command(self, command: commands.Command) -> None:
if not isinstance(command, commands.Command):
raise RuntimeError("Commands must be instances of `redbot.core.commands.Command`")
super().add_command(command)
permissions_not_loaded = "permissions" not in self.extensions
self.dispatch("command_add", command)
if permissions_not_loaded:
command.requires.ready_event.set()
if isinstance(command, commands.Group):
for subcommand in set(command.walk_commands()):
self.dispatch("command_add", subcommand)
if permissions_not_loaded:
command.requires.ready_event.set()
def remove_command(self, name: str) -> None:
command = super().remove_command(name)
command.requires.reset()
if isinstance(command, commands.Group):
for subcommand in set(command.walk_commands()):
subcommand.requires.reset()
def clear_permission_rules(self, guild_id: Optional[int]) -> None:
"""Clear all permission overrides in a scope.