summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qutebrowser/extensions/loader.py28
-rw-r--r--tests/unit/extensions/test_loader.py8
2 files changed, 34 insertions, 2 deletions
diff --git a/qutebrowser/extensions/loader.py b/qutebrowser/extensions/loader.py
index b5b232c5a..7ccdabc88 100644
--- a/qutebrowser/extensions/loader.py
+++ b/qutebrowser/extensions/loader.py
@@ -6,11 +6,12 @@
import pkgutil
import types
+import sys
import pathlib
import importlib
import argparse
import dataclasses
-from typing import Callable, Iterator, List, Optional, Tuple
+from typing import Callable, Iterator, List, Optional, Set, Tuple
from qutebrowser.qt.core import pyqtSlot
@@ -79,6 +80,14 @@ def load_components(*, skip_hooks: bool = False) -> None:
def walk_components() -> Iterator[ExtensionInfo]:
"""Yield ExtensionInfo objects for all modules."""
+ if hasattr(sys, 'frozen'):
+ yield from _walk_pyinstaller()
+ else:
+ yield from _walk_normal()
+
+
+def _walk_normal() -> Iterator[ExtensionInfo]:
+ """Walk extensions when not using PyInstaller."""
for _finder, name, ispkg in pkgutil.walk_packages(
path=components.__path__,
prefix=components.__name__ + '.',
@@ -93,6 +102,23 @@ def walk_components() -> Iterator[ExtensionInfo]:
yield ExtensionInfo(name=name)
+def _walk_pyinstaller() -> Iterator[ExtensionInfo]:
+ """Walk extensions when using PyInstaller.
+
+ See https://github.com/pyinstaller/pyinstaller/issues/1905
+
+ Inspired by:
+ https://github.com/webcomics/dosage/blob/master/dosagelib/loader.py
+ """
+ toc: Set[str] = set()
+ for importer in pkgutil.iter_importers('qutebrowser'):
+ if hasattr(importer, 'toc'):
+ toc |= importer.toc
+ for name in toc:
+ if name.startswith(components.__name__ + '.'):
+ yield ExtensionInfo(name=name)
+
+
def _get_init_context() -> InitContext:
"""Get an InitContext object."""
return InitContext(data_dir=pathlib.Path(standarddir.data()),
diff --git a/tests/unit/extensions/test_loader.py b/tests/unit/extensions/test_loader.py
index a2a99f305..fd15130ba 100644
--- a/tests/unit/extensions/test_loader.py
+++ b/tests/unit/extensions/test_loader.py
@@ -20,10 +20,16 @@ def test_on_walk_error():
def test_walk_normal():
- names = [info.name for info in loader.walk_components()]
+ names = [info.name for info in loader._walk_normal()]
assert 'qutebrowser.components.scrollcommands' in names
+def test_walk_pyinstaller():
+ # We can't test whether we get something back without being frozen by
+ # PyInstaller, but at least we can test that we don't crash.
+ list(loader._walk_pyinstaller())
+
+
def test_load_component(monkeypatch):
monkeypatch.setattr(objects, 'commands', {})