summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortoofar <toofar@spalge.com>2023-08-05 16:14:42 +1200
committertoofar <toofar@spalge.com>2023-08-12 13:36:50 +1200
commit64af5f0e264f5a79dc474838603f584b346f6ac4 (patch)
tree86e81107b52b669c6725d3915d16adef1187d524
parent32470686cef83fc00680939415913c7fdccf0e3c (diff)
downloadqutebrowser-64af5f0e264f5a79dc474838603f584b346f6ac4.tar.gz
qutebrowser-64af5f0e264f5a79dc474838603f584b346f6ac4.zip
walk_module workaround for PyInstaller
Restored from dd2fc8e10bb9d4a1bd0158110173793a18736d6b Now that we are putting our data files in the qutebrowser/ directory again pkgutil/importlib is getting confused by that dir existing and returning us a FileLoader for `qutebrowser.components`, I think that's what's happening anyway. Should try reverting that and this commit and see if extensions get loaded right again. So bring back this workaround of using the toc on the PyInstaller loader to get the list of component modules for now. ref: #7803
-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', {})