From ad8397c1c96add70bb744d695f8c8d487361061f Mon Sep 17 00:00:00 2001 From: Florian Strzelecki Date: Fri, 11 Sep 2020 11:43:24 +0200 Subject: [PATCH] loader, plugin: load decorated callables only --- sopel/loader.py | 3 +++ sopel/plugin.py | 11 +++++++++++ test/test_loader.py | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/sopel/loader.py b/sopel/loader.py index 3e075b0af9..562f8d92ad 100644 --- a/sopel/loader.py +++ b/sopel/loader.py @@ -234,8 +234,11 @@ def clean_module(module, config): urls = [] for obj in itervalues(vars(module)): if callable(obj): + is_sopel_callable = getattr(obj, '_sopel_callable', False) is True if getattr(obj, '__name__', None) == 'shutdown': shutdowns.append(obj) + elif not is_sopel_callable: + continue elif is_triggerable(obj): clean_callable(obj, config) callables.append(obj) diff --git a/sopel/plugin.py b/sopel/plugin.py index 701cdbf154..53738e1e5f 100644 --- a/sopel/plugin.py +++ b/sopel/plugin.py @@ -147,6 +147,7 @@ def spam_every_5s(bot): """ def add_attribute(function): + function._sopel_callable = True if not hasattr(function, "interval"): function.interval = [] for arg in intervals: @@ -201,6 +202,7 @@ def rule(*patterns): """ def add_attribute(function): + function._sopel_callable = True if not hasattr(function, "rule"): function.rule = [] for value in patterns: @@ -255,6 +257,7 @@ def find(*patterns): """ def add_attribute(function): + function._sopel_callable = True if not hasattr(function, "find_rules"): function.find_rules = [] for value in patterns: @@ -312,6 +315,7 @@ def search(*patterns): """ def add_attribute(function): + function._sopel_callable = True if not hasattr(function, "search_rules"): function.search_rules = [] for value in patterns: @@ -441,6 +445,7 @@ def command(*command_list): """ def add_attribute(function): + function._sopel_callable = True if not hasattr(function, "commands"): function.commands = [] for command in command_list: @@ -486,6 +491,7 @@ def nickname_command(*command_list): """ def add_attribute(function): + function._sopel_callable = True if not hasattr(function, 'nickname_commands'): function.nickname_commands = [] for cmd in command_list: @@ -540,6 +546,7 @@ def action_command(*command_list): """ def add_attribute(function): + function._sopel_callable = True if not hasattr(function, 'action_commands'): function.action_commands = [] for cmd in command_list: @@ -608,6 +615,7 @@ def event(*event_list): """ def add_attribute(function): + function._sopel_callable = True if not hasattr(function, "event"): function.event = [] for name in event_list: @@ -632,6 +640,7 @@ def intent(*intent_list): """ def add_attribute(function): + function._sopel_callable = True if not hasattr(function, "intents"): function.intents = [] for name in intent_list: @@ -945,6 +954,7 @@ def handle_example_bugs(bot, trigger): """ def actual_decorator(function): + function._sopel_callable = True if not hasattr(function, 'url_regex'): function.url_regex = [] for url_rule in url_rules: @@ -995,6 +1005,7 @@ def my_url_handler(bot, trigger): """ def decorator(function): + function._sopel_callable = True if not hasattr(function, 'url_lazy_loaders'): function.url_lazy_loaders = [] function.url_lazy_loaders.extend(loaders) diff --git a/test/test_loader.py b/test/test_loader.py index ff34c12d24..9b8553c8a4 100644 --- a/test/test_loader.py +++ b/test/test_loader.py @@ -63,6 +63,25 @@ def shutdown(): def ignored(): pass + +@sopel.module.rate(10) +def ignored_rate(): + pass + + +class Ignored: + def __init__(self): + self.rule = [r'.*'] + + def __call__(self, bot, trigger): + pass + +ignored_obj = Ignored() + +def ignored_trickster(): + pass + +ignored_trickster._sopel_callable = True """ @@ -185,6 +204,23 @@ def test_clean_module(testplugin, tmpconfig): assert test_mod.ignored not in jobs assert test_mod.ignored not in shutdowns assert test_mod.ignored not in urls + # @rate doesn't create a callable and is ignored + assert test_mod.ignored_rate not in callables + assert test_mod.ignored_rate not in jobs + assert test_mod.ignored_rate not in shutdowns + assert test_mod.ignored_rate not in urls + # object with a triggerable attribute are ignored by default + assert loader.is_triggerable(test_mod.ignored_obj) + assert test_mod.ignored_obj not in callables + assert test_mod.ignored_obj not in jobs + assert test_mod.ignored_obj not in shutdowns + assert test_mod.ignored_obj not in urls + # trickster function is ignored: it's still not a proper plugin callable + assert not loader.is_triggerable(test_mod.ignored_trickster) + assert test_mod.ignored_trickster not in callables + assert test_mod.ignored_trickster not in jobs + assert test_mod.ignored_trickster not in shutdowns + assert test_mod.ignored_trickster not in urls def test_clean_module_idempotency(testplugin, tmpconfig):