pyinstaller build fixes
This commit is contained in:
@@ -50,6 +50,9 @@ pushd $WINEPREFIX/drive_c/electrum
|
||||
# see https://github.com/pypa/pip/issues/2195 -- pip makes a copy of the entire directory
|
||||
info "Pip installing Electrum. This might take a long time if the project folder is large."
|
||||
$WINE_PYTHON -m pip install --no-build-isolation --no-dependencies --no-warn-script-location .
|
||||
# pyinstaller needs to be able to "import electrum", for which we need libsecp256k1:
|
||||
# (or could try "pip install -e" instead)
|
||||
cp electrum/libsecp256k1-*.dll "$WINEPREFIX/drive_c/python3/Lib/site-packages/electrum/"
|
||||
popd
|
||||
|
||||
|
||||
|
||||
@@ -4,47 +4,40 @@ from PyInstaller.utils.hooks import collect_data_files, collect_submodules, coll
|
||||
|
||||
import sys, os
|
||||
|
||||
PYPKG="electrum"
|
||||
MAIN_SCRIPT="run_electrum"
|
||||
PROJECT_ROOT = "C:/electrum"
|
||||
ICONS_FILE=f"{PROJECT_ROOT}/{PYPKG}/gui/icons/electrum.ico"
|
||||
|
||||
cmdline_name = os.environ.get("ELECTRUM_CMDLINE_NAME")
|
||||
if not cmdline_name:
|
||||
raise Exception('no name')
|
||||
|
||||
home = 'C:\\electrum\\'
|
||||
|
||||
# see https://github.com/pyinstaller/pyinstaller/issues/2005
|
||||
hiddenimports = []
|
||||
hiddenimports += collect_submodules('pkg_resources') # workaround for https://github.com/pypa/setuptools/issues/1963
|
||||
hiddenimports += collect_submodules('trezorlib')
|
||||
hiddenimports += collect_submodules('safetlib')
|
||||
hiddenimports += collect_submodules('btchip') # device plugin: ledger
|
||||
hiddenimports += collect_submodules('ledger_bitcoin') # device plugin: ledger
|
||||
hiddenimports += collect_submodules('keepkeylib')
|
||||
hiddenimports += collect_submodules('websocket')
|
||||
hiddenimports += collect_submodules('ckcc')
|
||||
hiddenimports += collect_submodules('bitbox02')
|
||||
hiddenimports += ['electrum.plugins.jade.jade']
|
||||
hiddenimports += ['electrum.plugins.jade.jadepy.jade']
|
||||
hiddenimports += ['PyQt5.QtPrintSupport'] # needed by Revealer
|
||||
hiddenimports += collect_submodules(f"{PYPKG}.plugins")
|
||||
|
||||
|
||||
binaries = []
|
||||
|
||||
# Workaround for "Retro Look":
|
||||
binaries += [b for b in collect_dynamic_libs('PyQt5') if 'qwindowsvista' in b[0]]
|
||||
# add libsecp256k1, libusb, etc:
|
||||
binaries += [(f"{PROJECT_ROOT}/{PYPKG}/*.dll", '.')]
|
||||
|
||||
binaries += [('C:/tmp/libsecp256k1-2.dll', '.')]
|
||||
binaries += [('C:/tmp/libusb-1.0.dll', '.')]
|
||||
binaries += [('C:/tmp/libzbar-0.dll', '.')]
|
||||
|
||||
datas = [
|
||||
(home+'electrum/*.json', 'electrum'),
|
||||
(home+'electrum/lnwire/*.csv', 'electrum/lnwire'),
|
||||
(home+'electrum/wordlist/english.txt', 'electrum/wordlist'),
|
||||
(home+'electrum/wordlist/slip39.txt', 'electrum/wordlist'),
|
||||
(home+'electrum/locale', 'electrum/locale'),
|
||||
(home+'electrum/plugins', 'electrum/plugins'),
|
||||
(home+'electrum/gui/icons', 'electrum/gui/icons'),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/*.json", PYPKG),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/lnwire/*.csv", f"{PYPKG}/lnwire"),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/wordlist/english.txt", f"{PYPKG}/wordlist"),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/wordlist/slip39.txt", f"{PYPKG}/wordlist"),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/locale", f"{PYPKG}/locale"),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/plugins", f"{PYPKG}/plugins"),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/gui/icons", f"{PYPKG}/gui/icons"),
|
||||
]
|
||||
datas += collect_data_files('trezorlib')
|
||||
datas += collect_data_files(f"{PYPKG}.plugins")
|
||||
datas += collect_data_files('trezorlib') # TODO is this needed? and same question for other hww libs
|
||||
datas += collect_data_files('safetlib')
|
||||
datas += collect_data_files('btchip')
|
||||
datas += collect_data_files('keepkeylib')
|
||||
@@ -52,29 +45,19 @@ datas += collect_data_files('ckcc')
|
||||
datas += collect_data_files('bitbox02')
|
||||
|
||||
# We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports
|
||||
a = Analysis([home+'run_electrum',
|
||||
home+'electrum/gui/qt/main_window.py',
|
||||
home+'electrum/gui/qt/qrreader/qtmultimedia/camera_dialog.py',
|
||||
home+'electrum/gui/text.py',
|
||||
home+'electrum/util.py',
|
||||
home+'electrum/wallet.py',
|
||||
home+'electrum/simple_config.py',
|
||||
home+'electrum/bitcoin.py',
|
||||
home+'electrum/dnssec.py',
|
||||
home+'electrum/commands.py',
|
||||
home+'electrum/plugins/cosigner_pool/qt.py',
|
||||
home+'electrum/plugins/trezor/qt.py',
|
||||
home+'electrum/plugins/safe_t/client.py',
|
||||
home+'electrum/plugins/safe_t/qt.py',
|
||||
home+'electrum/plugins/keepkey/qt.py',
|
||||
home+'electrum/plugins/ledger/qt.py',
|
||||
home+'electrum/plugins/coldcard/qt.py',
|
||||
home+'electrum/plugins/jade/qt.py',
|
||||
#home+'packages/requests/utils.py'
|
||||
a = Analysis([f"{PROJECT_ROOT}/{MAIN_SCRIPT}",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/gui/qt/main_window.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/gui/qt/qrreader/qtmultimedia/camera_dialog.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/gui/text.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/util.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/wallet.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/simple_config.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/bitcoin.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/dnssec.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/commands.py",
|
||||
],
|
||||
binaries=binaries,
|
||||
datas=datas,
|
||||
#pathex=[home+'lib', home+'gui', home+'plugins'],
|
||||
hiddenimports=hiddenimports,
|
||||
hookspath=[])
|
||||
|
||||
@@ -125,11 +108,11 @@ exe_standalone = EXE(
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
name=os.path.join('build\\pyi.win32\\electrum', cmdline_name + ".exe"),
|
||||
name=os.path.join("build", "pyi.win32", PYPKG, f"{cmdline_name}.exe"),
|
||||
debug=False,
|
||||
strip=None,
|
||||
upx=False,
|
||||
icon=home+'electrum/gui/icons/electrum.ico',
|
||||
icon=ICONS_FILE,
|
||||
console=False)
|
||||
# console=True makes an annoying black box pop up, but it does make Electrum output command line commands, with this turned off no output will be given but commands can still be used
|
||||
|
||||
@@ -138,11 +121,11 @@ exe_portable = EXE(
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas + [('is_portable', 'README.md', 'DATA')],
|
||||
name=os.path.join('build\\pyi.win32\\electrum', cmdline_name + "-portable.exe"),
|
||||
name=os.path.join("build", "pyi.win32", PYPKG, f"{cmdline_name}-portable.exe"),
|
||||
debug=False,
|
||||
strip=None,
|
||||
upx=False,
|
||||
icon=home+'electrum/gui/icons/electrum.ico',
|
||||
icon=ICONS_FILE,
|
||||
console=False)
|
||||
|
||||
#####
|
||||
@@ -152,22 +135,22 @@ exe_inside_setup_noconsole = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
exclude_binaries=True,
|
||||
name=os.path.join('build\\pyi.win32\\electrum', cmdline_name),
|
||||
name=os.path.join("build", "pyi.win32", PYPKG, f"{cmdline_name}.exe"),
|
||||
debug=False,
|
||||
strip=None,
|
||||
upx=False,
|
||||
icon=home+'electrum/gui/icons/electrum.ico',
|
||||
icon=ICONS_FILE,
|
||||
console=False)
|
||||
|
||||
exe_inside_setup_console = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
exclude_binaries=True,
|
||||
name=os.path.join('build\\pyi.win32\\electrum', cmdline_name+"-debug"),
|
||||
name=os.path.join("build", "pyi.win32", PYPKG, f"{cmdline_name}-debug.exe"),
|
||||
debug=False,
|
||||
strip=None,
|
||||
upx=False,
|
||||
icon=home+'electrum/gui/icons/electrum.ico',
|
||||
icon=ICONS_FILE,
|
||||
console=True)
|
||||
|
||||
coll = COLLECT(
|
||||
@@ -179,6 +162,6 @@ coll = COLLECT(
|
||||
strip=None,
|
||||
upx=True,
|
||||
debug=False,
|
||||
icon=home+'electrum/gui/icons/electrum.ico',
|
||||
icon=ICONS_FILE,
|
||||
console=False,
|
||||
name=os.path.join('dist', 'electrum'))
|
||||
name=os.path.join('dist', PYPKG))
|
||||
|
||||
@@ -53,9 +53,9 @@ $WINE_PYTHON -m pip install --no-build-isolation --no-dependencies --no-binary :
|
||||
|
||||
|
||||
# copy already built DLLs
|
||||
cp "$DLL_TARGET_DIR"/libsecp256k1-*.dll $WINEPREFIX/drive_c/tmp/ || fail "Could not copy libsecp to its destination"
|
||||
cp "$DLL_TARGET_DIR/libzbar-0.dll" $WINEPREFIX/drive_c/tmp/ || fail "Could not copy libzbar to its destination"
|
||||
cp "$DLL_TARGET_DIR/libusb-1.0.dll" $WINEPREFIX/drive_c/tmp/ || fail "Could not copy libusb to its destination"
|
||||
cp "$DLL_TARGET_DIR"/libsecp256k1-*.dll $WINEPREFIX/drive_c/electrum/electrum/ || fail "Could not copy libsecp to its destination"
|
||||
cp "$DLL_TARGET_DIR/libzbar-0.dll" $WINEPREFIX/drive_c/electrum/electrum/ || fail "Could not copy libzbar to its destination"
|
||||
cp "$DLL_TARGET_DIR/libusb-1.0.dll" $WINEPREFIX/drive_c/electrum/electrum/ || fail "Could not copy libusb to its destination"
|
||||
|
||||
|
||||
info "Building PyInstaller."
|
||||
|
||||
@@ -223,6 +223,9 @@ python3 -m pip install --no-build-isolation --no-dependencies --no-binary :all:
|
||||
info "Building $PACKAGE..."
|
||||
python3 -m pip install --no-build-isolation --no-dependencies \
|
||||
--no-warn-script-location . > /dev/null || fail "Could not build $PACKAGE"
|
||||
# pyinstaller needs to be able to "import electrum", for which we need libsecp256k1:
|
||||
# (or could try "pip install -e" instead)
|
||||
cp "$PROJECT_ROOT/electrum"/libsecp256k1.*.dylib "$VENV_DIR/lib/python$PY_VER_MAJOR/site-packages/electrum/"
|
||||
|
||||
# strip debug symbols of some compiled libs
|
||||
# - hidapi (hid.cpython-39-darwin.so) in particular is not reproducible without this
|
||||
|
||||
@@ -4,83 +4,67 @@ from PyInstaller.utils.hooks import collect_data_files, collect_submodules, coll
|
||||
|
||||
import sys, os
|
||||
|
||||
PACKAGE='Electrum'
|
||||
PACKAGE_NAME='Electrum.app'
|
||||
PYPKG='electrum'
|
||||
MAIN_SCRIPT='run_electrum'
|
||||
ICONS_FILE=PYPKG + '/gui/icons/electrum.icns'
|
||||
PROJECT_ROOT = os.path.abspath(".")
|
||||
ICONS_FILE=f"{PROJECT_ROOT}/{PYPKG}/gui/icons/electrum.icns"
|
||||
|
||||
|
||||
VERSION = os.environ.get("ELECTRUM_VERSION")
|
||||
if not VERSION:
|
||||
raise Exception('no version')
|
||||
|
||||
electrum = os.path.abspath(".") + "/"
|
||||
block_cipher = None
|
||||
|
||||
# see https://github.com/pyinstaller/pyinstaller/issues/2005
|
||||
hiddenimports = []
|
||||
hiddenimports += collect_submodules('pkg_resources') # workaround for https://github.com/pypa/setuptools/issues/1963
|
||||
hiddenimports += collect_submodules('trezorlib')
|
||||
hiddenimports += collect_submodules('safetlib')
|
||||
hiddenimports += collect_submodules('btchip') # device plugin: ledger
|
||||
hiddenimports += collect_submodules('ledger_bitcoin') # device plugin: ledger
|
||||
hiddenimports += collect_submodules('keepkeylib')
|
||||
hiddenimports += collect_submodules('websocket')
|
||||
hiddenimports += collect_submodules('ckcc')
|
||||
hiddenimports += collect_submodules('bitbox02')
|
||||
hiddenimports += ['electrum.plugins.jade.jade']
|
||||
hiddenimports += ['electrum.plugins.jade.jadepy.jade']
|
||||
hiddenimports += ['PyQt5.QtPrintSupport'] # needed by Revealer
|
||||
hiddenimports += collect_submodules(f"{PYPKG}.plugins")
|
||||
|
||||
|
||||
binaries = []
|
||||
# Workaround for "Retro Look":
|
||||
binaries += [b for b in collect_dynamic_libs('PyQt5') if 'macstyle' in b[0]]
|
||||
# add libsecp256k1, libusb, etc:
|
||||
binaries += [(f"{PROJECT_ROOT}/{PYPKG}/*.dylib", ".")]
|
||||
|
||||
|
||||
datas = [
|
||||
(electrum + PYPKG + '/*.json', PYPKG),
|
||||
(electrum + PYPKG + '/lnwire/*.csv', PYPKG + '/lnwire'),
|
||||
(electrum + PYPKG + '/wordlist/english.txt', PYPKG + '/wordlist'),
|
||||
(electrum + PYPKG + '/wordlist/slip39.txt', PYPKG + '/wordlist'),
|
||||
(electrum + PYPKG + '/locale', PYPKG + '/locale'),
|
||||
(electrum + PYPKG + '/plugins', PYPKG + '/plugins'),
|
||||
(electrum + PYPKG + '/gui/icons', PYPKG + '/gui/icons'),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/*.json", PYPKG),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/lnwire/*.csv", f"{PYPKG}/lnwire"),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/wordlist/english.txt", f"{PYPKG}/wordlist"),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/wordlist/slip39.txt", f"{PYPKG}/wordlist"),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/locale", f"{PYPKG}/locale"),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/plugins", f"{PYPKG}/plugins"),
|
||||
(f"{PROJECT_ROOT}/{PYPKG}/gui/icons", f"{PYPKG}/gui/icons"),
|
||||
]
|
||||
datas += collect_data_files('trezorlib')
|
||||
datas += collect_data_files(f"{PYPKG}.plugins")
|
||||
datas += collect_data_files('trezorlib') # TODO is this needed? and same question for other hww libs
|
||||
datas += collect_data_files('safetlib')
|
||||
datas += collect_data_files('btchip')
|
||||
datas += collect_data_files('keepkeylib')
|
||||
datas += collect_data_files('ckcc')
|
||||
datas += collect_data_files('bitbox02')
|
||||
|
||||
# Add libusb so Trezor and Safe-T mini will work
|
||||
binaries = [(electrum + "electrum/libusb-1.0.dylib", ".")]
|
||||
binaries += [(electrum + "electrum/libsecp256k1.2.dylib", ".")]
|
||||
binaries += [(electrum + "electrum/libzbar.0.dylib", ".")]
|
||||
|
||||
# Workaround for "Retro Look":
|
||||
binaries += [b for b in collect_dynamic_libs('PyQt5') if 'macstyle' in b[0]]
|
||||
|
||||
# We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports
|
||||
a = Analysis([electrum+ MAIN_SCRIPT,
|
||||
electrum+'electrum/gui/qt/main_window.py',
|
||||
electrum+'electrum/gui/qt/qrreader/qtmultimedia/camera_dialog.py',
|
||||
electrum+'electrum/gui/text.py',
|
||||
electrum+'electrum/util.py',
|
||||
electrum+'electrum/wallet.py',
|
||||
electrum+'electrum/simple_config.py',
|
||||
electrum+'electrum/bitcoin.py',
|
||||
electrum+'electrum/dnssec.py',
|
||||
electrum+'electrum/commands.py',
|
||||
electrum+'electrum/plugins/cosigner_pool/qt.py',
|
||||
electrum+'electrum/plugins/trezor/qt.py',
|
||||
electrum+'electrum/plugins/safe_t/client.py',
|
||||
electrum+'electrum/plugins/safe_t/qt.py',
|
||||
electrum+'electrum/plugins/keepkey/qt.py',
|
||||
electrum+'electrum/plugins/ledger/qt.py',
|
||||
electrum+'electrum/plugins/coldcard/qt.py',
|
||||
electrum+'electrum/plugins/jade/qt.py',
|
||||
a = Analysis([f"{PROJECT_ROOT}/{MAIN_SCRIPT}",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/gui/qt/main_window.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/gui/qt/qrreader/qtmultimedia/camera_dialog.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/gui/text.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/util.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/wallet.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/simple_config.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/bitcoin.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/dnssec.py",
|
||||
f"{PROJECT_ROOT}/{PYPKG}/commands.py",
|
||||
],
|
||||
binaries=binaries,
|
||||
datas=datas,
|
||||
hiddenimports=hiddenimports,
|
||||
hookspath=[])
|
||||
|
||||
|
||||
# http://stackoverflow.com/questions/19055089/pyinstaller-onefile-warning-pyconfig-h-when-importing-scipy-or-scipy-signal
|
||||
for d in a.datas:
|
||||
if 'pyconfig' in d[0]:
|
||||
@@ -106,7 +90,7 @@ exe = EXE(
|
||||
debug=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
icon=electrum+ICONS_FILE,
|
||||
icon=ICONS_FILE,
|
||||
console=False,
|
||||
target_arch='x86_64', # TODO investigate building 'universal2'
|
||||
)
|
||||
@@ -116,9 +100,9 @@ app = BUNDLE(
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
version = VERSION,
|
||||
name=PACKAGE + '.app',
|
||||
icon=electrum+ICONS_FILE,
|
||||
version=VERSION,
|
||||
name=PACKAGE_NAME,
|
||||
icon=ICONS_FILE,
|
||||
bundle_identifier=None,
|
||||
info_plist={
|
||||
'NSHighResolutionCapable': 'True',
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Copyright (C) 2023 The Electrum developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENCE or http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
# FIXME: remove when both desktop and mobile are Qt6
|
||||
def get_qt_major_version() -> int:
|
||||
_GUI_QT_VERSION = getattr(sys, '_GUI_QT_VERSION', None)
|
||||
if _GUI_QT_VERSION is None:
|
||||
# used by pyinstaller when building (analysis phase)
|
||||
_GUI_QT_VERSION = 5
|
||||
if _GUI_QT_VERSION in (5, 6):
|
||||
return _GUI_QT_VERSION
|
||||
raise Exception(f"unexpected {_GUI_QT_VERSION=}")
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import sys
|
||||
|
||||
if getattr(sys, '_GUI_QT_VERSION') == 5: # FIXME: remove when both desktop and mobile are Qt6
|
||||
from . import get_qt_major_version
|
||||
|
||||
if (qt_ver := get_qt_major_version()) == 5:
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject
|
||||
else:
|
||||
elif qt_ver == 6:
|
||||
from PyQt6.QtCore import pyqtSignal, pyqtProperty, QObject
|
||||
else:
|
||||
raise Exception(f"unexpected {qt_ver=}")
|
||||
|
||||
from electrum.logging import get_logger
|
||||
|
||||
|
||||
@@ -6,13 +6,19 @@ from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
import PyQt6
|
||||
except Exception:
|
||||
sys.exit("Error: Could not import PyQt6. On Linux systems, you may try 'sudo apt-get install python3-pyqt6'")
|
||||
except Exception as e:
|
||||
from electrum import GuiImportError
|
||||
raise GuiImportError(
|
||||
"Error: Could not import PyQt6. On Linux systems, "
|
||||
"you may try 'sudo apt-get install python3-pyqt6'") from e
|
||||
|
||||
try:
|
||||
import PyQt6.QtQml
|
||||
except Exception:
|
||||
sys.exit("Error: Could not import PyQt6.QtQml. On Linux systems, you may try 'sudo apt-get install python3-pyqt6.qtquick'")
|
||||
except Exception as e:
|
||||
from electrum import GuiImportError
|
||||
raise GuiImportError(
|
||||
"Error: Could not import PyQt6.QtQml. On Linux systems, "
|
||||
"you may try 'sudo apt-get install python3-pyqt6.qtquick'") from e
|
||||
|
||||
from PyQt6.QtCore import (Qt, QCoreApplication, QLocale, QTranslator, QTimer, QT_VERSION_STR, PYQT_VERSION_STR)
|
||||
from PyQt6.QtGui import QGuiApplication
|
||||
|
||||
@@ -80,7 +80,13 @@ class Plugins(DaemonThread):
|
||||
"""
|
||||
if cls._all_found_plugins is None:
|
||||
cls._all_found_plugins = dict()
|
||||
for loader, name, ispkg in pkgutil.iter_modules([cls.pkgpath]):
|
||||
iter_modules = list(pkgutil.iter_modules([cls.pkgpath]))
|
||||
for loader, name, ispkg in iter_modules:
|
||||
# FIXME pyinstaller binaries are packaging each built-in plugin twice:
|
||||
# once as data and once as code. To honor the "no duplicates" rule below,
|
||||
# we exclude the ones packaged as *code*, here:
|
||||
if loader.__class__.__qualname__ == "FrozenImporter":
|
||||
continue
|
||||
full_name = f'electrum.plugins.{name}'
|
||||
spec = importlib.util.find_spec(full_name)
|
||||
if spec is None: # pkgutil found it but importlib can't ?!
|
||||
@@ -94,7 +100,9 @@ class Plugins(DaemonThread):
|
||||
except Exception as e:
|
||||
raise Exception(f"Error pre-loading {full_name}: {repr(e)}") from e
|
||||
d = module.__dict__
|
||||
assert name not in cls._all_found_plugins
|
||||
if name in cls._all_found_plugins:
|
||||
_logger.info(f"Found the following plugin modules: {iter_modules=}")
|
||||
raise Exception(f"duplicate plugins? for {name=}")
|
||||
cls._all_found_plugins[name] = d
|
||||
return cls._all_found_plugins
|
||||
|
||||
|
||||
@@ -4,10 +4,14 @@ import base64
|
||||
import sys
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if getattr(sys, '_GUI_QT_VERSION') == 5: # FIXME: remove when both desktop and mobile are Qt6
|
||||
from electrum.gui.common_qt import get_qt_major_version
|
||||
|
||||
if (qt_ver := get_qt_major_version()) == 5:
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot
|
||||
else:
|
||||
elif qt_ver == 6:
|
||||
from PyQt6.QtCore import pyqtSignal, pyqtProperty, pyqtSlot
|
||||
else:
|
||||
raise Exception(f"unexpected {qt_ver=}")
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.bip32 import BIP32Node
|
||||
|
||||
Reference in New Issue
Block a user