mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-04-22 16:51:59 +00:00
[commands] Update stale parent references in subcommands.
This bug was kind of a long one to figure out, as per #1918 documents the issue had to do with subcommands but the actual adventure in finding this one was a long one. The first problem was that Command.cog was for some reason None, which indicated that a copy was happening somewhere along the way. After some fiddling I discovered that due to the copies of `Cog.__cog_commands__` the groups pointed to out-dated versions that got overriden by the new copies. The first attempt at fixing this was straightforward -- just remove the subcommand from the parent and replace it with the newer reference that we just received. However, this ended up not working due to a strange mystery where the subcommand being invoked was neither the original copy nor the new copy residing in `Cog.__cog_commands__`. Some more investigation later pointed out to me that a copy occurs during the `Group.copy` stage which calls `Command.copy` for all its subcommands. After spotting this out I had realised where the discrepancy comes from. As it turns out, the subcommand copy that was being invoked was actually a stale one created from `Group.copy`. The question remained, how come that one was being called? The problem stemmed from the fact that when the subcommand was copied, the parent reference pointed to the old parent. Since the old parent was the one that was getting the new reference, it went practically untouched. This is because the calling code fetches the child from the parent and the old parent is nowhere in the call chain. To fix this issue we needed to update the parent reference, and in order to do that a temporary lookup table is required pointing to the latest copies that we have made. Thus ends a 3.5 hour bug hunting adventure.
This commit is contained in:
parent
9827d6eeaf
commit
d3bc35a573
@ -136,9 +136,23 @@ class Cog(metaclass=CogMeta):
|
||||
# Either update the command with the cog provided defaults or copy it.
|
||||
self.__cog_commands__ = tuple(c._update_copy(cmd_attrs) for c in cls.__cog_commands__)
|
||||
|
||||
lookup = {
|
||||
cmd.qualified_name: cmd
|
||||
for cmd in self.__cog_commands__
|
||||
}
|
||||
|
||||
# Update the Command instances dynamically as well
|
||||
for command in self.__cog_commands__:
|
||||
setattr(self, command.callback.__name__, command)
|
||||
parent = command.parent
|
||||
if parent is not None:
|
||||
# Get the latest parent reference
|
||||
parent = lookup[parent.qualified_name]
|
||||
|
||||
# Update our parent's reference to ourself
|
||||
removed = parent.remove_command(command.name)
|
||||
parent.add_command(command)
|
||||
|
||||
return self
|
||||
|
||||
def get_commands(self):
|
||||
|
Loading…
x
Reference in New Issue
Block a user