From 4e99caafb9f9772155bbf5de18e8bad60b2127e0 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <me@the-compiler.org>
Date: Mon, 10 Dec 2018 16:00:31 +0100
Subject: [PATCH] Skip hooks for vulture/docs

---
 qutebrowser/extensions/loader.py     | 21 ++++++++++++++++-----
 scripts/dev/run_vulture.py           |  2 +-
 scripts/dev/src2asciidoc.py          |  2 +-
 tests/unit/extensions/test_loader.py |  2 +-
 4 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/qutebrowser/extensions/loader.py b/qutebrowser/extensions/loader.py
index be7beeb11..338449c5b 100644
--- a/qutebrowser/extensions/loader.py
+++ b/qutebrowser/extensions/loader.py
@@ -65,6 +65,7 @@ class ModuleInfo:
     _ConfigChangedHooksType = typing.List[typing.Tuple[typing.Optional[str],
                                                        typing.Callable]]
 
+    skip_hooks = attr.ib(False)  # type: bool
     init_hook = attr.ib(None)  # type: typing.Optional[typing.Callable]
     config_changed_hooks = attr.ib(
         attr.Factory(list))  # type: _ConfigChangedHooksType
@@ -86,10 +87,10 @@ def add_module_info(module: types.ModuleType) -> ModuleInfo:
     return module.__qute_module_info  # type: ignore
 
 
-def load_components() -> None:
+def load_components(*, skip_hooks=False) -> None:
     """Load everything from qutebrowser.components."""
     for info in walk_components():
-        _load_component(info)
+        _load_component(info, skip_hooks=skip_hooks)
 
 
 def walk_components() -> typing.Iterator[ExtensionInfo]:
@@ -141,13 +142,21 @@ def _get_init_context() -> InitContext:
                        args=objreg.get('args'))
 
 
-def _load_component(info: ExtensionInfo) -> types.ModuleType:
-    """Load the given extension and run its init hook (if any)."""
+def _load_component(info: ExtensionInfo, *, skip_hooks) -> types.ModuleType:
+    """Load the given extension and run its init hook (if any).
+
+    Args:
+        skip_hooks: Whether to skip all hooks for this module.
+                    This is used to only run @cmdutils.register decorators.
+    """
     log.extensions.debug("Importing {}".format(info.name))
     mod = importlib.import_module(info.name)
 
     mod_info = add_module_info(mod)
-    if mod_info.init_hook is not None:
+    if skip_hooks:
+        mod_info.skip_hooks = True
+
+    if mod_info.init_hook is not None and not skip_hooks:
         log.extensions.debug("Running init hook {!r}"
                              .format(mod_info.init_hook.__name__))
         mod_info.init_hook(_get_init_context())
@@ -161,6 +170,8 @@ def _load_component(info: ExtensionInfo) -> types.ModuleType:
 def _on_config_changed(changed_name: str) -> None:
     """Call config_changed hooks if the config changed."""
     for mod_info in _module_infos:
+        if mod_info.skip_hooks:
+            continue
         for option, hook in mod_info.config_changed_hooks:
             if option is None:
                 hook()
diff --git a/scripts/dev/run_vulture.py b/scripts/dev/run_vulture.py
index 7874f6a79..51662f3c9 100755
--- a/scripts/dev/run_vulture.py
+++ b/scripts/dev/run_vulture.py
@@ -44,7 +44,7 @@ from qutebrowser.config import configtypes
 
 def whitelist_generator():  # noqa
     """Generator which yields lines to add to a vulture whitelist."""
-    loader.load_components()
+    loader.load_components(skip_hooks=True)
 
     # qutebrowser commands
     for cmd in objects.commands.values():
diff --git a/scripts/dev/src2asciidoc.py b/scripts/dev/src2asciidoc.py
index f0536c045..1ba272fba 100755
--- a/scripts/dev/src2asciidoc.py
+++ b/scripts/dev/src2asciidoc.py
@@ -550,7 +550,7 @@ def regenerate_cheatsheet():
 def main():
     """Regenerate all documentation."""
     utils.change_cwd()
-    loader.load_components()
+    loader.load_components(skip_hooks=True)
     print("Generating manpage...")
     regenerate_manpage('doc/qutebrowser.1.asciidoc')
     print("Generating settings help...")
diff --git a/tests/unit/extensions/test_loader.py b/tests/unit/extensions/test_loader.py
index e0c1912fa..710b1ce9c 100644
--- a/tests/unit/extensions/test_loader.py
+++ b/tests/unit/extensions/test_loader.py
@@ -43,7 +43,7 @@ def test_load_component(monkeypatch):
     monkeypatch.setattr(objects, 'commands', {})
 
     info = loader.ExtensionInfo(name='qutebrowser.components.scrollcommands')
-    module = loader._load_component(info)
+    module = loader._load_component(info, skip_hooks=True)
 
     assert hasattr(module, 'scroll_to_perc')
     assert 'scroll-to-perc' in objects.commands