Browse Source

commands: add "version_info" cmd

example:
```
$ ./run_electrum -o version_info
{
    "aiohttp.version": "3.8.1",
    "aiorpcx.version": "0.22.1",
    "certifi.version": "2021.10.08",
    "cryptodome.version": null,
    "cryptography.path": "/home/user/.local/lib/python3.8/site-packages/cryptography",
    "cryptography.version": "3.4.6",
    "dnspython.version": "2.2.0",
    "electrum.path": "/home/user/wspace/electrum/electrum",
    "electrum.version": "4.2.1",
    "hidapi.version": "0.11.0.post2",
    "libsecp256k1.path": "/home/user/wspace/electrum/electrum/libsecp256k1.so.0",
    "libusb.path": "libusb-1.0.so",
    "libusb.version": "1.0.23.11397",
    "libzbar.path": "/home/user/wspace/electrum/electrum/libzbar.so.0",
    "pyaes.version": "1.3.0",
    "pyqt.path": "/usr/lib/python3/dist-packages/PyQt5",
    "pyqt.version": "5.14.1",
    "qt.version": "5.12.8"
}
```
patch-4
SomberNight 3 years ago
parent
commit
e47e0afa91
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 43
      electrum/commands.py
  2. 23
      electrum/crypto.py
  3. 6
      electrum/ecc_fast.py
  4. 6
      electrum/gui/__init__.py
  5. 9
      electrum/gui/kivy/__init__.py
  6. 10
      electrum/gui/qt/__init__.py
  7. 24
      electrum/plugin.py
  8. 6
      electrum/qrscanner.py

43
electrum/commands.py

