From f1956f881c21d996d146691f434c5a3578004cbc Mon Sep 17 00:00:00 2001 From: Humorous Baby <44451911+HumorBaby@users.noreply.github.com> Date: Fri, 26 Oct 2018 23:03:06 -0400 Subject: [PATCH] reload: fix issue with reloading modules within subpackage sopel-irl#1314 used recursion to reload nested modules. However, in Python 2 (maybe python 3 as well), this approach leads to odd behavior with callables being unloaded/reloaded twice. The loop detects my_module.my_callable and my_callable as two separate modules to reload. The first time it detects it, the rule is added to bot._callables as a string. I combined patched dgw branch 1056-no-dupes onto 1056-fix-with-recursion, to provide a more optimal solution to issue sopel-irc#1056. --- sopel/loader.py | 7 +++++-- sopel/modules/reload.py | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sopel/loader.py b/sopel/loader.py index dc0e48e56f..fd92d73223 100644 --- a/sopel/loader.py +++ b/sopel/loader.py @@ -167,10 +167,13 @@ def clean_callable(func, config): func.rule = getattr(func, 'rule', []) for command in getattr(func, 'commands', []): regexp = get_command_regexp(prefix, command) - func.rule.append(regexp) + if regexp not in func.rule: + # TODO: Maybe func.rule should be a set() instead? + func.rule.append(regexp) for command in getattr(func, 'nickname_commands', []): regexp = get_nickname_command_regexp(nick, command, alias_nicks) - func.rule.append(regexp) + if regexp not in func.rule: + func.rule.append(regexp) if hasattr(func, 'example'): example = func.example[0]["example"] example = example.replace('$nickname', nick) diff --git a/sopel/modules/reload.py b/sopel/modules/reload.py index 99fe786a95..62f4eae1f8 100644 --- a/sopel/modules/reload.py +++ b/sopel/modules/reload.py @@ -48,7 +48,7 @@ def f_reload(bot, trigger): return bot.reply('done') - if (name not in sys.modules and name not in sopel.loader.enumerate_modules(bot.config)): + if name not in sys.modules or name not in sopel.loader.enumerate_modules(bot.config): return bot.reply('"%s" not loaded, try the `load` command' % name) reload_module_tree(bot, name) @@ -66,7 +66,7 @@ def reload_module_tree(bot, name, seen=None, silent=False): old_callables = {} for obj_name, obj in iteritems(vars(old_module)): - if callable(obj): + if callable(obj) and '.' not in name: bot.unregister(obj) elif (type(obj) is ModuleType and obj.__name__.startswith(name + '.') and