wizard: typing
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import copy
|
||||
import os
|
||||
|
||||
from typing import List, NamedTuple, Any, Dict, Optional, Tuple
|
||||
from typing import List, NamedTuple, Any, Dict, Optional, Tuple, TYPE_CHECKING
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.interface import ServerAddr
|
||||
@@ -16,6 +16,11 @@ from electrum import keystore, mnemonic
|
||||
from electrum import bitcoin
|
||||
from electrum.mnemonic import is_any_2fa_seed_type
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from electrum.daemon import Daemon
|
||||
from electrum.plugin import Plugins
|
||||
from electrum.keystore import Hardware_KeyStore
|
||||
|
||||
|
||||
class WizardViewState(NamedTuple):
|
||||
view: Optional[str]
|
||||
@@ -40,7 +45,7 @@ class AbstractWizard:
|
||||
self._current = WizardViewState(None, {}, {})
|
||||
self._stack = [] # type: List[WizardViewState]
|
||||
|
||||
def navmap_merge(self, additional_navmap):
|
||||
def navmap_merge(self, additional_navmap: dict):
|
||||
# NOTE: only merges one level deep. Deeper dict levels will overwrite
|
||||
for k, v in additional_navmap.items():
|
||||
if k in self.navmap:
|
||||
@@ -55,7 +60,7 @@ class AbstractWizard:
|
||||
# view params are transient, meant for extra configuration of a view (e.g. info
|
||||
# msg in a generic choice dialog)
|
||||
# exception: stay on this view
|
||||
def resolve_next(self, view, wizard_data) -> WizardViewState:
|
||||
def resolve_next(self, view: str, wizard_data: dict) -> WizardViewState:
|
||||
assert view
|
||||
self._logger.debug(f'view={view}')
|
||||
assert view in self.navmap
|
||||
@@ -127,7 +132,7 @@ class AbstractWizard:
|
||||
return self._current
|
||||
|
||||
# check if this view is the final view
|
||||
def is_last_view(self, view, wizard_data):
|
||||
def is_last_view(self, view: str, wizard_data: dict) -> bool:
|
||||
assert view
|
||||
assert view in self.navmap
|
||||
|
||||
@@ -149,7 +154,7 @@ class AbstractWizard:
|
||||
else:
|
||||
raise Exception(f'last handler for view {view} is not callable nor a bool literal')
|
||||
|
||||
def finished(self, wizard_data):
|
||||
def finished(self, wizard_data: dict):
|
||||
self._logger.debug('finished.')
|
||||
|
||||
def reset(self):
|
||||
@@ -182,7 +187,7 @@ class AbstractWizard:
|
||||
return result
|
||||
return sanitize(_stack_item)
|
||||
|
||||
def get_wizard_data(self):
|
||||
def get_wizard_data(self) -> dict:
|
||||
return copy.deepcopy(self._current.wizard_data)
|
||||
|
||||
|
||||
@@ -190,7 +195,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
def __init__(self, daemon, plugins):
|
||||
def __init__(self, daemon: 'Daemon', plugins: 'Plugins'):
|
||||
AbstractWizard.__init__(self)
|
||||
self.navmap = {
|
||||
'wallet_name': {
|
||||
@@ -264,36 +269,36 @@ class NewWalletWizard(AbstractWizard):
|
||||
self._daemon = daemon
|
||||
self.plugins = plugins
|
||||
|
||||
def start(self, initial_data=None):
|
||||
def start(self, initial_data: dict = None) -> WizardViewState:
|
||||
if initial_data is None:
|
||||
initial_data = {}
|
||||
self.reset()
|
||||
self._current = WizardViewState('wallet_name', initial_data, {})
|
||||
return self._current
|
||||
|
||||
def is_single_password(self):
|
||||
def is_single_password(self) -> bool:
|
||||
raise NotImplementedError()
|
||||
|
||||
# returns (sub)dict of current cosigner (or root if first)
|
||||
def current_cosigner(self, wizard_data):
|
||||
def current_cosigner(self, wizard_data: dict) -> dict:
|
||||
wdata = wizard_data
|
||||
if wizard_data['wallet_type'] == 'multisig' and 'multisig_current_cosigner' in wizard_data:
|
||||
cosigner = wizard_data['multisig_current_cosigner']
|
||||
wdata = wizard_data['multisig_cosigner_data'][str(cosigner)]
|
||||
return wdata
|
||||
|
||||
def needs_derivation_path(self, wizard_data):
|
||||
def needs_derivation_path(self, wizard_data: dict) -> bool:
|
||||
wdata = self.current_cosigner(wizard_data)
|
||||
return 'seed_variant' in wdata and wdata['seed_variant'] in ['bip39', 'slip39']
|
||||
|
||||
def wants_ext(self, wizard_data):
|
||||
def wants_ext(self, wizard_data: dict) -> bool:
|
||||
wdata = self.current_cosigner(wizard_data)
|
||||
return 'seed_variant' in wdata and wdata['seed_extend']
|
||||
|
||||
def is_multisig(self, wizard_data):
|
||||
def is_multisig(self, wizard_data: dict) -> bool:
|
||||
return wizard_data['wallet_type'] == 'multisig'
|
||||
|
||||
def on_wallet_type(self, wizard_data):
|
||||
def on_wallet_type(self, wizard_data: dict) -> str:
|
||||
t = wizard_data['wallet_type']
|
||||
return {
|
||||
'standard': 'keystore_type',
|
||||
@@ -302,7 +307,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
'imported': 'imported'
|
||||
}.get(t)
|
||||
|
||||
def on_keystore_type(self, wizard_data):
|
||||
def on_keystore_type(self, wizard_data: dict) -> str:
|
||||
t = wizard_data['keystore_type']
|
||||
return {
|
||||
'createseed': 'create_seed',
|
||||
@@ -311,19 +316,19 @@ class NewWalletWizard(AbstractWizard):
|
||||
'hardware': 'choose_hardware_device'
|
||||
}.get(t)
|
||||
|
||||
def is_hardware(self, wizard_data):
|
||||
def is_hardware(self, wizard_data: dict) -> bool:
|
||||
return wizard_data['keystore_type'] == 'hardware'
|
||||
|
||||
def wallet_password_view(self, wizard_data):
|
||||
def wallet_password_view(self, wizard_data: dict) -> str:
|
||||
return 'wallet_password_hardware' if self.is_hardware(wizard_data) else 'wallet_password'
|
||||
|
||||
def on_hardware_device(self, wizard_data):
|
||||
def on_hardware_device(self, wizard_data: dict) -> str:
|
||||
_type, _info = wizard_data['hardware_device']
|
||||
run_hook('init_wallet_wizard', self)
|
||||
plugin = self.plugins.get_plugin(_type)
|
||||
return plugin.wizard_entry_for_device(_info)
|
||||
|
||||
def on_have_or_confirm_seed(self, wizard_data):
|
||||
def on_have_or_confirm_seed(self, wizard_data: dict) -> str:
|
||||
if self.needs_derivation_path(wizard_data):
|
||||
return 'script_and_derivation'
|
||||
elif self.is_multisig(wizard_data):
|
||||
@@ -331,7 +336,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
else:
|
||||
return 'wallet_password'
|
||||
|
||||
def maybe_master_pubkey(self, wizard_data):
|
||||
def maybe_master_pubkey(self, wizard_data: dict):
|
||||
self._logger.debug('maybe_master_pubkey')
|
||||
if self.needs_derivation_path(wizard_data) and 'derivation_path' not in wizard_data:
|
||||
self._logger.debug('deferred, missing derivation_path')
|
||||
@@ -339,7 +344,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
|
||||
wizard_data['multisig_master_pubkey'] = self.keystore_from_data(wizard_data['wallet_type'], wizard_data).get_master_public_key()
|
||||
|
||||
def on_cosigner_keystore_type(self, wizard_data):
|
||||
def on_cosigner_keystore_type(self, wizard_data: dict) -> str:
|
||||
t = wizard_data['cosigner_keystore_type']
|
||||
return {
|
||||
'key': 'multisig_cosigner_key',
|
||||
@@ -347,7 +352,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
'hardware': 'multisig_cosigner_hardware'
|
||||
}.get(t)
|
||||
|
||||
def on_have_cosigner_seed(self, wizard_data):
|
||||
def on_have_cosigner_seed(self, wizard_data: dict) -> str:
|
||||
current_cosigner = self.current_cosigner(wizard_data)
|
||||
if self.needs_derivation_path(wizard_data) and 'derivation_path' not in current_cosigner:
|
||||
return 'multisig_cosigner_script_and_derivation'
|
||||
@@ -356,7 +361,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
else:
|
||||
return 'multisig_cosigner_keystore'
|
||||
|
||||
def last_cosigner(self, wizard_data):
|
||||
def last_cosigner(self, wizard_data: dict) -> bool:
|
||||
# check if we have the final number of cosigners. Doesn't check if cosigner data itself is complete
|
||||
# (should be validated by wizardcomponents)
|
||||
if not self.is_multisig(wizard_data):
|
||||
@@ -367,7 +372,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
|
||||
return True
|
||||
|
||||
def has_duplicate_masterkeys(self, wizard_data) -> bool:
|
||||
def has_duplicate_masterkeys(self, wizard_data: dict) -> bool:
|
||||
"""Multisig wallets need distinct master keys. If True, need to prevent wallet-creation."""
|
||||
xpubs = [self.keystore_from_data(wizard_data['wallet_type'], wizard_data).get_master_public_key()]
|
||||
for cosigner in wizard_data['multisig_cosigner_data']:
|
||||
@@ -376,7 +381,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
assert xpubs
|
||||
return len(xpubs) != len(set(xpubs))
|
||||
|
||||
def has_heterogeneous_masterkeys(self, wizard_data) -> bool:
|
||||
def has_heterogeneous_masterkeys(self, wizard_data: dict) -> bool:
|
||||
"""Multisig wallets need homogeneous master keys.
|
||||
All master keys need to be bip32, and e.g. Ypub cannot be mixed with Zpub.
|
||||
If True, need to prevent wallet-creation.
|
||||
@@ -399,7 +404,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
return True
|
||||
return False
|
||||
|
||||
def keystore_from_data(self, wallet_type, data):
|
||||
def keystore_from_data(self, wallet_type: str, data: dict):
|
||||
if 'seed' in data:
|
||||
if data['seed_variant'] == 'electrum':
|
||||
return keystore.from_seed(data['seed'], data['seed_extra_words'], True)
|
||||
@@ -426,7 +431,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
else:
|
||||
raise Exception('no seed or master_key in data')
|
||||
|
||||
def is_current_cosigner_hardware(self, wizard_data):
|
||||
def is_current_cosigner_hardware(self, wizard_data: dict) -> bool:
|
||||
cosigner_data = self.current_cosigner(wizard_data)
|
||||
cosigner_is_hardware = cosigner_data == wizard_data and wizard_data['keystore_type'] == 'hardware'
|
||||
if 'cosigner_keystore_type' in wizard_data and wizard_data['cosigner_keystore_type'] == 'hardware':
|
||||
@@ -467,7 +472,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
|
||||
return multisig_keys_valid, user_info
|
||||
|
||||
def validate_seed(self, seed, seed_variant, wallet_type):
|
||||
def validate_seed(self, seed: str, seed_variant: str, wallet_type: str):
|
||||
seed_type = ''
|
||||
seed_valid = False
|
||||
validation_message = ''
|
||||
@@ -506,7 +511,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
|
||||
return seed_valid, seed_type, validation_message
|
||||
|
||||
def create_storage(self, path, data):
|
||||
def create_storage(self, path: str, data: dict):
|
||||
assert data['wallet_type'] in ['standard', '2fa', 'imported', 'multisig']
|
||||
|
||||
if os.path.exists(path):
|
||||
@@ -635,7 +640,7 @@ class NewWalletWizard(AbstractWizard):
|
||||
db.load_plugins()
|
||||
db.write()
|
||||
|
||||
def hw_keystore(self, data):
|
||||
def hw_keystore(self, data: dict) -> 'Hardware_KeyStore':
|
||||
return hardware_keystore({
|
||||
'type': 'hardware',
|
||||
'hw_type': data['hw_type'],
|
||||
@@ -673,7 +678,7 @@ class ServerConnectWizard(AbstractWizard):
|
||||
}
|
||||
self._daemon = daemon
|
||||
|
||||
def do_configure_proxy(self, wizard_data):
|
||||
def do_configure_proxy(self, wizard_data: dict):
|
||||
proxy_settings = wizard_data['proxy']
|
||||
if not self._daemon.network:
|
||||
self._logger.debug('not configuring proxy, electrum config wants offline mode')
|
||||
@@ -685,7 +690,7 @@ class ServerConnectWizard(AbstractWizard):
|
||||
net_params = net_params._replace(proxy=proxy_settings)
|
||||
self._daemon.network.run_from_another_thread(self._daemon.network.set_parameters(net_params))
|
||||
|
||||
def do_configure_server(self, wizard_data):
|
||||
def do_configure_server(self, wizard_data: dict):
|
||||
self._logger.debug(f'configuring server: {wizard_data!r}')
|
||||
net_params = self._daemon.network.get_parameters()
|
||||
try:
|
||||
@@ -697,12 +702,12 @@ class ServerConnectWizard(AbstractWizard):
|
||||
net_params = net_params._replace(server=server, auto_connect=wizard_data['autoconnect'])
|
||||
self._daemon.network.run_from_another_thread(self._daemon.network.set_parameters(net_params))
|
||||
|
||||
def do_configure_autoconnect(self, wizard_data):
|
||||
def do_configure_autoconnect(self, wizard_data: dict):
|
||||
self._logger.debug(f'configuring autoconnect: {wizard_data!r}')
|
||||
if self._daemon.config.cv.NETWORK_AUTO_CONNECT.is_modifiable():
|
||||
self._daemon.config.NETWORK_AUTO_CONNECT = wizard_data['autoconnect']
|
||||
|
||||
def start(self, initial_data=None):
|
||||
def start(self, initial_data: dict = None) -> WizardViewState:
|
||||
if initial_data is None:
|
||||
initial_data = {}
|
||||
self.reset()
|
||||
|
||||
Reference in New Issue
Block a user