@ -38,6 +38,7 @@ from functools import wraps, partial
from itertools import repeat
from decimal import Decimal
from typing import Optional, TYPE_CHECKING, Dict, List
import os
from .import util, ecc
from .util import (bfh, bh2u, format_satoshis, json_decode, json_normalize,
@ -57,11 +58,13 @@ from .lnutil import SENT, RECEIVED
from .lnutil import LnFeatures
from .lnutil import extract_nodeid
from .lnpeer import channel_id_from_funding_tx
from .plugin import run_hook
from .plugin import run_hook, DeviceMgr
from .version import ELECTRUM_VERSION
from .simple_config import SimpleConfig
from .invoices import LNInvoice
from . import submarine_swaps
from . import GuiImportError
from . import crypto
if TYPE_CHECKING:
@ -546,9 +549,45 @@ class Commands:
@command('')
async def version(self):
"""Return the version of Electrum."""
from .version import ELECTRUM_VERSION
return ELECTRUM_VERSION
@command('')
async def version_info(self):
"""Return information about dependencies, such as their version and path."""
ret = {
"electrum.version": ELECTRUM_VERSION,
"electrum.path": os.path.dirname(os.path.realpath(__file__)),
}
# add currently running GUI
if self.daemon and self.daemon.gui_object:
ret.update(self.daemon.gui_object.version_info())
# always add Qt GUI, so we get info even when running this from CLI
try:
from .gui.qt import ElectrumGui as QtElectrumGui
ret.update(QtElectrumGui.version_info())
except GuiImportError:
pass
# Add shared libs (.so/.dll), and non-pure-python dependencies.
# Such deps can be installed in various ways - often via the Linux distro's pkg manager,
# instead of using pip, hence it is useful to list them for debugging.
from . import ecc_fast
ret.update(ecc_fast.version_info())
from . import qrscanner
ret.update(qrscanner.version_info())
ret.update(DeviceMgr.version_info())
ret.update(crypto.version_info())
# add some special cases
import aiohttp
ret["aiohttp.version"] = aiohttp.__version__
import aiorpcx
ret["aiorpcx.version"] = aiorpcx._version_str
import certifi
ret["certifi.version"] = certifi.__version__
import dns
ret["dnspython.version"] = dns.__version__
return ret
@command('w')
async def getmpk(self, wallet: Abstract_Wallet = None):
"""Get master public key. Return your wallet\'s master public key"""

23
electrum/crypto.py

@ -28,7 +28,7 @@ import os
import sys
import hashlib
import hmac
from typing import Union
from typing import Union, Mapping, Optional
from .util import assert_bytes, InvalidPassword, to_bytes, to_string, WalletFileException, versiontuple
from .i18n import _
@ -84,6 +84,27 @@ if not (HAS_CRYPTODOME or HAS_CRYPTOGRAPHY):
sys.exit(f"Error: at least one of ('pycryptodomex', 'cryptography') needs to be installed.")
def version_info() -> Mapping[str, Optional[str]]:
ret = {}
if HAS_PYAES:
ret["pyaes.version"] = ".".join(map(str, pyaes.VERSION[:3]))
else:
ret["pyaes.version"] = None
if HAS_CRYPTODOME:
ret["cryptodome.version"] = Cryptodome.__version__
if hasattr(Cryptodome, "__path__"):
ret["cryptodome.path"] = ", ".join(Cryptodome.__path__ or [])
else:
ret["cryptodome.version"] = None
if HAS_CRYPTOGRAPHY:
ret["cryptography.version"] = cryptography.__version__
if hasattr(cryptography, "__path__"):
ret["cryptography.path"] = ", ".join(cryptography.__path__ or [])
else:
ret["cryptography.version"] = None
return ret
class InvalidPadding(Exception):
pass

6
electrum/ecc_fast.py

@ -138,3 +138,9 @@ except BaseException as e:
if _libsecp256k1 is None:
# hard fail:
sys.exit(f"Error: Failed to load libsecp256k1.")
def version_info() -> dict:
return {
"libsecp256k1.path": _libsecp256k1._name if _libsecp256k1 else None,
}

6
electrum/gui/__init__.py

@ -4,7 +4,7 @@
# Notifications about network events are sent to the GUI by using network.register_callback()
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Mapping, Optional
if TYPE_CHECKING:
from . import qt
@ -28,3 +28,7 @@ class BaseElectrumGui:
This method must be thread-safe.
"""
pass
@classmethod
def version_info(cls) -> Mapping[str, Optional[str]]:
return {}

9
electrum/gui/kivy/__init__.py

@ -80,3 +80,12 @@ class ElectrumGui(BaseElectrumGui, Logger):
if not app:
return
Clock.schedule_once(lambda dt: app.stop())
@classmethod
def version_info(cls):
ret = {
"kivy.version": kivy.__version__,
}
if hasattr(kivy, "__path__"):
ret["kivy.path"] = ", ".join(kivy.__path__ or [])
return ret

10
electrum/gui/qt/__init__.py

@ -472,3 +472,13 @@ class ElectrumGui(BaseElectrumGui, Logger):
def stop(self):
self.logger.info('closing GUI')
self.app.quit_signal.emit()
@classmethod
def version_info(cls):
ret = {
"qt.version": QtCore.QT_VERSION_STR,
"pyqt.version": QtCore.PYQT_VERSION_STR,
}
if hasattr(PyQt5, "__path__"):
ret["pyqt.path"] = ", ".join(PyQt5.__path__ or [])
return ret

24
electrum/plugin.py

@ -29,7 +29,7 @@ import time
import threading
import sys
from typing import (NamedTuple, Any, Union, TYPE_CHECKING, Optional, Tuple,
Dict, Iterable, List, Sequence, Callable, TypeVar)
Dict, Iterable, List, Sequence, Callable, TypeVar, Mapping)
import concurrent
from concurrent import futures
from functools import wraps, partial
@ -749,3 +749,25 @@ class DeviceMgr(ThreadJob):
client.handler.update_status(False)
return devices
@classmethod
def version_info(cls) -> Mapping[str, Optional[str]]:
ret = {}
# add libusb
try:
import usb1
except Exception as e:
ret["libusb.version"] = None
else:
ret["libusb.version"] = ".".join(map(str, usb1.getVersion()[:4]))
try:
ret["libusb.path"] = usb1.libusb1.libusb._name
except AttributeError:
ret["libusb.path"] = None
# add hidapi
from importlib.metadata import version
try:
ret["hidapi.version"] = version("hidapi")
except ImportError:
ret["hidapi.version"] = None
return ret

6
electrum/qrscanner.py

@ -102,5 +102,11 @@ def find_system_cameras() -> Mapping[str, str]:
return devices
def version_info() -> Mapping[str, Optional[str]]:
return {
"libzbar.path": libzbar._name if libzbar else None,
}
if __name__ == "__main__":
print(scan_barcode())

Loading…
Cancel
Save