From 989e1613b820bc8cf7d42766b148edeadde35a14 Mon Sep 17 00:00:00 2001 From: PiRK Date: Wed, 11 Jan 2023 11:57:19 +0100 Subject: [PATCH] plugin.py electrum backports This is a backport of > plugins: when loading plugins, use newer importlib mechanism https://github.com/spesmilo/electrum/commit/e04e8d236573d5ad5cd40bcca8c6d613b6ee31a4 > plugins: on some systems plugins with relative imports failed to load https://github.com/spesmilo/electrum/commit/811169da4b9a31388cc1d9e8e2cac738f14eded9 It fixes the windows binary which was broken when upgrading pyinstaller to 4.10. --- electroncash/plugins.py | 47 ++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/electroncash/plugins.py b/electroncash/plugins.py index 3f34b779b5c0..37582238f39c 100644 --- a/electroncash/plugins.py +++ b/electroncash/plugins.py @@ -29,6 +29,7 @@ # It is no longer needed for python 3.8+. import concurrent import concurrent.futures +import importlib.util import json import os import pkgutil @@ -169,14 +170,20 @@ def load_internal_plugins(self): for loader, name, ispkg in pkgutil.iter_modules( [self.internal_plugins_pkgpath] ): - # do not load deprecated plugins - if name in ["plot", "exchange_rate"]: - continue - # do not load plugins that rely on untrusted servers, for now - if name in ["labels", "cosigner_pool"]: - continue - m = loader.find_module(name).load_module(name) - d = m.__dict__ + full_name = f"electroncash_plugins.{name}" + spec = importlib.util.find_spec(full_name) + # pkgutil found it but importlib can't ?! + if spec is None: + raise Exception(f"Error pre-loading {full_name}: no spec") + try: + module = importlib.util.module_from_spec(spec) + # sys.modules needs to be modified for relative imports to work + # see https://stackoverflow.com/a/50395128 + sys.modules[spec.name] = module + spec.loader.exec_module(module) + except Exception as e: + raise Exception(f"Error pre-loading {full_name}: {repr(e)}") from e + d = module.__dict__ if not self.register_plugin(name, d): continue self.internal_plugin_metadata[name] = d @@ -257,14 +264,15 @@ def load_internal_plugin(self, name): if name in self.internal_plugins: return self.internal_plugins[name] - full_name = "electroncash_plugins." + name + "." + self.gui_name - loader = pkgutil.find_loader(full_name) - if not loader: + full_name = f"electroncash_plugins.{name}.{self.gui_name}" + spec = importlib.util.find_spec(full_name) + if spec is None: raise RuntimeError( "%s implementation for %s plugin not found" % (self.gui_name, name) ) - p = loader.load_module(full_name) - plugin = p.Plugin(self, self.config, name) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + plugin = module.Plugin(self, self.config, name) plugin.set_enabled_prefix(INTERNAL_USE_PREFIX) self.add_jobs(plugin.thread_jobs()) self.internal_plugins[name] = plugin @@ -298,16 +306,17 @@ def load_external_plugin(self, name): ) return - sys.modules["electroncash_external_plugins." + name] = module + sys.modules[f"electroncash_external_plugins.{name}"] = module - full_name = "electroncash_external_plugins." + name + "." + self.gui_name - loader = pkgutil.find_loader(full_name) - if not loader: + full_name = f"electroncash_external_plugins.{name}.{self.gui_name}" + spec = importlib.util.find_spec(full_name) + if spec is None: raise RuntimeError( "%s implementation for %s plugin not found" % (self.gui_name, name) ) - p = loader.load_module(full_name) - plugin = p.Plugin(self, self.config, name) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + plugin = module.Plugin(self, self.config, name) plugin.set_enabled_prefix(EXTERNAL_USE_PREFIX) self.add_jobs(plugin.thread_jobs()) self.external_plugins[name] = plugin