Browse Source

whitespace: cmdtest_d

The MMGen Project 1 month ago
parent
commit
9bc284ae24

+ 191 - 178
test/cmdtest_py_d/cfg.py

@@ -12,203 +12,217 @@
 test.cmdtest_py_d.cfg: configuration data for cmdtest.py
 """
 
-from .common import pwfile,hincog_fn,incog_id_fn,randbool
+from .common import pwfile, hincog_fn, incog_id_fn, randbool
 from ..include.common import cfg
 
-cmd_groups_altcoin = ['ref_altcoin','autosign','ethdev','xmrwallet','xmr_autosign']
+cmd_groups_altcoin = ['ref_altcoin', 'autosign', 'ethdev', 'xmrwallet', 'xmr_autosign']
 
 cmd_groups_dfl = {
-	'misc':             ('CmdTestMisc',{}),
-	'opts':             ('CmdTestOpts',{'full_data':True}),
-	'cfgfile':          ('CmdTestCfgFile',{'full_data':True}),
-	'help':             ('CmdTestHelp',{'full_data':True}),
-	'main':             ('CmdTestMain',{'full_data':True}),
-	'conv':             ('CmdTestWalletConv',{'is3seed':True,'modname':'wallet'}),
-	'ref':              ('CmdTestRef',{}),
-	'ref3':             ('CmdTestRef3Seed',{'is3seed':True,'modname':'ref_3seed'}),
-	'ref3_addr':        ('CmdTestRef3Addr',{'is3seed':True,'modname':'ref_3seed'}),
-	'ref3_pw':          ('CmdTestRef3Passwd',{'is3seed':True,'modname':'ref_3seed'}),
-	'ref_altcoin':      ('CmdTestRefAltcoin',{}),
-	'seedsplit':        ('CmdTestSeedSplit',{}),
-	'tool':             ('CmdTestTool',{'full_data':True}),
-	'input':            ('CmdTestInput',{}),
-	'output':           ('CmdTestOutput',{'modname':'misc','full_data':True}),
-	'autosign_clean':   ('CmdTestAutosignClean', {'modname':'autosign'}),
-	'autosign':         ('CmdTestAutosign',{}),
-	'autosign_automount': ('CmdTestAutosignAutomount', {'modname':'automount'}),
-	'autosign_eth':     ('CmdTestAutosignETH', {'modname':'automount_eth'}),
-	'regtest':          ('CmdTestRegtest',{}),
-#	'chainsplit':       ('CmdTestChainsplit',{}),
-	'ethdev':           ('CmdTestEthdev',{}),
-	'xmrwallet':        ('CmdTestXMRWallet',{}),
-	'xmr_autosign':     ('CmdTestXMRAutosign',{}),
+	'misc':               ('CmdTestMisc',              {}),
+	'opts':               ('CmdTestOpts',              {'full_data': True}),
+	'cfgfile':            ('CmdTestCfgFile',           {'full_data': True}),
+	'help':               ('CmdTestHelp',              {'full_data': True}),
+	'main':               ('CmdTestMain',              {'full_data': True}),
+	'conv':               ('CmdTestWalletConv',        {'is3seed': True, 'modname': 'wallet'}),
+	'ref':                ('CmdTestRef',               {}),
+	'ref3':               ('CmdTestRef3Seed',          {'is3seed': True, 'modname': 'ref_3seed'}),
+	'ref3_addr':          ('CmdTestRef3Addr',          {'is3seed': True, 'modname': 'ref_3seed'}),
+	'ref3_pw':            ('CmdTestRef3Passwd',        {'is3seed': True, 'modname': 'ref_3seed'}),
+	'ref_altcoin':        ('CmdTestRefAltcoin',        {}),
+	'seedsplit':          ('CmdTestSeedSplit',         {}),
+	'tool':               ('CmdTestTool',              {'full_data': True}),
+	'input':              ('CmdTestInput',             {}),
+	'output':             ('CmdTestOutput',            {'modname': 'misc', 'full_data': True}),
+	'autosign_clean':     ('CmdTestAutosignClean',     {'modname': 'autosign'}),
+	'autosign':           ('CmdTestAutosign',          {}),
+	'autosign_automount': ('CmdTestAutosignAutomount', {'modname': 'automount'}),
+	'autosign_eth':       ('CmdTestAutosignETH',       {'modname': 'automount_eth'}),
+	'regtest':            ('CmdTestRegtest',           {}),
+	# 'chainsplit':         ('CmdTestChainsplit',      {}),
+	'ethdev':             ('CmdTestEthdev',            {}),
+	'xmrwallet':          ('CmdTestXMRWallet',         {}),
+	'xmr_autosign':       ('CmdTestXMRAutosign',       {}),
 }
 
 cmd_groups_extra = {
-	'dev':                    ('CmdTestDev',{'modname':'misc'}),
-	'regtest_legacy':         ('CmdTestRegtestBDBWallet', {'modname':'regtest'}),
-	'autosign_btc':           ('CmdTestAutosignBTC',{'modname':'autosign'}),
-	'autosign_live':          ('CmdTestAutosignLive',{'modname':'autosign'}),
-	'autosign_live_simulate': ('CmdTestAutosignLiveSimulate',{'modname':'autosign'}),
-	'create_ref_tx':          ('CmdTestRefTX',{'modname':'misc','full_data':True}),
+	'dev':                    ('CmdTestDev',                  {'modname': 'misc'}),
+	'regtest_legacy':         ('CmdTestRegtestBDBWallet',     {'modname': 'regtest'}),
+	'autosign_btc':           ('CmdTestAutosignBTC',          {'modname': 'autosign'}),
+	'autosign_live':          ('CmdTestAutosignLive',         {'modname': 'autosign'}),
+	'autosign_live_simulate': ('CmdTestAutosignLiveSimulate', {'modname': 'autosign'}),
+	'create_ref_tx':          ('CmdTestRefTX',                {'modname': 'misc', 'full_data': True}),
 }
 
-cfgs = { # addr_idx_lists (except 31,32,33,34) must contain exactly 8 addresses
-	'1':  { 'wpasswd':       'Dorian-α',
-			'kapasswd':      'Grok the blockchain',
-			'addr_idx_list': '12,99,5-10,5,12',
-			'dep_generators':  {
-				pwfile:        'walletgen',
-				'mmdat':       'walletgen',
-				'addrs':       'addrgen',
-				'rawtx':       'txcreate',
-				'txbump':      'txbump',
-				'sigtx':       'txsign',
-				'mmwords':     'export_mnemonic',
-				'mmseed':      'export_seed',
-				'mmhex':       'export_hex',
-				'mmincog':     'export_incog',
-				'mmincox':     'export_incog_hex',
-				hincog_fn:     'export_incog_hidden',
-				incog_id_fn:   'export_incog_hidden',
-				'akeys.mmenc': 'keyaddrgen'
-			},
+cfgs = { # addr_idx_lists (except 31, 32, 33, 34) must contain exactly 8 addresses
+	'1': {
+		'wpasswd':       'Dorian-α',
+		'kapasswd':      'Grok the blockchain',
+		'addr_idx_list': '12,99,5-10,5,12',
+		'dep_generators': {
+			pwfile:        'walletgen',
+			'mmdat':       'walletgen',
+			'addrs':       'addrgen',
+			'rawtx':       'txcreate',
+			'txbump':      'txbump',
+			'sigtx':       'txsign',
+			'mmwords':     'export_mnemonic',
+			'mmseed':      'export_seed',
+			'mmhex':       'export_hex',
+			'mmincog':     'export_incog',
+			'mmincox':     'export_incog_hex',
+			hincog_fn:     'export_incog_hidden',
+			incog_id_fn:   'export_incog_hidden',
+			'akeys.mmenc': 'keyaddrgen'
+		},
 	},
-	'2':  { 'wpasswd':       'Hodling away',
-			'addr_idx_list': '37,45,3-6,22-23',
-			'seed_len':      128,
-			'dep_generators': {
-				'mmdat':   'walletgen2',
-				'addrs':   'addrgen2',
-				'rawtx':   'txcreate2',
-				'sigtx':   'txsign2',
-				'mmwords': 'export_mnemonic2',
-			},
+	'2': {
+		'wpasswd':       'Hodling away',
+		'addr_idx_list': '37,45,3-6,22-23',
+		'seed_len':      128,
+		'dep_generators': {
+			'mmdat':   'walletgen2',
+			'addrs':   'addrgen2',
+			'rawtx':   'txcreate2',
+			'sigtx':   'txsign2',
+			'mmwords': 'export_mnemonic2',
+		},
 	},
-	'3':  { 'wpasswd':       'Major miner',
-			'addr_idx_list': '73,54,1022-1023,2-5',
-			'dep_generators': {
-				'mmdat': 'walletgen3',
-				'addrs': 'addrgen3',
-				'rawtx': 'txcreate3',
-				'sigtx': 'txsign3'
-			},
+	'3': {
+		'wpasswd':       'Major miner',
+		'addr_idx_list': '73,54,1022-1023,2-5',
+		'dep_generators': {
+			'mmdat': 'walletgen3',
+			'addrs': 'addrgen3',
+			'rawtx': 'txcreate3',
+			'sigtx': 'txsign3'
+		},
 	},
-	'4':  { 'wpasswd':       'Hashrate good',
-			'addr_idx_list': '63,1004,542-544,7-9',
-			'seed_len':      192,
-			'dep_generators': {
-				'mmdat':   'walletgen4',
-				'mmbrain': 'walletgen4',
-				'addrs':   'addrgen4',
-				'rawtx':   'txcreate4',
-				'sigtx':   'txsign4',
-				'txdo':    'txdo4',
-			},
-			'bw_filename': 'brainwallet.mmbrain',
-			'bw_params':   '192,1',
+	'4': {
+		'wpasswd':       'Hashrate good',
+		'addr_idx_list': '63,1004,542-544,7-9',
+		'seed_len':      192,
+		'dep_generators': {
+			'mmdat':   'walletgen4',
+			'mmbrain': 'walletgen4',
+			'addrs':   'addrgen4',
+			'rawtx':   'txcreate4',
+			'sigtx':   'txsign4',
+			'txdo':    'txdo4',
+		},
+		'bw_filename': 'brainwallet.mmbrain',
+		'bw_params':   '192,1',
 	},
-	'5':  { 'wpasswd':     'My changed password-α',
-			'hash_preset': '2',
-			'dep_generators': {
-				'mmdat': 'passchg',
-				pwfile:  'passchg',
-			},
+	'5': {
+		'wpasswd':     'My changed password-α',
+		'hash_preset': '2',
+		'dep_generators': {
+			'mmdat': 'passchg',
+			pwfile:  'passchg',
+		},
 	},
-	'6':  { 'seed_len':       128,
-			'seed_id':        'FE3C6545',
-			'ref_bw_seed_id': '33F10310',
-			'wpasswd':        'reference password',
-			'kapasswd':      '',
-			'dep_generators':  {
-				'mmdat':       'ref_walletgen_brain_1',
-				pwfile:        'ref_walletgen_brain_1',
-				'addrs':       'refaddrgen_1',
-				'akeys.mmenc': 'refkeyaddrgen_1'
-			},
+	'6': {
+		'seed_len':       128,
+		'seed_id':        'FE3C6545',
+		'ref_bw_seed_id': '33F10310',
+		'wpasswd':        'reference password',
+		'kapasswd':      '',
+		'dep_generators': {
+			'mmdat':       'ref_walletgen_brain_1',
+			pwfile:        'ref_walletgen_brain_1',
+			'addrs':       'refaddrgen_1',
+			'akeys.mmenc': 'refkeyaddrgen_1'
+		},
 	},
-	'7':  { 'seed_len':       192,
-			'seed_id':        '1378FC64',
-			'ref_bw_seed_id': 'CE918388',
-			'wpasswd':        'reference password',
-			'kapasswd':      '',
-			'dep_generators':  {
-				'mmdat':       'ref_walletgen_brain_2',
-				pwfile:        'ref_walletgen_brain_2',
-				'addrs':       'refaddrgen_2',
-				'akeys.mmenc': 'refkeyaddrgen_2'
-			},
+	'7': {
+		'seed_len':       192,
+		'seed_id':        '1378FC64',
+		'ref_bw_seed_id': 'CE918388',
+		'wpasswd':        'reference password',
+		'kapasswd':      '',
+		'dep_generators': {
+			'mmdat':       'ref_walletgen_brain_2',
+			pwfile:        'ref_walletgen_brain_2',
+			'addrs':       'refaddrgen_2',
+			'akeys.mmenc': 'refkeyaddrgen_2'
+		},
 	},
-	'8':  { 'seed_len':       256,
-			'seed_id':        '98831F3A',
-			'ref_bw_seed_id': 'B48CD7FC',
-			'wpasswd':        'reference password',
-			'kapasswd':      '',
-			'dep_generators':  {
-				'mmdat':       'ref_walletgen_brain_3',
-				pwfile:        'ref_walletgen_brain_3',
-				'addrs':       'refaddrgen_3',
-				'akeys.mmenc': 'refkeyaddrgen_3'
-			},
+	'8': {
+		'seed_len':       256,
+		'seed_id':        '98831F3A',
+		'ref_bw_seed_id': 'B48CD7FC',
+		'wpasswd':        'reference password',
+		'kapasswd':      '',
+		'dep_generators': {
+			'mmdat':       'ref_walletgen_brain_3',
+			pwfile:        'ref_walletgen_brain_3',
+			'addrs':       'refaddrgen_3',
+			'akeys.mmenc': 'refkeyaddrgen_3'
+		},
 	},
-	'9':  { 'tool_enc_infn': 'tool_encrypt.in',
-			'dep_generators': {
-				'tool_encrypt.in':       'tool_encrypt',
-				'tool_encrypt.in.mmenc': 'tool_encrypt',
-			},
+	'9': {
+		'tool_enc_infn': 'tool_encrypt.in',
+		'dep_generators': {
+			'tool_encrypt.in':       'tool_encrypt',
+			'tool_encrypt.in.mmenc': 'tool_encrypt',
+		},
 	},
 	'11': {}, # wallet
 	'12': {}, # wallet
 	'13': {}, # wallet
-	'14': { 'kapasswd':      'Maxwell',
-			'wpasswd':       'The Halving',
-			'addr_idx_list': '61,998,502-504,7-9',
-			'seed_len':      256,
-			'dep_generators': {
-				'mmdat':       'walletgen14',
-				'addrs':       'addrgen14',
-				'akeys.mmenc': 'keyaddrgen14',
-			},
+	'14': {
+		'kapasswd':      'Maxwell',
+		'wpasswd':       'The Halving',
+		'addr_idx_list': '61,998,502-504,7-9',
+		'seed_len':      256,
+		'dep_generators': {
+			'mmdat':       'walletgen14',
+			'addrs':       'addrgen14',
+			'akeys.mmenc': 'keyaddrgen14',
+		},
 	},
-	'15': { 'wpasswd':       'Dorian-α',
-			'kapasswd':      'Grok the blockchain',
-			'addr_idx_list': '12,99,5-10,5,12',
-			'dep_generators':  {
-				pwfile:       'walletgen_dfl_wallet',
-				'addrs':      'addrgen_dfl_wallet',
-				'rawtx':      'txcreate_dfl_wallet',
-				'sigtx':      'txsign_dfl_wallet',
-				'mmseed':     'export_seed_dfl_wallet',
-				'del_dw_run': 'delete_dfl_wallet',
-			},
+	'15': {
+		'wpasswd':       'Dorian-α',
+		'kapasswd':      'Grok the blockchain',
+		'addr_idx_list': '12,99,5-10,5,12',
+		'dep_generators': {
+			pwfile:       'walletgen_dfl_wallet',
+			'addrs':      'addrgen_dfl_wallet',
+			'rawtx':      'txcreate_dfl_wallet',
+			'sigtx':      'txsign_dfl_wallet',
+			'mmseed':     'export_seed_dfl_wallet',
+			'del_dw_run': 'delete_dfl_wallet',
+		},
 	},
-	'16': { 'wpasswd':     'My changed password',
-			'hash_preset': '2',
-			'dep_generators': {
-				pwfile: 'passchg_dfl_wallet',
-			},
+	'16': {
+		'wpasswd':     'My changed password',
+		'hash_preset': '2',
+		'dep_generators': {
+			pwfile: 'passchg_dfl_wallet',
+		},
 	},
 	'17': {}, # regtest
 	'18': {}, # autosign
-	'19': { 'wpasswd':'abc' },
-	'20': { 'wpasswd':       'Vsize it',
-			'addr_idx_list': '1-8',
-			'seed_len':      256,
-			'dep_generators': {
-				'mmdat': 'walletgen5',
-				'addrs': 'addrgen5',
-				'rawtx': 'txcreate5',
-				'sigtx': 'txsign5',
+	'19': {'wpasswd': 'abc'},
+	'20': {
+		'wpasswd':       'Vsize it',
+		'addr_idx_list': '1-8',
+		'seed_len':      256,
+		'dep_generators': {
+			'mmdat': 'walletgen5',
+			'addrs': 'addrgen5',
+			'rawtx': 'txcreate5',
+			'sigtx': 'txsign5',
 		},
 	},
-	'21': { 'wpasswd':       'Vsize it',
-			'addr_idx_list': '1-8',
-			'seed_len':      256,
-			'dep_generators': {
-				'mmdat': 'walletgen6',
-				'addrs': 'addrgen6',
-				'rawtx': 'txcreate6',
-				'sigtx': 'txsign6',
+	'21': {
+		'wpasswd':       'Vsize it',
+		'addr_idx_list': '1-8',
+		'seed_len':      256,
+		'dep_generators': {
+			'mmdat': 'walletgen6',
+			'addrs': 'addrgen6',
+			'rawtx': 'txcreate6',
+			'sigtx': 'txsign6',
 		},
 	},
 	'22': {}, # ethdev
@@ -236,16 +250,15 @@ def fixup_cfgs():
 	for k in cfgs:
 		cfgs[k]['tmpdir'] = os.path.join('test', 'tmp', str(k))
 
-	for src,target in (
-			('6','11'),
-			('7','12'),
-			('8','13'),
-			('6','26'),
-			('7','27'),
-			('8','28')
-		):
+	for src, target in (
+			('6', '11'),
+			('7', '12'),
+			('8', '13'),
+			('6', '26'),
+			('7', '27'),
+			('8', '28')):
 		cfgs[target].update(cfgs[src])
-		cfgs[target]['tmpdir'] = os.path.join('test','tmp',target)
+		cfgs[target]['tmpdir'] = os.path.join('test', 'tmp', target)
 
 	for k in cfgs:
 		cfgs[k]['segwit'] = randbool() if cfg.segwit_random else bool(cfg.segwit or cfg.bech32)

+ 38 - 31
test/cmdtest_py_d/common.py

@@ -20,12 +20,12 @@
 test.cmdtest_py_d.common: Shared routines and data for the cmdtest.py test suite
 """
 
-import sys,os
+import sys, os
 
 from mmgen.color import green, blue, gray
 from mmgen.util import msg
 
-from ..include.common import cfg,getrand,text_jp,text_zh,ascii_cyr_gr,lat_cyr_gr
+from ..include.common import cfg, getrand, text_jp, text_zh, ascii_cyr_gr, lat_cyr_gr
 
 rt_pw = 'abc-α'
 ref_wallet_brainpass = 'abc'
@@ -45,11 +45,11 @@ hincog_seedlen = 256
 incog_id_fn = 'incog_id'
 non_mmgen_fn = 'coinkey'
 
-ref_dir = os.path.join('test','ref')
-dfl_words_file = os.path.join(ref_dir,'98831F3A.mmwords')
-dfl_bip39_file = os.path.join(ref_dir,'98831F3A.bip39')
+ref_dir = os.path.join('test', 'ref')
+dfl_words_file = os.path.join(ref_dir, '98831F3A.mmwords')
+dfl_bip39_file = os.path.join(ref_dir, '98831F3A.bip39')
 
-from mmgen.obj import MMGenTxComment,TwComment
+from mmgen.obj import MMGenTxComment, TwComment
 
 tx_comment_jp = text_jp
 tx_comment_zh = text_zh
@@ -75,8 +75,8 @@ def ok_msg():
 		return
 	sys.stderr.write(green('\nOK\n') if cfg.exact_output or cfg.verbose else ' OK\n')
 
-def skip(name,reason=None):
-	msg(gray('Skipping {}{}'.format( name, f' ({reason})' if reason else '' )))
+def skip(name, reason=None):
+	msg(gray('Skipping {}{}'.format(name, f' ({reason})' if reason else '')))
 	return 'skip'
 
 def confirm_continue():
@@ -85,7 +85,7 @@ def confirm_continue():
 			cfg,
 			blue('Continue? (Y/n): '),
 			default_yes     = True,
-			complete_prompt = True ):
+			complete_prompt = True):
 		if cfg.verbose or cfg.exact_output:
 			sys.stderr.write('\n')
 	else:
@@ -101,18 +101,25 @@ def get_env_without_debug_vars():
 			del ret[k]
 	return ret
 
-def get_file_with_ext(tdir,ext,delete=True,no_dot=False,return_list=False,delete_all=False,substr=False):
+def get_file_with_ext(
+		tdir,
+		ext,
+		delete      = True,
+		no_dot      = False,
+		return_list = False,
+		delete_all  = False,
+		substr      = False):
 
 	dot = '' if no_dot else '.'
 
 	def have_match(fn):
 		return (
 			fn == ext
-			or fn.endswith( dot + ext )
-			or (substr and ext in fn) )
+			or fn.endswith(dot + ext)
+			or (substr and ext in fn))
 
 	# Don’t use os.scandir here - it returns broken paths under Windows/MSYS2
-	flist = [os.path.join(tdir,name) for name in os.listdir(tdir) if have_match(name)]
+	flist = [os.path.join(tdir, name) for name in os.listdir(tdir) if have_match(name)]
 
 	if not flist:
 		return False
@@ -135,26 +142,26 @@ def get_file_with_ext(tdir,ext,delete=True,no_dot=False,return_list=False,delete
 
 def get_comment(do_shuffle=False):
 	labels = [
-		"Automotive",
-		"Travel expenses",
-		"Healthcare",
+		'Automotive',
+		'Travel expenses',
+		'Healthcare',
 		tx_comment_jp[:40],
 		tx_comment_zh[:40],
-		"Alice’s allowance",
-		"Bob’s bequest",
-		"House purchase",
-		"Real estate fund",
-		"Job 1",
-		"XYZ Corp.",
-		"Eddie’s endowment",
-		"Emergency fund",
-		"Real estate fund",
-		"Ian’s inheritance",
-		"",
-		"Rainy day",
-		"Fred’s funds",
-		"Job 2",
-		"Carl’s capital",
+		'Alice’s allowance',
+		'Bob’s bequest',
+		'House purchase',
+		'Real estate fund',
+		'Job 1',
+		'XYZ Corp.',
+		'Eddie’s endowment',
+		'Emergency fund',
+		'Real estate fund',
+		'Ian’s inheritance',
+		'',
+		'Rainy day',
+		'Fred’s funds',
+		'Job 2',
+		'Carl’s capital',
 	]
 	from random import shuffle
 	global label_iter

+ 122 - 122
test/cmdtest_py_d/ct_autosign.py

@@ -21,7 +21,7 @@ test.cmdtest_py_d.ct_autosign: Autosign tests for the cmdtest.py test suite
 """
 
 import sys, os, time, shutil, atexit
-from subprocess import run,DEVNULL
+from subprocess import run, DEVNULL
 from pathlib import Path
 
 from mmgen.cfg import Config
@@ -45,7 +45,7 @@ from ..include.common import (
 	end_silence,
 	VirtBlockDevice,
 )
-from .common import ref_dir,dfl_words_file,dfl_bip39_file
+from .common import ref_dir, dfl_words_file, dfl_bip39_file
 
 from .ct_base import CmdTestBase
 from .input import stealth_mnemonic_entry
@@ -58,9 +58,9 @@ class CmdTestAutosignBase(CmdTestBase):
 	threaded     = False
 	daemon_coins = []
 
-	def __init__(self,trunner,cfgs,spawn):
+	def __init__(self, trunner, cfgs, spawn):
 
-		CmdTestBase.__init__(self,trunner,cfgs,spawn)
+		CmdTestBase.__init__(self, trunner, cfgs, spawn)
 
 		if trunner is None:
 			return
@@ -89,7 +89,7 @@ class CmdTestAutosignBase(CmdTestBase):
 			self.spawn_env['MMGEN_TEST_SUITE_AUTOSIGN_THREADED'] = '1'
 
 	def __del__(self):
-		if hasattr(self,'have_dummy_control_files'):
+		if hasattr(self, 'have_dummy_control_files'):
 			db = LEDControl.boards['dummy']
 			for fn in (db.status, db.trigger):
 				run(f'sudo rm -f {fn}'.split(), check=True)
@@ -102,13 +102,13 @@ class CmdTestAutosignBase(CmdTestBase):
 				for label in (self.asi.dev_label, self.asi.ramdisk.label):
 					self._macOS_eject_disk(label)
 
-	def _create_autosign_instances(self,create_dirs):
+	def _create_autosign_instances(self, create_dirs):
 		d = {'offline': {'name':'asi'}}
 
 		if self.have_online:
 			d['online'] =  {'name':'asi_online'}
 
-		for subdir,data in d.items():
+		for subdir, data in d.items():
 			asi = Autosign(
 				Config({
 					'coins': ','.join(self.coins),
@@ -164,17 +164,17 @@ class CmdTestAutosignBase(CmdTestBase):
 
 	def _macOS_eject_disk(self, label):
 		try:
-			run(['diskutil' ,'eject', label], stdout=DEVNULL, stderr=DEVNULL)
+			run(['diskutil' , 'eject', label], stdout=DEVNULL, stderr=DEVNULL)
 		except:
 			pass
 
 	def start_daemons(self):
-		self.spawn('',msg_only=True)
+		self.spawn('', msg_only=True)
 		start_test_daemons(*self.network_ids)
 		return 'ok'
 
 	def stop_daemons(self):
-		self.spawn('',msg_only=True)
+		self.spawn('', msg_only=True)
 		stop_test_daemons(*self.network_ids)
 		return 'ok'
 
@@ -205,16 +205,16 @@ class CmdTestAutosignBase(CmdTestBase):
 			no_passthru_opts = True)
 
 		if use_dfl_wallet:
-			t.expect( 'Use default wallet for autosigning? (Y/n): ', 'y' )
+			t.expect('Use default wallet for autosigning? (Y/n): ', 'y')
 			t.passphrase('MMGen wallet', passwd)
 		else:
 			if use_dfl_wallet is not None: # None => no dfl wallet present
-				t.expect( 'Use default wallet for autosigning? (Y/n): ', 'n' )
-			mn_file = mn_file or { 'mmgen': dfl_words_file, 'bip39': dfl_bip39_file }[mn_type]
+				t.expect('Use default wallet for autosigning? (Y/n): ', 'n')
+			mn_file = mn_file or {'mmgen': dfl_words_file, 'bip39': dfl_bip39_file}[mn_type]
 			mn = read_from_file(mn_file).strip().split()
 			if not seed_len:
-				t.expect('words: ',{ 12:'1', 18:'2', 24:'3' }[len(mn)])
-				t.expect('OK? (Y/n): ','\n')
+				t.expect('words: ', {12:'1', 18:'2', 24:'3'}[len(mn)])
+				t.expect('OK? (Y/n): ', '\n')
 			from mmgen.mn_entry import mn_entry
 			entry_mode = 'full'
 			mne = mn_entry(cfg, mn_type, entry_mode)
@@ -225,7 +225,7 @@ class CmdTestAutosignBase(CmdTestBase):
 					'Type a number.*: ',
 					str(mne.entry_modes.index(entry_mode) + 1),
 					regex = True)
-			stealth_mnemonic_entry(t,mne,mn,entry_mode)
+			stealth_mnemonic_entry(t, mne, mn, entry_mode)
 
 		t.written_to_file('Autosign wallet')
 
@@ -272,7 +272,7 @@ class CmdTestAutosignBase(CmdTestBase):
 			self._macOS_eject_disk(loc.dev_label)
 
 	def _mount_ops(self, loc, cmd, *args, **kwargs):
-		return getattr(getattr(self,loc),cmd)(*args, silent=self.silent_mount, **kwargs)
+		return getattr(getattr(self, loc), cmd)(*args, silent=self.silent_mount, **kwargs)
 
 	def do_mount(self, *args, **kwargs):
 		return self._mount_ops('asi', 'do_mount', *args, **kwargs)
@@ -282,7 +282,7 @@ class CmdTestAutosignBase(CmdTestBase):
 
 	def _gen_listing(self):
 		for k in self.asi.dirs:
-			d = getattr(self.asi,k)
+			d = getattr(self.asi, k)
 			if d.is_dir():
 				yield '{:12} {}'.format(
 					str(Path(*d.parts[6:])) + ':',
@@ -364,7 +364,7 @@ class CmdTestAutosignClean(CmdTestAutosignBase):
 		self.asi = Autosign(Config({'_clone': self.asi.cfg, 'coins': 'xmr,btc,bch,eth'}))
 		return self._clean('xmr,btc,bch,eth')
 
-	def _clean(self,coins):
+	def _clean(self, coins):
 
 		self.spawn('', msg_only=True)
 
@@ -377,7 +377,7 @@ class CmdTestAutosignClean(CmdTestAutosignBase):
 		self.create_fake_tx_files()
 		before = '\n'.join(self._gen_listing())
 
-		t = self.spawn('mmgen-autosign', [f'--coins={coins}','clean'], no_msg=True)
+		t = self.spawn('mmgen-autosign', [f'--coins={coins}', 'clean'], no_msg=True)
 		out = t.read()
 
 		if sys.platform == 'darwin':
@@ -447,18 +447,18 @@ class CmdTestAutosignThreaded(CmdTestAutosignBase):
 		return 'silent'
 
 	def wait_loop_kill(self):
-		self.spawn('',msg_only=True)
+		self.spawn('', msg_only=True)
 		pid = int(self.read_from_tmpfile('autosign_thread_pid'))
 		self.delete_tmpfile('autosign_thread_pid')
 		from signal import SIGTERM
 		imsg(purple(f'Killing autosign wait loop [PID {pid}]'))
 		try:
-			os.kill(pid,SIGTERM)
+			os.kill(pid, SIGTERM)
 		except:
 			imsg(yellow(f'{pid}: no such process'))
 		return 'ok'
 
-	def _wait_signed(self,desc):
+	def _wait_signed(self, desc):
 		oqmsg_r(gray(f'→ offline wallet{"s" if desc.endswith("s") else ""} waiting for {desc}'))
 		assert not self.asi.device_inserted, f'‘{self.asi.dev_label}’ is inserted!'
 		assert not self.asi.mountpoint.is_mount(), f'‘{self.asi.mountpoint}’ is mounted!'
@@ -510,69 +510,69 @@ class CmdTestAutosignThreaded(CmdTestAutosignBase):
 
 class CmdTestAutosign(CmdTestAutosignBase):
 	'autosigning transactions for all supported coins'
-	coins           = ['btc','bch','ltc','eth']
-	daemon_coins    = ['btc','bch','ltc']
-	txfile_coins    = ['btc','bch','ltc','eth','mm1','etc']
+	coins           = ['btc', 'bch', 'ltc', 'eth']
+	daemon_coins    = ['btc', 'bch', 'ltc']
+	txfile_coins    = ['btc', 'bch', 'ltc', 'eth', 'mm1', 'etc']
 	have_online     = False
 	live            = False
 	simulate_led    = True
 	no_insert_check = True
 
 	filedir_map = (
-		('btc',''),
-		('bch',''),
-		('ltc','litecoin'),
-		('eth','ethereum'),
-		('mm1','ethereum'),
-		('etc','ethereum_classic'),
+		('btc', ''),
+		('bch', ''),
+		('ltc', 'litecoin'),
+		('eth', 'ethereum'),
+		('mm1', 'ethereum'),
+		('etc', 'ethereum_classic'),
 	)
 
 	cmd_group = (
-		('start_daemons',            'starting daemons'),
-		('copy_tx_files',            'copying transaction files'),
-		('gen_key',                  'generating key'),
-		('create_dfl_wallet',        'creating default MMGen wallet'),
-		('bad_opt1',                 'running ‘mmgen-autosign’ with --seed-len in invalid context'),
-		('bad_opt2',                 'running ‘mmgen-autosign’ with --mnemonic-fmt in invalid context'),
-		('bad_opt3',                 'running ‘mmgen-autosign’ with --led in invalid context'),
-		('run_setup_dfl_wallet',     'running ‘autosign setup’ (with default wallet)'),
-		('sign_quiet',               'signing transactions (--quiet)'),
-		('remove_signed_txfiles',    'removing signed transaction files'),
-		('run_setup_bip39',          'running ‘autosign setup’ (BIP39 mnemonic)'),
-		('create_bad_txfiles',       'creating bad transaction files'),
-		('sign_full_summary',        'signing transactions (--full-summary)'),
-		('remove_signed_txfiles_btc','removing transaction files (BTC only)'),
-		('remove_bad_txfiles',       'removing bad transaction files'),
-		('sign_led',                 'signing transactions (--led - BTC files only)'),
-		('remove_signed_txfiles',    'removing signed transaction files'),
-		('sign_stealth_led',         'signing transactions (--stealth-led)'),
-		('remove_signed_txfiles',    'removing signed transaction files'),
-		('copy_msgfiles',            'copying message files'),
-		('sign_quiet_msg',           'signing transactions and messages (--quiet)'),
-		('remove_signed_txfiles',    'removing signed transaction files'),
-		('create_bad_txfiles2',      'creating bad transaction files'),
-		('remove_signed_msgfiles',   'removing signed message files'),
-		('create_invalid_msgfile',   'creating invalid message file'),
-		('sign_full_summary_msg',    'signing transactions and messages (--full-summary)'),
-		('remove_invalid_msgfile',   'removing invalid message file'),
-		('remove_bad_txfiles2',      'removing bad transaction files'),
-		('sign_no_unsigned',         'signing transactions and messages (nothing to sign)'),
-		('sign_no_unsigned_xmr',     'signing transactions and messages (nothing to sign, with XMR)'),
-		('sign_no_unsigned_xmronly', 'signing transactions and messages (nothing to sign, XMR-only)'),
-		('wipe_key',                 'wiping the wallet encryption key'),
-		('stop_daemons',             'stopping daemons'),
-		('sign_bad_no_daemon',       'signing transactions (error, no daemons running)'),
+		('start_daemons',             'starting daemons'),
+		('copy_tx_files',             'copying transaction files'),
+		('gen_key',                   'generating key'),
+		('create_dfl_wallet',         'creating default MMGen wallet'),
+		('bad_opt1',                  'running ‘mmgen-autosign’ with --seed-len in invalid context'),
+		('bad_opt2',                  'running ‘mmgen-autosign’ with --mnemonic-fmt in invalid context'),
+		('bad_opt3',                  'running ‘mmgen-autosign’ with --led in invalid context'),
+		('run_setup_dfl_wallet',      'running ‘autosign setup’ (with default wallet)'),
+		('sign_quiet',                'signing transactions (--quiet)'),
+		('remove_signed_txfiles',     'removing signed transaction files'),
+		('run_setup_bip39',           'running ‘autosign setup’ (BIP39 mnemonic)'),
+		('create_bad_txfiles',        'creating bad transaction files'),
+		('sign_full_summary',         'signing transactions (--full-summary)'),
+		('remove_signed_txfiles_btc', 'removing transaction files (BTC only)'),
+		('remove_bad_txfiles',        'removing bad transaction files'),
+		('sign_led',                  'signing transactions (--led - BTC files only)'),
+		('remove_signed_txfiles',     'removing signed transaction files'),
+		('sign_stealth_led',          'signing transactions (--stealth-led)'),
+		('remove_signed_txfiles',     'removing signed transaction files'),
+		('copy_msgfiles',             'copying message files'),
+		('sign_quiet_msg',            'signing transactions and messages (--quiet)'),
+		('remove_signed_txfiles',     'removing signed transaction files'),
+		('create_bad_txfiles2',       'creating bad transaction files'),
+		('remove_signed_msgfiles',    'removing signed message files'),
+		('create_invalid_msgfile',    'creating invalid message file'),
+		('sign_full_summary_msg',     'signing transactions and messages (--full-summary)'),
+		('remove_invalid_msgfile',    'removing invalid message file'),
+		('remove_bad_txfiles2',       'removing bad transaction files'),
+		('sign_no_unsigned',          'signing transactions and messages (nothing to sign)'),
+		('sign_no_unsigned_xmr',      'signing transactions and messages (nothing to sign, with XMR)'),
+		('sign_no_unsigned_xmronly',  'signing transactions and messages (nothing to sign, XMR-only)'),
+		('wipe_key',                  'wiping the wallet encryption key'),
+		('stop_daemons',              'stopping daemons'),
+		('sign_bad_no_daemon',        'signing transactions (error, no daemons running)'),
 	)
 
-	def __init__(self,trunner,cfgs,spawn):
+	def __init__(self, trunner, cfgs, spawn):
 
-		super().__init__(trunner,cfgs,spawn)
+		super().__init__(trunner, cfgs, spawn)
 
 		if trunner is None:
 			return
 
 		if self.live and not cfg.exact_output:
-			die(1,red('autosign_live tests must be run with --exact-output enabled!'))
+			die(1, red('autosign_live tests must be run with --exact-output enabled!'))
 
 		if self.no_insert_check:
 			self.opts.append('--no-insert-check')
@@ -585,10 +585,10 @@ class CmdTestAutosign(CmdTestAutosignBase):
 			for coin in self.coins:
 				if coin == 'xmr':
 					continue
-				sdir = os.path.join('test','ref',fmap[coin])
+				sdir = os.path.join('test', 'ref', fmap[coin])
 				for fn in os.listdir(sdir):
 					if fn.endswith(f'[{coin.upper()}].rawmsg.json'):
-						yield os.path.join(sdir,fn)
+						yield os.path.join(sdir, fn)
 
 		self.ref_msgfiles = tuple(gen_msg_fns())
 		self.good_msg_count = 0
@@ -606,20 +606,20 @@ class CmdTestAutosign(CmdTestAutosignBase):
 
 	def gen_key(self):
 		self.insert_device()
-		t = self.spawn( 'mmgen-autosign', self.opts + ['gen_key'] )
+		t = self.spawn('mmgen-autosign', self.opts + ['gen_key'])
 		t.expect_getend('Wrote key file ')
 		t.read()
 		self.remove_device()
 		return t
 
 	def create_dfl_wallet(self):
-		t = self.spawn( 'mmgen-walletconv', [
+		t = self.spawn('mmgen-walletconv', [
 				f'--outdir={cfg.data_dir}',
 				'--usr-randchars=0', '--quiet', '--hash-preset=1', '--label=foo',
 				'test/ref/98831F3A.hex'
 			]
 		)
-		t.passphrase_new('new MMGen wallet','abc')
+		t.passphrase_new('new MMGen wallet', 'abc')
 		t.written_to_file('MMGen wallet')
 		return t
 
@@ -638,13 +638,13 @@ class CmdTestAutosign(CmdTestAutosignBase):
 		return self._bad_opt(['--led', 'gen_key'], 'makes no sense')
 
 	def run_setup_dfl_wallet(self):
-		return self.run_setup(mn_type='default',use_dfl_wallet=True)
+		return self.run_setup(mn_type='default', use_dfl_wallet=True)
 
 	def run_setup_bip39(self):
 		from mmgen.cfgfile import mmgen_cfg_file
-		fn = mmgen_cfg_file(cfg,'usr').fn
-		old_data = mmgen_cfg_file(cfg,'usr').get_data(fn)
-		new_data = [d.replace('bip39:fixed','bip39:full')[2:]
+		fn = mmgen_cfg_file(cfg, 'usr').fn
+		old_data = mmgen_cfg_file(cfg, 'usr').get_data(fn)
+		new_data = [d.replace('bip39:fixed', 'bip39:full')[2:]
 			if d.startswith('# mnemonic_entry_modes') else d for d in old_data]
 		with open(fn, 'w') as fh:
 			fh.write('\n'.join(new_data) + '\n')
@@ -657,7 +657,7 @@ class CmdTestAutosign(CmdTestAutosignBase):
 		return t
 
 	def copy_tx_files(self):
-		self.spawn('',msg_only=True)
+		self.spawn('', msg_only=True)
 		return self.tx_file_ops('copy')
 
 	def remove_signed_txfiles(self):
@@ -665,24 +665,24 @@ class CmdTestAutosign(CmdTestAutosignBase):
 		return 'skip'
 
 	def remove_signed_txfiles_btc(self):
-		self.tx_file_ops('remove_signed',txfile_coins=['btc'])
+		self.tx_file_ops('remove_signed', txfile_coins=['btc'])
 		return 'skip'
 
-	def tx_file_ops(self,op,txfile_coins=[]):
+	def tx_file_ops(self, op, txfile_coins=[]):
 
-		assert op in ('copy','set_count','remove_signed')
+		assert op in ('copy', 'set_count', 'remove_signed')
 
 		from .ct_ref import CmdTestRef
 		def gen():
 			d = CmdTestRef.sources['ref_tx_file']
 			dirmap = [e for e in self.filedir_map if e[0] in (txfile_coins or self.txfile_coins)]
-			for coin,coindir in dirmap:
-				for network in (0,1):
+			for coin, coindir in dirmap:
+				for network in (0, 1):
 					fn = d[coin][network]
 					if fn:
-						yield (coindir,fn)
+						yield (coindir, fn)
 
-		data = list(gen()) + [('','25EFA3[2.34].testnet.rawtx')] # TX with 2 non-MMGen outputs
+		data = list(gen()) + [('', '25EFA3[2.34].testnet.rawtx')] # TX with 2 non-MMGen outputs
 
 		self.tx_count = len(data)
 		if op == 'set_count':
@@ -694,16 +694,16 @@ class CmdTestAutosign(CmdTestAutosignBase):
 		self.do_mount(verbose=cfg.verbose or cfg.exact_output)
 		end_silence()
 
-		for coindir,fn in data:
-			src = joinpath(ref_dir,coindir,fn)
+		for coindir, fn in data:
+			src = joinpath(ref_dir, coindir, fn)
 			if cfg.debug_utf8:
 				ext = '.testnet.rawtx' if fn.endswith('.testnet.rawtx') else '.rawtx'
 				fn = fn[:-len(ext)] + '-α' + ext
 			target = joinpath(self.asi.tx_dir, fn)
 			if not op == 'remove_signed':
-				shutil.copyfile(src,target)
+				shutil.copyfile(src, target)
 			try:
-				os.unlink(target.replace('.rawtx','.sigtx'))
+				os.unlink(target.replace('.rawtx', '.sigtx'))
 			except:
 				pass
 
@@ -721,15 +721,15 @@ class CmdTestAutosign(CmdTestAutosignBase):
 	create_bad_txfiles2 = create_bad_txfiles
 	remove_bad_txfiles2 = remove_bad_txfiles
 
-	def bad_txfiles(self,op):
+	def bad_txfiles(self, op):
 		self.insert_device()
 		self.do_mount()
 		# create or delete 2 bad tx files
-		self.spawn('',msg_only=True)
-		fns = [joinpath(self.asi.tx_dir, f'bad{n}.rawtx') for n in (1,2)]
+		self.spawn('', msg_only=True)
+		fns = [joinpath(self.asi.tx_dir, f'bad{n}.rawtx') for n in (1, 2)]
 		if op == 'create':
 			for fn in fns:
-				with open(fn,'w') as fp:
+				with open(fn, 'w') as fp:
 					fp.write('bad tx data\n')
 			self.bad_tx_count = 2
 		elif op == 'remove':
@@ -755,16 +755,16 @@ class CmdTestAutosign(CmdTestAutosignBase):
 	def remove_invalid_msgfile(self):
 		return self.msgfile_ops('remove_invalid')
 
-	def msgfile_ops(self,op):
-		self.spawn('',msg_only=True)
-		destdir = joinpath(self.asi.mountpoint,'msg')
+	def msgfile_ops(self, op):
+		self.spawn('', msg_only=True)
+		destdir = joinpath(self.asi.mountpoint, 'msg')
 		self.insert_device()
 		self.do_mount()
-		os.makedirs(destdir,exist_ok=True)
+		os.makedirs(destdir, exist_ok=True)
 		if op.endswith('_invalid'):
-			fn = os.path.join(destdir,'DEADBE[BTC].rawmsg.json')
+			fn = os.path.join(destdir, 'DEADBE[BTC].rawmsg.json')
 			if op == 'create_invalid':
-				with open(fn,'w') as fp:
+				with open(fn, 'w') as fp:
 					fp.write('bad data\n')
 				self.bad_msg_count += 1
 			elif op == 'remove_invalid':
@@ -778,9 +778,9 @@ class CmdTestAutosign(CmdTestAutosignBase):
 					else:
 						self.good_msg_count += 1
 					imsg(f'Copying: {fn} -> {destdir}')
-					shutil.copy2(fn,destdir)
+					shutil.copy2(fn, destdir)
 				elif op == 'remove_signed':
-					os.unlink(os.path.join( destdir, os.path.basename(fn).replace('rawmsg','sigmsg') ))
+					os.unlink(os.path.join(destdir, os.path.basename(fn).replace('rawmsg', 'sigmsg')))
 		self.do_umount()
 		self.remove_device()
 		return 'ok'
@@ -858,7 +858,7 @@ class CmdTestAutosign(CmdTestAutosignBase):
 			return 'skip'
 		return self._sign_no_unsigned(
 			coins = 'XMR,BTC',
-			present = ['xmr_signables','non_xmr_signables'])
+			present = ['xmr_signables', 'non_xmr_signables'])
 
 	def sign_no_unsigned_xmronly(self):
 		if self.coins == ['btc']:
@@ -868,17 +868,17 @@ class CmdTestAutosign(CmdTestAutosignBase):
 			present = ['xmr_signables'],
 			absent  = ['non_xmr_signables'])
 
-	def _sign_no_unsigned(self,coins,present=[],absent=[]):
+	def _sign_no_unsigned(self, coins, present=[], absent=[]):
 		self.insert_device()
 		t = self.spawn('mmgen-autosign', ['--quiet', '--no-insert-check', f'--coins={coins}'])
 		res = t.read()
 		self.remove_device()
 		for signable_list in present:
-			for signable_clsname in getattr(Signable,signable_list):
+			for signable_clsname in getattr(Signable, signable_list):
 				desc = getattr(Signable, signable_clsname).desc
 				assert f'No unsigned {desc}s' in res, f'‘No unsigned {desc}s’ missing in output'
 		for signable_list in absent:
-			for signable_clsname in getattr(Signable,signable_list):
+			for signable_clsname in getattr(Signable, signable_list):
 				desc = getattr(Signable, signable_clsname).desc
 				assert not f'No unsigned {desc}s' in res, f'‘No unsigned {desc}s’ should be absent in output'
 		return t
@@ -904,33 +904,33 @@ class CmdTestAutosignLive(CmdTestAutosignBTC):
 	no_insert_check = False
 
 	cmd_group = (
-		('start_daemons',        'starting daemons'),
-		('copy_tx_files',        'copying transaction files'),
-		('gen_key',              'generating key'),
-		('run_setup_mmgen',      'running ‘autosign setup’ (MMGen native mnemonic)'),
-		('sign_live',            'signing transactions'),
-		('create_bad_txfiles',   'creating bad transaction files'),
-		('sign_live_led',        'signing transactions (--led)'),
-		('remove_bad_txfiles',   'removing bad transaction files'),
-		('sign_live_stealth_led','signing transactions (--stealth-led)'),
-		('stop_daemons',         'stopping daemons'),
+		('start_daemons',         'starting daemons'),
+		('copy_tx_files',         'copying transaction files'),
+		('gen_key',               'generating key'),
+		('run_setup_mmgen',       'running ‘autosign setup’ (MMGen native mnemonic)'),
+		('sign_live',             'signing transactions'),
+		('create_bad_txfiles',    'creating bad transaction files'),
+		('sign_live_led',         'signing transactions (--led)'),
+		('remove_bad_txfiles',    'removing bad transaction files'),
+		('sign_live_stealth_led', 'signing transactions (--stealth-led)'),
+		('stop_daemons',          'stopping daemons'),
 	)
 
-	def __init__(self,trunner,cfgs,spawn):
+	def __init__(self, trunner, cfgs, spawn):
 
-		super().__init__(trunner,cfgs,spawn)
+		super().__init__(trunner, cfgs, spawn)
 
 		if trunner is None:
 			return
 
 		try:
-			LEDControl(enabled=True,simulate=self.simulate_led)
+			LEDControl(enabled=True, simulate=self.simulate_led)
 		except Exception as e:
 			msg(str(e))
-			die(2,'LEDControl initialization failed')
+			die(2, 'LEDControl initialization failed')
 
 	def run_setup_mmgen(self):
-		return self.run_setup(mn_type='mmgen',use_dfl_wallet=None)
+		return self.run_setup(mn_type='mmgen', use_dfl_wallet=None)
 
 	def sign_live(self):
 		return self.do_sign_live()
@@ -941,7 +941,7 @@ class CmdTestAutosignLive(CmdTestAutosignBTC):
 	def sign_live_stealth_led(self):
 		return self.do_sign_live(['--stealth-led'], 'You should see no LED activity now')
 
-	def do_sign_live(self,led_opts=None,led_msg=None):
+	def do_sign_live(self, led_opts=None, led_msg=None):
 
 		def prompt_remove():
 			omsg_r(orange('\nExtract removable device and then hit ENTER '))

+ 18 - 18
test/cmdtest_py_d/ct_base.py

@@ -20,17 +20,17 @@
 test.cmdtest_py_d.ct_base: Base class for the cmdtest.py test suite
 """
 
-import sys,os
+import sys, os
 
 from mmgen.util import msg
 from mmgen.color import gray
 
-from ..include.common import cfg,write_to_file,read_from_file
+from ..include.common import cfg, write_to_file, read_from_file
 from .common import get_file_with_ext
 
 class CmdTestBase:
 	'initializer class for the cmdtest.py test suite'
-	base_passthru_opts = ('data_dir','skip_cfg_file')
+	base_passthru_opts = ('data_dir', 'skip_cfg_file')
 	passthru_opts = ()
 	networks = ()
 	segwit_opts_ok = False
@@ -40,8 +40,8 @@ class CmdTestBase:
 	tmpdir_nums = []
 	test_name = None
 
-	def __init__(self,trunner,cfgs,spawn):
-		if hasattr(self,'name'): # init will be called multiple times for classes with multiple inheritance
+	def __init__(self, trunner, cfgs, spawn):
+		if hasattr(self, 'name'): # init will be called multiple times for classes with multiple inheritance
 			return
 		self.name = type(self).__name__
 		self.proto = cfg._proto
@@ -49,9 +49,9 @@ class CmdTestBase:
 		self.cfgs = cfgs
 		self.spawn = spawn
 		self.have_dfl_wallet = False
-		self.usr_rand_chars = (5,30)[bool(cfg.usr_random)]
+		self.usr_rand_chars = (5, 30)[bool(cfg.usr_random)]
 		self.usr_rand_arg = f'-r{self.usr_rand_chars}'
-		self.tn_ext = ('','.testnet')[self.proto.testnet]
+		self.tn_ext = ('', '.testnet')[self.proto.testnet]
 		self.coin = self.proto.coin.lower()
 		self.fork = 'btc' if self.coin == 'bch' and not cfg.cashaddr else self.coin
 		self.altcoin_pfx = '' if self.fork == 'btc' else f'-{self.proto.coin}'
@@ -66,19 +66,19 @@ class CmdTestBase:
 
 	@property
 	def tmpdir(self):
-		return os.path.join('test','tmp','{}{}'.format(self.tmpdir_num,'-α' if cfg.debug_utf8 else ''))
+		return os.path.join('test', 'tmp', '{}{}'.format(self.tmpdir_num, '-α' if cfg.debug_utf8 else ''))
 
-	def get_file_with_ext(self,ext,**kwargs):
-		return get_file_with_ext(self.tmpdir,ext,**kwargs)
+	def get_file_with_ext(self, ext, **kwargs):
+		return get_file_with_ext(self.tmpdir, ext, **kwargs)
 
-	def read_from_tmpfile(self,fn,binary=False):
-		return read_from_file(os.path.join(self.tmpdir,fn),binary=binary)
+	def read_from_tmpfile(self, fn, binary=False):
+		return read_from_file(os.path.join(self.tmpdir, fn), binary=binary)
 
-	def write_to_tmpfile(self,fn,data,binary=False):
-		return write_to_file(os.path.join(self.tmpdir,fn),data,binary=binary)
+	def write_to_tmpfile(self, fn, data, binary=False):
+		return write_to_file(os.path.join(self.tmpdir, fn), data, binary=binary)
 
-	def delete_tmpfile(self,fn):
-		fn = os.path.join(self.tmpdir,fn)
+	def delete_tmpfile(self, fn):
+		fn = os.path.join(self.tmpdir, fn)
 		try:
 			return os.unlink(fn)
 		except:
@@ -100,13 +100,13 @@ class CmdTestBase:
 	def skip_for_win(self, extra_msg=None):
 		return self.skip_for_platform('win32', extra_msg)
 
-	def spawn_chk(self,*args,**kwargs):
+	def spawn_chk(self, *args, **kwargs):
 		"""
 		Drop-in replacement for spawn() + t.read() for tests that spawn more than one process.
 		Ensures that test script execution stops when a spawned process fails.
 
 		"""
-		t = self.spawn(*args,**kwargs)
+		t = self.spawn(*args, **kwargs)
 		t.read()
 		t.ok()
 		t.skip_ok = True

+ 63 - 63
test/cmdtest_py_d/ct_cfgfile.py

@@ -10,12 +10,12 @@
 test.cmdtest_py_d.ct_cfgfile: CfgFile tests for the MMGen cmdtest.py test suite
 """
 
-import sys,os,time,shutil
+import sys, os, time, shutil
 
 from mmgen.color import yellow
-from mmgen.cfgfile import CfgFileSampleSys,CfgFileSampleUsr,cfg_file_sample
+from mmgen.cfgfile import CfgFileSampleSys, CfgFileSampleUsr, cfg_file_sample
 
-from ..include.common import cfg,read_from_file,write_to_file,imsg
+from ..include.common import cfg, read_from_file, write_to_file, imsg
 from .ct_base import CmdTestBase
 
 class CmdTestCfgFile(CmdTestBase):
@@ -26,25 +26,25 @@ class CmdTestCfgFile(CmdTestBase):
 	color = True
 
 	cmd_group = (
-		('sysfile',                  (40,'init with system cfg sample file in place', [])),
-		('no_metadata_sample',       (40,'init with unversioned cfg sample file', [])),
-		('altered_sample',           (40,'init with user-modified cfg sample file', [])),
-		('old_sample',               (40,'init with old v2 cfg sample file', [])),
-		('old_sample_bad_var',       (40,'init with old v2 cfg sample file and bad variable in mmgen.cfg', [])),
-		('autoset_opts',             (40,'setting autoset opts', [])),
-		('autoset_opts_cmdline',     (40,'setting autoset opts (override on cmdline)', [])),
-		('autoset_opts_bad',         (40,'setting autoset opts (bad value in cfg file)', [])),
-		('autoset_opts_bad_cmdline', (40,'setting autoset opts (bad param on cmdline)', [])),
-		('coin_specific_vars',       (40,'setting coin-specific vars', [])),
-		('chain_names',              (40,'setting chain names', [])),
-		('mnemonic_entry_modes',     (40,'setting mnemonic entry modes', [])),
+		('sysfile',                  (40, 'init with system cfg sample file in place', [])),
+		('no_metadata_sample',       (40, 'init with unversioned cfg sample file', [])),
+		('altered_sample',           (40, 'init with user-modified cfg sample file', [])),
+		('old_sample',               (40, 'init with old v2 cfg sample file', [])),
+		('old_sample_bad_var',       (40, 'init with old v2 cfg sample file and bad variable in mmgen.cfg', [])),
+		('autoset_opts',             (40, 'setting autoset opts', [])),
+		('autoset_opts_cmdline',     (40, 'setting autoset opts (override on cmdline)', [])),
+		('autoset_opts_bad',         (40, 'setting autoset opts (bad value in cfg file)', [])),
+		('autoset_opts_bad_cmdline', (40, 'setting autoset opts (bad param on cmdline)', [])),
+		('coin_specific_vars',       (40, 'setting coin-specific vars', [])),
+		('chain_names',              (40, 'setting chain names', [])),
+		('mnemonic_entry_modes',     (40, 'setting mnemonic entry modes', [])),
 	)
 
-	def __init__(self,trunner,cfgs,spawn):
-		CmdTestBase.__init__(self,trunner,cfgs,spawn)
+	def __init__(self, trunner, cfgs, spawn):
+		CmdTestBase.__init__(self, trunner, cfgs, spawn)
 		self.spawn_env['MMGEN_TEST_SUITE_CFGTEST'] = '1'
 
-	def spawn_test(self,args=[],extra_desc='',pexpect_spawn=None, exit_val=None):
+	def spawn_test(self, args=[], extra_desc='', pexpect_spawn=None, exit_val=None):
 		return self.spawn(
 			'test/misc/cfg.py',
 			[f'--data-dir={self.path("data_dir")}'] + args,
@@ -53,19 +53,19 @@ class CmdTestCfgFile(CmdTestBase):
 			pexpect_spawn = pexpect_spawn,
 			exit_val      = exit_val)
 
-	def path(self,id_str):
+	def path(self, id_str):
 		return {
 			'ref':         'test/ref/mmgen.cfg',
 			'data_dir':    '{}/data_dir'.format(self.tmpdir),
-			'shared_data': '{}/data_dir/{}'.format(self.tmpdir,CfgFileSampleSys.test_fn_subdir),
+			'shared_data': '{}/data_dir/{}'.format(self.tmpdir, CfgFileSampleSys.test_fn_subdir),
 			'usr':         '{}/data_dir/mmgen.cfg'.format(self.tmpdir),
-			'sys':         '{}/data_dir/{}/mmgen.cfg'.format(self.tmpdir,CfgFileSampleSys.test_fn_subdir),
+			'sys':         '{}/data_dir/{}/mmgen.cfg'.format(self.tmpdir, CfgFileSampleSys.test_fn_subdir),
 			'sample':      '{}/data_dir/mmgen.cfg.sample'.format(os.path.abspath(self.tmpdir)),
 		}[id_str]
 
 	def copy_sys_sample(self):
-		os.makedirs(self.path('shared_data'),exist_ok=True)
-		shutil.copy2(self.path('ref'),self.path('sys'))
+		os.makedirs(self.path('shared_data'), exist_ok=True)
+		shutil.copy2(self.path('ref'), self.path('sys'))
 
 	def sysfile(self):
 		self.copy_sys_sample()
@@ -74,7 +74,7 @@ class CmdTestCfgFile(CmdTestBase):
 		u = read_from_file(self.path('usr'))
 		S = read_from_file(self.path('sys'))
 		assert u[-1] == '\n', u
-		assert u.replace('\r\n','\n') == S, 'u != S'
+		assert u.replace('\r\n', '\n') == S, 'u != S'
 		self.check_replaced_sample()
 		return t
 
@@ -84,8 +84,8 @@ class CmdTestCfgFile(CmdTestBase):
 		assert s[-1] == '\n', s
 		assert S.splitlines() == s.splitlines()[:-1], 'sys != sample[:-1]'
 
-	def bad_sample(self,s,e):
-		write_to_file(self.path('sample'),s)
+	def bad_sample(self, s, e):
+		write_to_file(self.path('sample'), s)
 		t = self.spawn_test()
 		t.expect(e)
 		t.read()
@@ -96,44 +96,44 @@ class CmdTestCfgFile(CmdTestBase):
 		self.copy_sys_sample()
 		s = read_from_file(self.path('sys'))
 		e = CfgFileSampleUsr.out_of_date_fs.format(self.path('sample'))
-		return self.bad_sample(s,e)
+		return self.bad_sample(s, e)
 
 	def altered_sample(self):
 		s = '\n'.join(read_from_file(self.path('sample')).splitlines()[1:]) + '\n'
 		e = CfgFileSampleUsr.altered_by_user_fs.format(self.path('sample'))
-		return self.bad_sample(s,e)
+		return self.bad_sample(s, e)
 
-	def old_sample_common(self,old_set=False,args=[],pexpect_spawn=False):
+	def old_sample_common(self, old_set=False, args=[], pexpect_spawn=False):
 		s = read_from_file(self.path('sys'))
-		d = s.replace('monero_','zcash_').splitlines()
-		a1 = ['','# Uncomment to make foo true:','# foo true']
-		a2 = ['','# Uncomment to make bar false:','# bar false']
+		d = s.replace('monero_', 'zcash_').splitlines()
+		a1 = ['', '# Uncomment to make foo true:', '# foo true']
+		a2 = ['', '# Uncomment to make bar false:', '# bar false']
 		d = d + a1 + a2
 		chk = cfg_file_sample.cls_make_metadata(d)
-		write_to_file(self.path('sample'),'\n'.join(d+chk) + '\n')
+		write_to_file(self.path('sample'), '\n'.join(d+chk) + '\n')
 
 		t = self.spawn_test(args=args, pexpect_spawn=pexpect_spawn, exit_val=1 if old_set else None)
 
 		t.expect('options have changed')
-		for s in ('have been added','monero_','have been removed','zcash_','foo','bar'):
+		for s in ('have been added', 'monero_', 'have been removed', 'zcash_', 'foo', 'bar'):
 			t.expect(s)
 
 		if old_set:
-			for s in ('must be deleted','bar','foo'):
+			for s in ('must be deleted', 'bar', 'foo'):
 				t.expect(s)
 
 		cp = CfgFileSampleUsr.details_confirm_prompt + ' (y/N): '
 
-		t.expect(cp,'y')
+		t.expect(cp, 'y')
 
-		for s in ('CHANGES','Removed','# zcash_','# foo','# bar','Added','# monero_'):
+		for s in ('CHANGES', 'Removed', '# zcash_', '# foo', '# bar', 'Added', '# monero_'):
 			t.expect(s)
 
 		if t.pexpect_spawn: # view and exit pager
 			time.sleep(1 if cfg.exact_output else t.send_delay)
 			t.send('q')
 
-		t.expect(cp,'n')
+		t.expect(cp, 'n')
 
 		if old_set:
 			t.expect('unrecognized option')
@@ -148,13 +148,13 @@ class CmdTestCfgFile(CmdTestBase):
 		return t
 
 	def old_sample(self):
-		d = ['testnet true','rpc_password passwOrd']
-		write_to_file(self.path('usr'),'\n'.join(d) + '\n')
+		d = ['testnet true', 'rpc_password passwOrd']
+		write_to_file(self.path('usr'), '\n'.join(d) + '\n')
 		return self.old_sample_common(args=['parse_test'])
 
 	def old_sample_bad_var(self):
-		d = ['foo true','bar false']
-		write_to_file(self.path('usr'),'\n'.join(d) + '\n')
+		d = ['foo true', 'bar false']
+		write_to_file(self.path('usr'), '\n'.join(d) + '\n')
 		t = self.old_sample_common(
 			old_set       = True,
 			pexpect_spawn = not sys.platform == 'win32')
@@ -162,7 +162,7 @@ class CmdTestCfgFile(CmdTestBase):
 		return t
 
 	def _autoset_opts(self, args=[], text='rpc_backend aiohttp\n', exit_val=None):
-		write_to_file( self.path('usr'), text )
+		write_to_file(self.path('usr'), text)
 		imsg(yellow(f'Wrote cfg file:\n  {text}'))
 		return self.spawn_test(args=args, exit_val=exit_val)
 
@@ -170,7 +170,7 @@ class CmdTestCfgFile(CmdTestBase):
 		return self._autoset_opts(args=['autoset_opts'])
 
 	def autoset_opts_cmdline(self):
-		return self._autoset_opts(args=['--rpc-backend=curl','autoset_opts_cmdline'])
+		return self._autoset_opts(args=['--rpc-backend=curl', 'autoset_opts_cmdline'])
 
 	def _autoset_opts_bad(self, expect, kwargs):
 		t = self._autoset_opts(exit_val=1, **kwargs)
@@ -193,15 +193,15 @@ class CmdTestCfgFile(CmdTestBase):
 			'btc_ignore_daemon_version true',
 			'eth_ignore_daemon_version true'
 		]
-		write_to_file(self.path('usr'),'\n'.join(d) + '\n')
+		write_to_file(self.path('usr'), '\n'.join(d) + '\n')
 		imsg(yellow('Wrote cfg file:\n  {}'.format('\n  '.join(d))))
 
-		for coin,res1_chk,res2_chk,res2_chk_eq in (
-			('BTC','True', '1.2345',True),
-			('LTC','False','1.2345',False),
-			('BCH','False','1.2345',False),
-			('ETH','True', '5.4321',True),
-			('ETC','False','5.4321',False)
+		for coin, res1_chk, res2_chk, res2_chk_eq in (
+			('BTC', 'True',  '1.2345', True),
+			('LTC', 'False', '1.2345', False),
+			('BCH', 'False', '1.2345', False),
+			('ETH', 'True',  '5.4321', True),
+			('ETC', 'False', '5.4321', False)
 		):
 			if cfg.no_altcoin and coin != 'BTC':
 				continue
@@ -212,7 +212,7 @@ class CmdTestCfgFile(CmdTestBase):
 					'ignore_daemon_version',
 					'max_tx_fee'
 				],
-				extra_desc=f'({coin})' )
+				extra_desc=f'({coin})')
 			res1 = t.expect_getend('ignore_daemon_version: ')
 			res2 = t.expect_getend('max_tx_fee: ')
 			assert res1 == res1_chk, f'{res1} != {res1_chk}'
@@ -235,7 +235,7 @@ class CmdTestCfgFile(CmdTestBase):
 			return t
 
 		txt = 'mnemonic_entry_modes mmgen:full bip39:short'
-		write_to_file(self.path('usr'),txt+'\n')
+		write_to_file(self.path('usr'), txt+'\n')
 		imsg(yellow(f'Wrote cfg file: {txt!r}'))
 		t = run("{'mmgen': 'full', 'bip39': 'short'}")
 		# check that set_dfl_entry_mode() set the mode correctly:
@@ -248,11 +248,11 @@ class CmdTestCfgFile(CmdTestBase):
 		if cfg.no_altcoin:
 			return 'skip'
 
-		def run(chk,testnet):
-			for coin,chain_chk in (('ETH',chk),('ETC',None)):
+		def run(chk, testnet):
+			for coin, chain_chk in (('ETH', chk), ('ETC', None)):
 				t = self.spawn_test(
-					args = [f'--coin={coin}',f'--testnet={(0,1)[testnet]}','coin_specific_vars','chain_names'],
-					extra_desc = f'({coin} testnet={testnet!r:5} chain_names={chain_chk})' )
+					args = [f'--coin={coin}', f'--testnet={(0, 1)[testnet]}', 'coin_specific_vars', 'chain_names'],
+					extra_desc = f'({coin} testnet={testnet!r:5} chain_names={chain_chk})')
 				chain = t.expect_getend('chain_names: ')
 				if chain_chk:
 					assert chain == chain_chk, f'{chain} != {chain_chk}'
@@ -263,16 +263,16 @@ class CmdTestCfgFile(CmdTestBase):
 			return t
 
 		txt = 'eth_mainnet_chain_names istanbul constantinople'
-		write_to_file(self.path('usr'),txt+'\n')
+		write_to_file(self.path('usr'), txt+'\n')
 		imsg(yellow(f'Wrote cfg file: {txt!r}'))
-		t = run("['istanbul', 'constantinople']",False)
-		t = run(None,True)
+		t = run("['istanbul', 'constantinople']", False)
+		t = run(None, True)
 
 		txt = 'eth_testnet_chain_names rinkeby'
-		write_to_file(self.path('usr'),txt+'\n')
+		write_to_file(self.path('usr'), txt+'\n')
 		imsg(yellow(f'Wrote cfg file: {txt!r}'))
-		t = run(None,False)
-		t = run("['rinkeby']",True)
+		t = run(None, False)
+		t = run("['rinkeby']", True)
 
 		t.skip_ok = True
 		return t

+ 48 - 48
test/cmdtest_py_d/ct_chainsplit.py

@@ -23,51 +23,51 @@ This module is unmaintained and currently non-functional
 
 from mmgen.util import die
 
-from .common import get_file_with_ext,rt_pw
+from .common import get_file_with_ext, rt_pw
 from .ct_regtest import CmdTestRegtest
 
 class CmdTestChainsplit(CmdTestRegtest):
 	'forking scenario tests for the cmdtest.py test suite'
 	cmd_group = (
-		('split_setup',        'regtest forking scenario setup'),
-		('walletgen_bob',      "generating Bob's wallet"),
-		('addrgen_bob',        "generating Bob's addresses"),
-		('addrimport_bob',     "importing Bob's addresses"),
-		('fund_bob',           "funding Bob's wallet"),
-		('split_fork',         'regtest split fork'),
-		('split_start_btc',    'start regtest daemon (BTC)'),
-		('split_start_b2x',    'start regtest daemon (B2X)'),
-		('split_gen_btc',      'mining a block (BTC)'),
-		('split_gen_b2x',      'mining 100 blocks (B2X)'),
-		('split_do_split',     'creating coin splitting transactions'),
-		('split_sign_b2x',     'signing B2X split transaction'),
-		('split_sign_btc',     'signing BTC split transaction'),
-		('split_send_b2x',     'sending B2X split transaction'),
-		('split_send_btc',     'sending BTC split transaction'),
-		('split_gen_btc',      'mining a block (BTC)'),
-		('split_gen_b2x2',     'mining a block (B2X)'),
-		('split_txdo_timelock_bad_btc', 'sending transaction with bad locktime (BTC)'),
-		('split_txdo_timelock_good_btc','sending transaction with good locktime (BTC)'),
-		('split_txdo_timelock_bad_b2x', 'sending transaction with bad locktime (B2X)'),
-		('split_txdo_timelock_good_b2x','sending transaction with good locktime (B2X)'),
+		('split_setup',                  'regtest forking scenario setup'),
+		('walletgen_bob',                'generating Bob’s wallet'),
+		('addrgen_bob',                  'generating Bob’s addresses'),
+		('addrimport_bob',               'importing Bob’s addresses'),
+		('fund_bob',                     'funding Bob’s wallet'),
+		('split_fork',                   'regtest split fork'),
+		('split_start_btc',              'start regtest daemon (BTC)'),
+		('split_start_b2x',              'start regtest daemon (B2X)'),
+		('split_gen_btc',                'mining a block (BTC)'),
+		('split_gen_b2x',                'mining 100 blocks (B2X)'),
+		('split_do_split',               'creating coin splitting transactions'),
+		('split_sign_b2x',               'signing B2X split transaction'),
+		('split_sign_btc',               'signing BTC split transaction'),
+		('split_send_b2x',               'sending B2X split transaction'),
+		('split_send_btc',               'sending BTC split transaction'),
+		('split_gen_btc',                'mining a block (BTC)'),
+		('split_gen_b2x2',               'mining a block (B2X)'),
+		('split_txdo_timelock_bad_btc',  'sending transaction with bad locktime (BTC)'),
+		('split_txdo_timelock_good_btc', 'sending transaction with good locktime (BTC)'),
+		('split_txdo_timelock_bad_b2x',  'sending transaction with bad locktime (B2X)'),
+		('split_txdo_timelock_good_b2x', 'sending transaction with good locktime (B2X)'),
 	)
 
 	def split_setup(self):
 		if self.proto.coin != 'BTC':
-			die(1,'Test valid only for coin BTC')
+			die(1, 'Test valid only for coin BTC')
 		self.coin = 'BTC'
 		return self.setup()
 
 	def split_fork(self):
 		self.coin = 'B2X'
-		t = self.spawn('mmgen-regtest',['fork','btc'])
+		t = self.spawn('mmgen-regtest', ['fork', 'btc'])
 		t.expect('Creating fork from coin')
 		t.expect('successfully created')
 		t.ok()
 
-	def split_start(self,coin):
+	def split_start(self, coin):
 		self.coin = coin
-		t = self.spawn('mmgen-regtest',['bob'])
+		t = self.spawn('mmgen-regtest', ['bob'])
 		t.expect('Starting')
 		t.expect('done')
 		t.ok()
@@ -82,7 +82,7 @@ class CmdTestChainsplit(CmdTestRegtest):
 		self.regtest_generate(coin='BTC')
 
 	def split_gen_b2x(self):
-		self.regtest_generate(coin='B2X',num_blocks=100)
+		self.regtest_generate(coin='B2X', num_blocks=100)
 
 	def split_gen_b2x2(self):
 		self.regtest_generate(coin='B2X')
@@ -90,17 +90,17 @@ class CmdTestChainsplit(CmdTestRegtest):
 	def split_do_split(self):
 		self.coin = 'B2X'
 		sid = self.regtest_user_sid('bob')
-		t = self.spawn('mmgen-split',[
+		t = self.spawn('mmgen-split', [
 			'--bob',
 			'--outdir='+self.tmpdir,
 			'--tx-fees=0.0001,0.0003',
-			sid+':S:1',sid+':S:2'])
-		t.expect(r'\[q\]uit menu, .*?:.','q', regex=True)
-		t.expect('outputs to spend: ','1\n')
+			sid+':S:1', sid+':S:2'])
+		t.expect(r'\[q\]uit menu, .*?:.', 'q', regex=True)
+		t.expect('outputs to spend: ', '1\n')
 
 		for _ in ('timelocked', 'split'):
 			for _ in ('fee', 'change'):
-				t.expect('OK? (Y/n): ','y')
+				t.expect('OK? (Y/n): ', 'y')
 			t.do_comment(False)
 			t.view_tx('t')
 
@@ -108,30 +108,30 @@ class CmdTestChainsplit(CmdTestRegtest):
 		t.written_to_file('Short chain transaction')
 		t.ok()
 
-	def split_sign(self,coin,ext):
-		wf = get_file_with_ext(self.regtest_user_dir('bob',coin=coin.lower()),'mmdat')
-		txfile = self.get_file_with_ext(ext,no_dot=True)
+	def split_sign(self, coin, ext):
+		wf = get_file_with_ext(self.regtest_user_dir('bob', coin=coin.lower()), 'mmdat')
+		txfile = self.get_file_with_ext(ext, no_dot=True)
 		self.coin = coin
-		self.txsign(txfile,wf,extra_opts=['--bob'])
+		self.txsign(txfile, wf, extra_opts=['--bob'])
 
 	def split_sign_b2x(self):
-		return self.regtest_sign(coin='B2X',ext='533].rawtx')
+		return self.regtest_sign(coin='B2X', ext='533].rawtx')
 
 	def split_sign_btc(self):
-		return self.regtest_sign(coin='BTC',ext='9997].rawtx')
+		return self.regtest_sign(coin='BTC', ext='9997].rawtx')
 
-	def split_send(self,coin,ext):
+	def split_send(self, coin, ext):
 		self.coin = coin
-		txfile = self.get_file_with_ext(ext,no_dot=True)
-		self.txsend(txfile,bogus_send=False,extra_opts=['--bob'])
+		txfile = self.get_file_with_ext(ext, no_dot=True)
+		self.txsend(txfile, bogus_send=False, extra_opts=['--bob'])
 
 	def split_send_b2x(self):
-		return self.regtest_send(coin='B2X',ext='533].sigtx')
+		return self.regtest_send(coin='B2X', ext='533].sigtx')
 
 	def split_send_btc(self):
-		return self.regtest_send(coin='BTC',ext='9997].sigtx')
+		return self.regtest_send(coin='BTC', ext='9997].sigtx')
 
-	def split_txdo_timelock(self,coin,locktime,bad_locktime):
+	def split_txdo_timelock(self, coin, locktime, bad_locktime):
 		self.coin = coin
 		sid = self.regtest_user_sid('bob')
 		self.regtest_user_txdo(
@@ -144,10 +144,10 @@ class CmdTestChainsplit(CmdTestRegtest):
 			bad_locktime = bad_locktime)
 
 	def split_txdo_timelock_bad_btc(self):
-		self.regtest_txdo_timelock('BTC',locktime=8888,bad_locktime=True)
+		self.regtest_txdo_timelock('BTC', locktime=8888, bad_locktime=True)
 	def split_txdo_timelock_good_btc(self):
-		self.regtest_txdo_timelock('BTC',locktime=1321009871,bad_locktime=False)
+		self.regtest_txdo_timelock('BTC', locktime=1321009871, bad_locktime=False)
 	def split_txdo_timelock_bad_b2x(self):
-		self.regtest_txdo_timelock('B2X',locktime=8888,bad_locktime=True)
+		self.regtest_txdo_timelock('B2X', locktime=8888, bad_locktime=True)
 	def split_txdo_timelock_good_b2x(self):
-		self.regtest_txdo_timelock('B2X',locktime=1321009871,bad_locktime=False)
+		self.regtest_txdo_timelock('B2X', locktime=1321009871, bad_locktime=False)

File diff suppressed because it is too large
+ 262 - 262
test/cmdtest_py_d/ct_ethdev.py


+ 32 - 32
test/cmdtest_py_d/ct_help.py

@@ -23,19 +23,19 @@ from .ct_base import CmdTestBase
 class CmdTestHelp(CmdTestBase):
 	'help, info and usage screens'
 	networks = ('btc', 'ltc', 'bch', 'eth', 'xmr', 'doge')
-	passthru_opts = ('daemon_data_dir','rpc_port','coin','testnet')
+	passthru_opts = ('daemon_data_dir', 'rpc_port', 'coin', 'testnet')
 	cmd_group = (
-		('usage1',                (1,'usage message (via --usage)',[])),
-		('usage2',                (1,'usage message (via bad invocation)',[])),
-		('version',               (1,'version message',[])),
-		('license',               (1,'license message',[])),
-		('helpscreens',           (1,'help screens',             [])),
-		('longhelpscreens',       (1,'help screens (--longhelp)',[])),
-		('show_hash_presets',     (1,'info screen (--show-hash-presets)',[])),
-		('tool_help',             (1,"'mmgen-tool' usage screen",[])),
-		('tool_cmd_usage',        (1,"'mmgen-tool' usage screen",[])),
-		('test_help',             (1,"'cmdtest.py' help screens",[])),
-		('tooltest_help',         (1,"'tooltest.py' help screens",[])),
+		('usage1',            (1, 'usage message (via --usage)', [])),
+		('usage2',            (1, 'usage message (via bad invocation)', [])),
+		('version',           (1, 'version message', [])),
+		('license',           (1, 'license message', [])),
+		('helpscreens',       (1, 'help screens',             [])),
+		('longhelpscreens',   (1, 'help screens (--longhelp)', [])),
+		('show_hash_presets', (1, 'info screen (--show-hash-presets)', [])),
+		('tool_help',         (1, '‘mmgen-tool’ usage screen', [])),
+		('tool_cmd_usage',    (1, '‘mmgen-tool’ usage screen', [])),
+		('test_help',         (1, '‘cmdtest.py’ help screens', [])),
+		('tooltest_help',     (1, '‘tooltest.py’ help screens', [])),
 	)
 
 	def usage1(self):
@@ -67,13 +67,13 @@ class CmdTestHelp(CmdTestBase):
 		if cfg.pexpect_spawn:
 			t.send('q')
 		t.expect('to continue: ', 'c')
-		t.expect('data: ','beadcafe'*4 + '\n')
+		t.expect('data: ', 'beadcafe'*4 + '\n')
 		t.expect('to confirm: ', 'YES\n')
 		return t
 
-	def spawn_chk_expect(self,*args,**kwargs):
+	def spawn_chk_expect(self, *args, **kwargs):
 		expect = kwargs.pop('expect')
-		t = self.spawn(*args,**kwargs)
+		t = self.spawn(*args, **kwargs)
 		t.expect(expect)
 		if t.pexpect_spawn:
 			time.sleep(0.4)
@@ -106,7 +106,7 @@ class CmdTestHelp(CmdTestBase):
 				[arg],
 				extra_desc       = f'(mmgen-{cmdname})',
 				no_passthru_opts = not gc.cmd_caps_data[cmdname].proto)
-			t.expect(expect,regex=True)
+			t.expect(expect, regex=True)
 			if pager and t.pexpect_spawn:
 				time.sleep(0.2)
 				t.send('q')
@@ -117,17 +117,17 @@ class CmdTestHelp(CmdTestBase):
 		return t
 
 	def longhelpscreens(self):
-		return self.helpscreens(arg='--longhelp',expect='USAGE:.*GLOBAL OPTIONS:')
+		return self.helpscreens(arg='--longhelp', expect='USAGE:.*GLOBAL OPTIONS:')
 
 	def show_hash_presets(self):
 		return self.helpscreens(
 			arg = '--show-hash-presets',
 			scripts = (
-					'walletgen','walletconv','walletchk','passchg','subwalletgen',
-					'addrgen','keygen','passgen',
-					'txsign','txdo','txbump'),
+				'walletgen', 'walletconv', 'walletchk', 'passchg', 'subwalletgen',
+				'addrgen', 'keygen', 'passgen',
+				'txsign', 'txdo', 'txbump'),
 			expect = 'Available parameters.*Preset',
-			pager  = False )
+			pager  = False)
 
 	def tool_help(self):
 
@@ -143,7 +143,7 @@ class CmdTestHelp(CmdTestBase):
 				'mmgen-tool',
 				[arg],
 				extra_desc = f'(mmgen-tool {arg})',
-				expect = 'GENERAL USAGE' )
+				expect = 'GENERAL USAGE')
 		return t
 
 	def tool_cmd_usage(self):
@@ -156,32 +156,32 @@ class CmdTestHelp(CmdTestBase):
 
 		for cmdlist in mods.values():
 			for cmd in cmdlist:
-				t = self.spawn_chk( 'mmgen-tool', ['help',cmd], extra_desc=f'({cmd})' )
+				t = self.spawn_chk('mmgen-tool', ['help', cmd], extra_desc=f'({cmd})')
 		return t
 
 	def test_help(self):
-		for arg,expect in (
-			('--help','USAGE'),
-			('--list-cmds','AVAILABLE COMMANDS'),
-			('--list-cmd-groups','AVAILABLE COMMAND GROUPS')
+		for arg, expect in (
+			('--help', 'USAGE'),
+			('--list-cmds', 'AVAILABLE COMMANDS'),
+			('--list-cmd-groups', 'AVAILABLE COMMAND GROUPS')
 		):
 			t = self.spawn_chk_expect(
 				'cmdtest.py',
 				[arg],
 				cmd_dir = 'test',
 				extra_desc = f'(cmdtest.py {arg})',
-				expect = expect )
+				expect = expect)
 		return t
 
 	def tooltest_help(self):
-		for arg,expect in (
-			('--list-cmds','Available commands'),
-			('--testing-status','Testing status')
+		for arg, expect in (
+			('--list-cmds', 'Available commands'),
+			('--testing-status', 'Testing status')
 		):
 			t = self.spawn_chk_expect(
 				'tooltest.py',
 				[arg],
 				cmd_dir = 'test',
 				extra_desc = f'(tooltest.py {arg})',
-				expect = expect )
+				expect = expect)
 		return t

+ 105 - 105
test/cmdtest_py_d/ct_input.py

@@ -10,10 +10,10 @@
 test.cmdtest_py_d.ct_input: user input tests for the MMGen cmdtest.py test suite
 """
 
-import sys,os
+import sys, os
 
 from mmgen.cfg import gc
-from mmgen.util import fmt,capfirst,remove_whitespace
+from mmgen.util import fmt, capfirst, remove_whitespace
 from mmgen.wallet import get_wallet_cls
 
 from ..include.common import (
@@ -25,9 +25,9 @@ from ..include.common import (
 	read_from_file,
 	strip_ansi_escapes
 )
-from .common import Ctrl_U,ref_dir
+from .common import Ctrl_U, ref_dir
 from .ct_base import CmdTestBase
-from .input import stealth_mnemonic_entry,user_dieroll_entry
+from .input import stealth_mnemonic_entry, user_dieroll_entry
 
 hold_protect_delay = 2 if sys.platform == 'darwin' else None
 
@@ -88,17 +88,17 @@ class CmdTestInput(CmdTestBase):
 	),
 	'mnemonic': (
 		'mnemonic entry',
-		('mnemonic_entry_mmgen',          'stealth mnemonic entry (mmgen)'),
-		('mnemonic_entry_mmgen_minimal',  'stealth mnemonic entry (mmgen - minimal entry mode)'),
-		('mnemonic_entry_bip39',          'stealth mnemonic entry (bip39)'),
-		('mnemonic_entry_bip39_short',    'stealth mnemonic entry (bip39 - short entry mode)'),
-		('mn2hex_interactive_mmgen',      'mn2hex_interactive (mmgen)'),
-		('mn2hex_interactive_mmgen_fixed','mn2hex_interactive (mmgen - fixed (10-letter) entry mode)'),
-		('mn2hex_interactive_bip39',      'mn2hex_interactive (bip39)'),
-		('mn2hex_interactive_bip39_short','mn2hex_interactive (bip39 - short entry mode (+pad entry))'),
-		('mn2hex_interactive_bip39_fixed','mn2hex_interactive (bip39 - fixed (4-letter) entry mode)'),
-		('mn2hex_interactive_xmr',        'mn2hex_interactive (xmrseed)'),
-		('mn2hex_interactive_xmr_short',  'mn2hex_interactive (xmrseed - short entry mode)'),
+		('mnemonic_entry_mmgen',           'stealth mnemonic entry (mmgen)'),
+		('mnemonic_entry_mmgen_minimal',   'stealth mnemonic entry (mmgen - minimal entry mode)'),
+		('mnemonic_entry_bip39',           'stealth mnemonic entry (bip39)'),
+		('mnemonic_entry_bip39_short',     'stealth mnemonic entry (bip39 - short entry mode)'),
+		('mn2hex_interactive_mmgen',       'mn2hex_interactive (mmgen)'),
+		('mn2hex_interactive_mmgen_fixed', 'mn2hex_interactive (mmgen - fixed (10-letter) entry mode)'),
+		('mn2hex_interactive_bip39',       'mn2hex_interactive (bip39)'),
+		('mn2hex_interactive_bip39_short', 'mn2hex_interactive (bip39 - short entry mode (+pad entry))'),
+		('mn2hex_interactive_bip39_fixed', 'mn2hex_interactive (bip39 - fixed (4-letter) entry mode)'),
+		('mn2hex_interactive_xmr',         'mn2hex_interactive (xmrseed)'),
+		('mn2hex_interactive_xmr_short',   'mn2hex_interactive (xmrseed - short entry mode)'),
 	),
 	'dieroll': (
 		'dieroll entry',
@@ -108,79 +108,79 @@ class CmdTestInput(CmdTestBase):
 	}
 
 	def get_seed_from_stdin(self):
-		self.spawn('',msg_only=True)
-		from subprocess import run,PIPE
-		cmd = ['python3','cmds/mmgen-walletconv','--in-fmt=words','--out-fmt=words','--outdir=test/trash']
+		self.spawn('', msg_only=True)
+		from subprocess import run, PIPE
+		cmd = ['python3', 'cmds/mmgen-walletconv', '--in-fmt=words', '--out-fmt=words', '--outdir=test/trash']
 		mn = sample_mn['mmgen']['mn']
 		run_env = dict(os.environ)
 		run_env['MMGEN_TEST_SUITE'] = ''
 
 		# the test can fail the first time if cfg file has changed, so run it twice if necessary:
 		for _ in range(2):
-			cp = run( cmd, input=mn.encode(), stdout=PIPE, stderr=PIPE, env=run_env )
+			cp = run(cmd, input=mn.encode(), stdout=PIPE, stderr=PIPE, env=run_env)
 			if b'written to file' in cp.stderr:
 				break
 
 		from mmgen.color import set_vt100
 		set_vt100()
 		imsg(cp.stderr.decode().strip())
-		res = get_data_from_file(cfg,'test/trash/A773B05C[128].mmwords',silent=True).strip()
+		res = get_data_from_file(cfg, 'test/trash/A773B05C[128].mmwords', silent=True).strip()
 		assert res == mn, f'{res} != {mn}'
 		return 'ok' if b'written to file' in cp.stderr else 'error'
 
 	def get_passphrase_ui(self):
-		t = self.spawn('test/misc/get_passphrase.py',['--usr-randchars=0','seed'],cmd_dir='.')
+		t = self.spawn('test/misc/get_passphrase.py', ['--usr-randchars=0', 'seed'], cmd_dir='.')
 
-		# 1 - new wallet, default hp,label;empty pw
-		t.expect('accept the default.*: ','\n',regex=True)
+		# 1 - new wallet, default hp, label;empty pw
+		t.expect('accept the default.*: ', '\n', regex=True)
 
 		# bad repeat
-		t.expect('new MMGen wallet: ','pass1\n')
-		t.expect('peat passphrase: ','pass2\n')
+		t.expect('new MMGen wallet: ', 'pass1\n')
+		t.expect('peat passphrase: ', 'pass2\n')
 
 		# good repeat
-		t.expect('new MMGen wallet: ','\n')
-		t.expect('peat passphrase: ','\n')
+		t.expect('new MMGen wallet: ', '\n')
+		t.expect('peat passphrase: ', '\n')
 		t.expect('mpty pass')
 
-		t.expect('no label: ','\n')
+		t.expect('no label: ', '\n')
 
 		t.expect('[][3][No Label]')
 
-		# 2 - new wallet, user-selected hp,pw,label
+		# 2 - new wallet, user-selected hp, pw, label
 		t.expect('accept the default.*: ', '1\n', regex=True)
 
-		t.expect('new MMGen wallet: ','pass1\n')
-		t.expect('peat passphrase: ','pass1\n')
+		t.expect('new MMGen wallet: ', 'pass1\n')
+		t.expect('peat passphrase: ', 'pass1\n')
 
-		t.expect('no label: ','lbl1\n')
+		t.expect('no label: ', 'lbl1\n')
 
 		t.expect('[pass1][1][lbl1]')
 
 		# 3 - passchg, nothing changes
 		t.expect('new hash preset')
-		t.expect('reuse the old value.*: ','\n',regex=True)
+		t.expect('reuse the old value.*: ', '\n', regex=True)
 		t.expect('unchanged')
 
-		t.expect('new passphrase.*: ','pass1\n',regex=True)
-		t.expect('peat new passphrase: ','pass1\n')
+		t.expect('new passphrase.*: ', 'pass1\n', regex=True)
+		t.expect('peat new passphrase: ', 'pass1\n')
 		t.expect('unchanged')
 
-		t.expect('reuse the label .*: ','\n',regex=True)
+		t.expect('reuse the label .*: ', '\n', regex=True)
 		t.expect('unchanged')
 
 		t.expect('[pass1][1][lbl1]')
 
 		# 4 - passchg, everything changes
 		t.expect('new hash preset')
-		t.expect('reuse the old value.*: ','2\n',regex=True)
+		t.expect('reuse the old value.*: ', '2\n', regex=True)
 		t.expect(' changed to')
 
-		t.expect('new passphrase.*: ','pass2\n',regex=True)
-		t.expect('peat new passphrase: ','pass2\n')
+		t.expect('new passphrase.*: ', 'pass2\n', regex=True)
+		t.expect('peat new passphrase: ', 'pass2\n')
 		t.expect(' changed')
 
-		t.expect('reuse the label .*: ','lbl2\n',regex=True)
+		t.expect('reuse the label .*: ', 'lbl2\n', regex=True)
 		t.expect(' changed to')
 		t.expect('[pass2][2][lbl2]')
 
@@ -188,32 +188,32 @@ class CmdTestInput(CmdTestBase):
 		t.expect('from file')
 
 		# bad passphrase
-		t.expect('passphrase for MMGen wallet: ','bad\n')
+		t.expect('passphrase for MMGen wallet: ', 'bad\n')
 		t.expect('Trying again')
 
 		# good passphrase
-		t.expect('passphrase for MMGen wallet: ','reference password\n')
+		t.expect('passphrase for MMGen wallet: ', 'reference password\n')
 		t.expect('[reference password][1][No Label]')
 
 		return t
 
 	def get_passphrase_cmdline(self):
-		with open('test/trash/pwfile','w') as fp:
+		with open('test/trash/pwfile', 'w') as fp:
 			fp.write('reference password\n')
 		t = self.spawn('test/misc/get_passphrase.py', [
 			'--usr-randchars=0',
 			'--label=MyLabel',
 			'--passwd-file=test/trash/pwfile',
 			'--hash-preset=1',
-			'seed' ],
-			cmd_dir = '.' )
+			'seed'],
+			cmd_dir = '.')
 		for _ in range(4):
 			t.expect('[reference password][1][MyLabel]')
 
 		return t
 
 	def get_passphrase_crypto(self):
-		t = self.spawn('test/misc/get_passphrase.py',['--usr-randchars=0','crypto'],cmd_dir='.')
+		t = self.spawn('test/misc/get_passphrase.py', ['--usr-randchars=0', 'crypto'], cmd_dir='.')
 
 		# new passwd
 		t.expect('passphrase for .*: ', 'x\n', regex=True)
@@ -242,20 +242,20 @@ class CmdTestInput(CmdTestBase):
 
 	def _input_func(self, func_name, arg_dfls, func_args, text, expect, term, delay=None):
 		if term and sys.platform == 'win32':
-			return ('skip_warn','pexpect_spawn not supported on Windows platform')
-		func_args = dict(zip(arg_dfls.keys(),func_args))
+			return ('skip_warn', 'pexpect_spawn not supported on Windows platform')
+		func_args = dict(zip(arg_dfls.keys(), func_args))
 		t = self.spawn(
 			'test/misc/input_func.py',
-			[func_name,repr(func_args)],
+			[func_name, repr(func_args)],
 			cmd_dir='.',
-			pexpect_spawn=term )
+			pexpect_spawn=term)
 		imsg('Parameters:')
 		imsg(f'  pexpect_spawn: {term}')
 		imsg(f'  sending:       {text!r}')
 		imsg(f'  expecting:     {expect!r}')
 		imsg('\nFunction args:')
-		for k,v in func_args.items():
-			imsg('  {:14} {!r}'.format(k+':',v))
+		for k, v in func_args.items():
+			imsg('  {:14} {!r}'.format(k+':', v))
 		imsg_r('\nScript output: ')
 		prompt_add = (func_args['insert_txt'] if term else '') if func_name == 'line_input' else ''
 		prompt = func_args['prompt'] + prompt_add
@@ -268,14 +268,14 @@ class CmdTestInput(CmdTestBase):
 		assert ret == repr(expect), f'Text mismatch! {ret} != {repr(expect)}'
 		return t
 
-	def _get_char(self,func_args,text,expect,term):
+	def _get_char(self, func_args, text, expect, term):
 		arg_dfls = {
 			'prompt': '',
 			'immed_chars': '',
 			'prehold_protect': True,
 			'num_bytes': 5,
 		}
-		return self._input_func('get_char',arg_dfls,func_args,text,expect,term)
+		return self._input_func('get_char', arg_dfls, func_args, text, expect, term)
 
 	def _line_input(self, func_args, text, expect, term, delay=None):
 		arg_dfls = {
@@ -287,29 +287,29 @@ class CmdTestInput(CmdTestBase):
 		return self._input_func('line_input', arg_dfls, func_args, text+'\n', expect, term, delay=delay)
 
 	def get_char1(self):
-		return self._get_char(['prompt> ','',True,5],'x','x',False)
+		return self._get_char(['prompt> ', '', True, 5], 'x', 'x', False)
 
 	def get_char2(self):
 		expect = 'x' if sys.platform == 'win32' else 'xxxxx'
-		return self._get_char(['prompt> ','',True,5],'xxxxx',expect,False)
+		return self._get_char(['prompt> ', '', True, 5], 'xxxxx', expect, False)
 
 	def get_char3(self):
-		return self._get_char(['','',True,5],'x','x',False)
+		return self._get_char(['', '', True, 5], 'x', 'x', False)
 
 	def get_char4(self):
-		return self._get_char(['prompt> ','',True,2],'α','α',False) # UTF-8, must get 2 bytes
+		return self._get_char(['prompt> ', '', True, 2], 'α', 'α', False) # UTF-8, must get 2 bytes
 
 	def get_char_term1(self):
-		return self._get_char(['prompt> ','',True,2],'β','β',True)  # UTF-8, must get 2 bytes
+		return self._get_char(['prompt> ', '', True, 2], 'β', 'β', True)  # UTF-8, must get 2 bytes
 
 	def get_char_term2(self):
-		return self._get_char(['prompt> ','',True,5],'xxxxx','xxxxx',True)
+		return self._get_char(['prompt> ', '', True, 5], 'xxxxx', 'xxxxx', True)
 
 	def get_char_term3(self):
-		return self._get_char(['','',False,5],'x','x',True)
+		return self._get_char(['', '', False, 5], 'x', 'x', True)
 
 	def get_char_term4(self):
-		return self._get_char(['prompt> ','xyz',False,5],'x','x',True)
+		return self._get_char(['prompt> ', 'xyz', False, 5], 'x', 'x', True)
 
 	def line_input(self):
 		return self._line_input(
@@ -387,13 +387,13 @@ class CmdTestInput(CmdTestBase):
 			True,
 			hold_protect_delay)
 
-	def _password_entry(self,prompt,opts=[],term=False):
+	def _password_entry(self, prompt, opts=[], term=False):
 		if term and sys.platform == 'win32':
-			return ('skip_warn','pexpect_spawn not supported on Windows platform')
-		t = self.spawn( 'test/misc/input_func.py', opts + ['passphrase'], cmd_dir='.', pexpect_spawn=term )
+			return ('skip_warn', 'pexpect_spawn not supported on Windows platform')
+		t = self.spawn('test/misc/input_func.py', opts + ['passphrase'], cmd_dir='.', pexpect_spawn=term)
 		imsg(f'Terminal: {term}')
 		pw = 'abc-α'
-		t.expect(prompt,pw+'\n')
+		t.expect(prompt, pw+'\n')
 		ret = t.expect_getend('Entered: ')
 		assert ret == pw, f'Password mismatch! {ret} != {pw}'
 		return t
@@ -406,35 +406,35 @@ class CmdTestInput(CmdTestBase):
 		  test/misc/input_func.py{} passphrase
 	"""
 
-	def password_entry_noecho(self,term=False):
-		return self._password_entry('Enter passphrase: ',term=term)
+	def password_entry_noecho(self, term=False):
+		return self._password_entry('Enter passphrase: ', term=term)
 
 	def password_entry_noecho_term(self):
 		if self.skip_for_win('no pexpect_spawn'):
-			return ('skip_warn','\n' + fmt(self.winskip_msg.format(''),strip_char='\t'))
+			return ('skip_warn', '\n' + fmt(self.winskip_msg.format(''), strip_char='\t'))
 		return self.password_entry_noecho(term=True)
 
-	def password_entry_echo(self,term=False):
-		return self._password_entry('Enter passphrase (echoed): ',['--echo-passphrase'],term=term)
+	def password_entry_echo(self, term=False):
+		return self._password_entry('Enter passphrase (echoed): ', ['--echo-passphrase'], term=term)
 
 	def password_entry_echo_term(self):
 		if self.skip_for_win('no pexpect_spawn'):
-			return ('skip_warn','\n' + fmt(self.winskip_msg.format(' --echo-passphrase'),strip_char='\t'))
+			return ('skip_warn', '\n' + fmt(self.winskip_msg.format(' --echo-passphrase'), strip_char='\t'))
 		return self.password_entry_echo(term=True)
 
-	def _mn2hex(self,fmt,entry_mode='full',mn=None,pad_entry=False,enter_for_dfl=False):
+	def _mn2hex(self, fmt, entry_mode='full', mn=None, pad_entry=False, enter_for_dfl=False):
 		mn = mn or sample_mn[fmt]['mn'].split()
-		t = self.spawn('mmgen-tool',['mn2hex_interactive','fmt='+fmt,'mn_len=12','print_mn=1'])
+		t = self.spawn('mmgen-tool', ['mn2hex_interactive', 'fmt='+fmt, 'mn_len=12', 'print_mn=1'])
 		from mmgen.mn_entry import mn_entry
-		mne = mn_entry( cfg, fmt, entry_mode )
+		mne = mn_entry(cfg, fmt, entry_mode)
 		t.expect(
 			'Type a number.*: ',
 			('\n' if enter_for_dfl else str(mne.entry_modes.index(entry_mode)+1)),
-			regex = True )
+			regex = True)
 		t.expect(r'Using entry mode (\S+)', regex=True)
 		mode = strip_ansi_escapes(t.p.match.group(1)).lower()
 		assert mode == mne.em.name.lower(), f'{mode} != {mne.em.name.lower()}'
-		stealth_mnemonic_entry(t,mne,mn,entry_mode=entry_mode,pad_entry=pad_entry)
+		stealth_mnemonic_entry(t, mne, mn, entry_mode=entry_mode, pad_entry=pad_entry)
 		t.expect(sample_mn[fmt]['hex'])
 		return t
 
@@ -448,52 +448,52 @@ class CmdTestInput(CmdTestBase):
 			seedlen_opt = False):
 
 		wcls = get_wallet_cls(fmt_code=fmt)
-		wf = os.path.join(ref_dir,f'FE3C6545.{wcls.ext}')
+		wf = os.path.join(ref_dir, f'FE3C6545.{wcls.ext}')
 		if wcls.base_type == 'mnemonic':
 			mn = mn or read_from_file(wf).strip().split()
 		elif wcls.type == 'dieroll':
 			mn = mn or list(remove_whitespace(read_from_file(wf)))
-			for idx,val in ((5,'x'),(18,'0'),(30,'7'),(44,'9')):
-				mn.insert(idx,val)
+			for idx, val in ((5, 'x'), (18, '0'), (30, '7'), (44, '9')):
+				mn.insert(idx, val)
 		t = self.spawn(
 			'mmgen-walletconv',
 			['--usr-randchars=10', '--stdout']
 			+ (['--seed-len=128'] if seedlen_opt else [])
 			+ [f'--in-fmt={fmt}', f'--out-fmt={out_fmt or fmt}']
 		)
-		t.expect(f'{capfirst(wcls.base_type or wcls.type)} type:.*{wcls.mn_type}',regex=True)
+		t.expect(f'{capfirst(wcls.base_type or wcls.type)} type:.*{wcls.mn_type}', regex=True)
 		if not seedlen_opt:
-			t.expect(wcls.choose_seedlen_prompt,'1')
-			t.expect('(Y/n): ','y')
+			t.expect(wcls.choose_seedlen_prompt, '1')
+			t.expect('(Y/n): ', 'y')
 		if wcls.base_type == 'mnemonic':
-			t.expect('Type a number.*: ','6',regex=True)
+			t.expect('Type a number.*: ', '6', regex=True)
 			t.expect('invalid')
 			from mmgen.mn_entry import mn_entry
-			mne = mn_entry( cfg, fmt, entry_mode )
-			t.expect('Type a number.*: ',str(mne.entry_modes.index(entry_mode)+1),regex=True)
-			t.expect(r'Using entry mode (\S+)',regex=True)
+			mne = mn_entry(cfg, fmt, entry_mode)
+			t.expect('Type a number.*: ', str(mne.entry_modes.index(entry_mode)+1), regex=True)
+			t.expect(r'Using entry mode (\S+)', regex=True)
 			mode = strip_ansi_escapes(t.p.match.group(1)).lower()
 			assert mode == mne.em.name.lower(), f'{mode} != {mne.em.name.lower()}'
-			stealth_mnemonic_entry(t,mne,mn,entry_mode=entry_mode)
+			stealth_mnemonic_entry(t, mne, mn, entry_mode=entry_mode)
 		elif wcls.type == 'dieroll':
-			user_dieroll_entry(t,mn)
+			user_dieroll_entry(t, mn)
 			if usr_rand:
-				t.expect(wcls.user_entropy_prompt,'y')
+				t.expect(wcls.user_entropy_prompt, 'y')
 				t.usr_rand(10)
 			else:
-				t.expect(wcls.user_entropy_prompt,'n')
+				t.expect(wcls.user_entropy_prompt, 'n')
 		if not usr_rand:
 			sid_chk = 'FE3C6545'
 			sid = t.expect_getend(f'Valid {wcls.desc} for Seed ID')
 			sid = strip_ansi_escapes(sid.split(',')[0])
 			assert sid_chk in sid, f'Seed ID mismatch! {sid_chk} not found in {sid}'
-		t.expect('to confirm: ','YES\n')
+		t.expect('to confirm: ', 'YES\n')
 		return t
 
 	def mnemonic_entry_mmgen_minimal(self):
 		from mmgen.mn_entry import mn_entry
 		# erase_chars: '\b\x7f'
-		m = mn_entry( cfg, 'mmgen', 'minimal' )
+		m = mn_entry(cfg, 'mmgen', 'minimal')
 		np = 2
 		mn = (
 			'z',
@@ -511,30 +511,30 @@ class CmdTestInput(CmdTestBase):
 			'app\bpl',
 			'wd',
 			'busy')
-		return self._user_seed_entry('words',entry_mode='minimal',mn=mn)
+		return self._user_seed_entry('words', entry_mode='minimal', mn=mn)
 	def mnemonic_entry_mmgen(self):
-		return self._user_seed_entry('words',entry_mode='full')
+		return self._user_seed_entry('words', entry_mode='full')
 	def mnemonic_entry_bip39(self):
-		return self._user_seed_entry('bip39',entry_mode='full')
+		return self._user_seed_entry('bip39', entry_mode='full')
 	def mnemonic_entry_bip39_short(self):
-		return self._user_seed_entry('bip39',entry_mode='short')
+		return self._user_seed_entry('bip39', entry_mode='short')
 
 	def mn2hex_interactive_mmgen(self):
-		return self._mn2hex('mmgen',entry_mode='full')
+		return self._mn2hex('mmgen', entry_mode='full')
 	def mn2hex_interactive_mmgen_fixed(self):
-		return self._mn2hex('mmgen',entry_mode='fixed')
+		return self._mn2hex('mmgen', entry_mode='fixed')
 	def mn2hex_interactive_bip39(self):
-		return self._mn2hex('bip39',entry_mode='full')
+		return self._mn2hex('bip39', entry_mode='full')
 	def mn2hex_interactive_bip39_short(self):
-		return self._mn2hex('bip39',entry_mode='short',pad_entry=True)
+		return self._mn2hex('bip39', entry_mode='short', pad_entry=True)
 	def mn2hex_interactive_bip39_fixed(self):
-		return self._mn2hex('bip39',entry_mode='fixed',enter_for_dfl=True)
+		return self._mn2hex('bip39', entry_mode='fixed', enter_for_dfl=True)
 	def mn2hex_interactive_xmr(self):
-		return self._mn2hex('xmrseed',entry_mode='full')
+		return self._mn2hex('xmrseed', entry_mode='full')
 	def mn2hex_interactive_xmr_short(self):
-		return self._mn2hex('xmrseed',entry_mode='short')
+		return self._mn2hex('xmrseed', entry_mode='short')
 
 	def dieroll_entry(self):
 		return self._user_seed_entry('dieroll', seedlen_opt=True)
 	def dieroll_entry_usrrand(self):
-		return self._user_seed_entry('dieroll',usr_rand=True,out_fmt='bip39')
+		return self._user_seed_entry('dieroll', usr_rand=True, out_fmt='bip39')

File diff suppressed because it is too large
+ 411 - 317
test/cmdtest_py_d/ct_main.py


+ 63 - 58
test/cmdtest_py_d/ct_misc.py

@@ -39,8 +39,8 @@ class CmdTestDev(CmdTestBase):
 	tmpdir_nums = [99]
 	color = True
 
-	def _spawn(self,script,args):
-		return self.spawn(script,args,cmd_dir='.',no_exec_wrapper=True)
+	def _spawn(self, script, args):
+		return self.spawn(script, args, cmd_dir='.', no_exec_wrapper=True)
 
 	def compute_file_chksum(self):
 		t = self._spawn('scripts/compute-file-chksum.py', ['test/ref/25EFA3[2.34].testnet.rawtx'])
@@ -50,28 +50,29 @@ class CmdTestDev(CmdTestBase):
 	def create_bip_hd_chain_params(self):
 		t = self._spawn('scripts/create-bip-hd-chain-params.py', ['test/ref/altcoin/slip44-mini.json'])
 		t.expect('[defaults]')
-		t.expect(r"secp.*0488ade4.*0488b21e.*0'\/0\/0",regex=True)
+		t.expect(r"secp.*0488ade4.*0488b21e.*0'\/0\/0", regex=True)
 		t.expect('[bip-44]')
 		t.expect('[bip-49]')
-		t.match_expect_list(['0','BTC','x','m','P2SH','049d7878','049d7cb2','80','05','x','Bitcoin','1'])
+		t.match_expect_list(
+			['0', 'BTC', 'x', 'm', 'P2SH', '049d7878', '049d7cb2', '80', '05', 'x', 'Bitcoin', '1'])
 		return t
 
 class CmdTestMisc(CmdTestBase):
 	'miscellaneous tests (RPC backends, xmrwallet_txview, term)'
 	networks = ('btc',)
 	tmpdir_nums = [99]
-	passthru_opts = ('daemon_data_dir','rpc_port')
+	passthru_opts = ('daemon_data_dir', 'rpc_port')
 	cmd_group = (
 		('rpc_backends',         'RPC backends'),
-		('bch_txview_legacy1',   "'mmgen-tool --coin=bch --cashaddr=0 txview terse=0'"),
-		('bch_txview_legacy2',   "'mmgen-tool --coin=bch --cashaddr=0 txview terse=1'"),
-		('bch_txview_cashaddr1', "'mmgen-tool --coin=bch --cashaddr=1 txview terse=0'"),
-		('bch_txview_cashaddr2', "'mmgen-tool --coin=bch --cashaddr=1 txview terse=1'"),
-		('xmrwallet_txview',     "'mmgen-xmrwallet' txview"),
-		('xmrwallet_txlist',     "'mmgen-xmrwallet' txlist"),
-		('coin_daemon_info',     "'examples/coin-daemon-info.py'"),
-		('examples_bip_hd',      "'examples/bip_hd.py'"),
-		('term_echo',            "term.set('echo')"),
+		('bch_txview_legacy1',   'mmgen-tool --coin=bch --cashaddr=0 txview terse=0'),
+		('bch_txview_legacy2',   'mmgen-tool --coin=bch --cashaddr=0 txview terse=1'),
+		('bch_txview_cashaddr1', 'mmgen-tool --coin=bch --cashaddr=1 txview terse=0'),
+		('bch_txview_cashaddr2', 'mmgen-tool --coin=bch --cashaddr=1 txview terse=1'),
+		('xmrwallet_txview',     '‘mmgen-xmrwallet txview’'),
+		('xmrwallet_txlist',     '‘mmgen-xmrwallet txlist’'),
+		('coin_daemon_info',     'examples/coin-daemon-info.py'),
+		('examples_bip_hd',      'examples/bip_hd.py'),
+		('term_echo',            'term.set("echo")'),
 		('term_cleanup',         'term.register_cleanup()'),
 	)
 	need_daemon = True
@@ -80,7 +81,7 @@ class CmdTestMisc(CmdTestBase):
 	def rpc_backends(self):
 		backends = cfg._autoset_opts['rpc_backend'][1]
 		for b in backends:
-			t = self.spawn_chk('mmgen-tool',[f'--rpc-backend={b}','daemon_version'],extra_desc=f'({b})')
+			t = self.spawn_chk('mmgen-tool', [f'--rpc-backend={b}', 'daemon_version'], extra_desc=f'({b})')
 		return t
 
 	def _bch_txview(self, view_pref, terse, expect):
@@ -104,11 +105,11 @@ class CmdTestMisc(CmdTestBase):
 	def bch_txview_cashaddr2(self):
 		return self._bch_txview(1, 1, '[1HpynST7vkLn8yNtdrqPfeghexZk4sdB3W]')
 
-	def xmrwallet_txview(self,op='txview'):
+	def xmrwallet_txview(self, op='txview'):
 		if cfg.no_altcoin:
 			return 'skip'
-		files = get_file_with_ext('test/ref/monero','tx',no_dot=True,delete=False,return_list=True)
-		t = self.spawn( 'mmgen-xmrwallet', [op] + files )
+		files = get_file_with_ext('test/ref/monero', 'tx', no_dot=True, delete=False, return_list=True)
+		t = self.spawn('mmgen-xmrwallet', [op] + files)
 		res = t.read(strip_color=True)
 		if op == 'txview':
 			for s in (
@@ -117,7 +118,7 @@ class CmdTestMisc(CmdTestBase):
 			):
 				assert s in res, f'{s} not in {res}'
 		elif op == 'txlist':
-			assert re.search( '3EBD06-.*D94583-.*8BFA29-', res, re.DOTALL )
+			assert re.search('3EBD06-.*D94583-.*8BFA29-', res, re.DOTALL)
 		return t
 
 	def xmrwallet_txlist(self):
@@ -126,31 +127,31 @@ class CmdTestMisc(CmdTestBase):
 	def examples_bip_hd(self):
 		if cfg.no_altcoin:
 			return 'skip'
-		return self.spawn('examples/bip_hd.py',cmd_dir='.')
+		return self.spawn('examples/bip_hd.py', cmd_dir='.')
 
 	def coin_daemon_info(self):
 		if cfg.no_altcoin:
 			coins = ['btc']
 		else:
-			coins = ['btc','ltc','eth']
-			start_test_daemons('ltc','eth')
-		t = self.spawn('examples/coin-daemon-info.py',coins,cmd_dir='.')
+			coins = ['btc', 'ltc', 'eth']
+			start_test_daemons('ltc', 'eth')
+		t = self.spawn('examples/coin-daemon-info.py', coins, cmd_dir='.')
 		for coin in coins:
-			t.expect(coin.upper() + r'\s+mainnet\s+Up',regex=True)
+			t.expect(coin.upper() + r'\s+mainnet\s+Up', regex=True)
 		if cfg.pexpect_spawn:
 			t.send('q')
 		if not cfg.no_altcoin:
-			stop_test_daemons('ltc','eth')
+			stop_test_daemons('ltc', 'eth')
 		return t
 
 	def term_echo(self):
 
 		def test_echo():
-			t.expect('echo> ','foo\n')
+			t.expect('echo> ', 'foo\n')
 			t.expect('foo')
 
 		def test_noecho():
-			t.expect('noecho> ','foo\n')
+			t.expect('noecho> ', 'foo\n')
 			import pexpect
 			try:
 				t.expect('foo')
@@ -163,7 +164,7 @@ class CmdTestMisc(CmdTestBase):
 		if self.skip_for_win('no termios support') or self.skip_for_mac('termios.ECHO issues'):
 			return 'skip'
 
-		t = self.spawn('test/misc/term_ni.py',['echo'],cmd_dir='.',pexpect_spawn=True,timeout=1)
+		t = self.spawn('test/misc/term_ni.py', ['echo'], cmd_dir='.', pexpect_spawn=True, timeout=1)
 		t.p.logfile = None
 		t.p.logfile_read = sys.stdout if cfg.verbose or cfg.exact_output else None
 		t.p.logfile_send = None
@@ -177,23 +178,23 @@ class CmdTestMisc(CmdTestBase):
 	def term_cleanup(self):
 		if self.skip_for_win('no termios support'):
 			return 'skip'
-		return self.spawn('test/misc/term_ni.py',['cleanup'],cmd_dir='.',pexpect_spawn=True)
+		return self.spawn('test/misc/term_ni.py', ['cleanup'], cmd_dir='.', pexpect_spawn=True)
 
 class CmdTestOutput(CmdTestBase):
 	'screen output'
 	networks = ('btc',)
 	cmd_group = (
-		('output_gr', (1,"Greek text", [])),
-		('output_ru', (1,"Russian text", [])),
-		('output_zh', (1,"Chinese text", [])),
-		('output_jp', (1,"Japanese text", [])),
-		('oneshot_warning', (1,"Oneshot warnings", [])),
-		('oneshot_warning_term', (1,"Oneshot warnings (pexpect_spawn)", []))
+		('output_gr',            (1, 'Greek text', [])),
+		('output_ru',            (1, 'Russian text', [])),
+		('output_zh',            (1, 'Chinese text', [])),
+		('output_jp',            (1, 'Japanese text', [])),
+		('oneshot_warning',      (1, 'Oneshot warnings', [])),
+		('oneshot_warning_term', (1, 'Oneshot warnings (pexpect_spawn)', []))
 	)
 	color = True
 
-	def screen_output(self,lang):
-		return self.spawn('test/misc/utf8_output.py',[lang],cmd_dir='.')
+	def screen_output(self, lang):
+		return self.spawn('test/misc/utf8_output.py', [lang], cmd_dir='.')
 
 	def output_gr(self):
 		return self.screen_output('gr')
@@ -204,8 +205,8 @@ class CmdTestOutput(CmdTestBase):
 	def output_jp(self):
 		return self.screen_output('jp')
 
-	def oneshot_warning(self,pexpect_spawn=None):
-		t = self.spawn('test/misc/oneshot_warning.py',cmd_dir='.',pexpect_spawn=pexpect_spawn)
+	def oneshot_warning(self, pexpect_spawn=None):
+		t = self.spawn('test/misc/oneshot_warning.py', cmd_dir='.', pexpect_spawn=pexpect_spawn)
 		nl = '\r\n' if sys.platform == 'win32' or t.pexpect_spawn else '\n'
 		for s in (
 			f'pw{nl}wg1',
@@ -234,33 +235,37 @@ class CmdTestOutput(CmdTestBase):
 			return 'skip'
 		return self.oneshot_warning(pexpect_spawn=True)
 
-class CmdTestRefTX(CmdTestMain,CmdTestBase):
+class CmdTestRefTX(CmdTestMain, CmdTestBase):
 	'create a reference transaction file (administrative command)'
 	segwit_opts_ok = False
-	passthru_opts = ('daemon_data_dir','rpc_port','coin','testnet')
-	tmpdir_nums = [31,32,33,34]
+	passthru_opts = ('daemon_data_dir', 'rpc_port', 'coin', 'testnet')
+	tmpdir_nums = [31, 32, 33, 34]
 	need_daemon = True
 	cmd_group = (
-		('ref_tx_addrgen1', (31,'address generation (legacy)', [[[],1]])),
-		('ref_tx_addrgen2', (32,'address generation (compressed)', [[[],1]])),
-		('ref_tx_addrgen3', (33,'address generation (segwit)', [[[],1]])),
-		('ref_tx_addrgen4', (34,'address generation (bech32)', [[[],1]])),
-		('ref_tx_txcreate', (31,'transaction creation',
-								([['addrs'],31],[['addrs'],32],[['addrs'],33],[['addrs'],34]))),
+		('ref_tx_addrgen1', (31, 'address generation (legacy)',     [[[], 1]])),
+		('ref_tx_addrgen2', (32, 'address generation (compressed)', [[[], 1]])),
+		('ref_tx_addrgen3', (33, 'address generation (segwit)',     [[[], 1]])),
+		('ref_tx_addrgen4', (34, 'address generation (bech32)',     [[[], 1]])),
+		('ref_tx_txcreate',
+			(31, 'transaction creation',
+			([['addrs'], 31], [['addrs'], 32], [['addrs'], 33], [['addrs'], 34]))
+		),
 	)
 
-	def __init__(self,trunner,cfgs,spawn):
+	def __init__(self, trunner, cfgs, spawn):
 		if cfgs:
 			for n in self.tmpdir_nums:
-				cfgs[str(n)].update({   'addr_idx_list': '1-2',
-										'segwit': n in (33,34),
-										'dep_generators': { 'addrs':'ref_tx_addrgen'+str(n)[-1] }})
-		CmdTestMain.__init__(self,trunner,cfgs,spawn)
-
-	def ref_tx_addrgen(self,atype):
+				cfgs[str(n)].update({
+					'addr_idx_list': '1-2',
+					'segwit': n in (33, 34),
+					'dep_generators': {'addrs':'ref_tx_addrgen'+str(n)[-1]}
+				})
+		CmdTestMain.__init__(self, trunner, cfgs, spawn)
+
+	def ref_tx_addrgen(self, atype):
 		if atype not in self.proto.mmtypes:
 			return
-		return self.spawn('mmgen-addrgen',['--outdir='+self.tmpdir,'--type='+atype,dfl_words_file,'1-2'])
+		return self.spawn('mmgen-addrgen', ['--outdir='+self.tmpdir, '--type='+atype, dfl_words_file, '1-2'])
 
 	def ref_tx_addrgen1(self):
 		return self.ref_tx_addrgen(atype='L')
@@ -271,8 +276,8 @@ class CmdTestRefTX(CmdTestMain,CmdTestBase):
 	def ref_tx_addrgen4(self):
 		return self.ref_tx_addrgen(atype='B')
 
-	def ref_tx_txcreate(self,f1,f2,f3,f4):
-		sources = ['31','32']
+	def ref_tx_txcreate(self, f1, f2, f3, f4):
+		sources = ['31', '32']
 		if 'S' in self.proto.mmtypes:
 			sources += ['33']
 		if 'B' in self.proto.mmtypes:

+ 87 - 87
test/cmdtest_py_d/ct_opts.py

@@ -10,7 +10,7 @@
 test.cmdtest_py_d.ct_opts: options processing tests for the MMGen cmdtest.py test suite
 """
 
-import os,time
+import os, time
 
 from ..include.common import cfg
 from .ct_base import CmdTestBase
@@ -46,41 +46,41 @@ class CmdTestOpts(CmdTestBase):
 		('opt_bad_outdir',       (41, 'bad outdir parameter', [])),
 		('opt_bad_incompatible', (41, 'incompatible opts', [])),
 		('opt_bad_autoset',      (41, 'invalid autoset value', [])),
-		('opt_invalid_1',     (41, 'invalid cmdline opt ‘--x’', [])),
-		('opt_invalid_2',     (41, 'invalid cmdline opt ‘---’', [])),
-		('opt_invalid_5',     (41, 'invalid cmdline opt (missing parameter)', [])),
-		('opt_invalid_6',     (41, 'invalid cmdline opt (missing parameter)', [])),
-		('opt_invalid_7',     (41, 'invalid cmdline opt (parameter not required)', [])),
-		('opt_invalid_8',     (41, 'invalid cmdline opt (non-existent option)', [])),
-		('opt_invalid_9',     (41, 'invalid cmdline opt (non-existent option)', [])),
-		('opt_invalid_10',    (41, 'invalid cmdline opt (missing parameter)', [])),
-		('opt_invalid_11',    (41, 'invalid cmdline opt (missing parameter)', [])),
-		('opt_invalid_12',    (41, 'invalid cmdline opt (non-existent option)', [])),
-		('opt_invalid_13',    (41, 'invalid cmdline opt (ambiguous long opt substring)', [])),
-		('opt_invalid_14',    (41, 'invalid cmdline opt (long opt substring too short)', [])),
-		('opt_invalid_15',    (41, 'invalid cmdline (too many args)', [])),
-		('opt_invalid_16',    (41, 'invalid cmdline (overlong arg)', [])),
+		('opt_invalid_1',        (41, 'invalid cmdline opt ‘--x’', [])),
+		('opt_invalid_2',        (41, 'invalid cmdline opt ‘---’', [])),
+		('opt_invalid_5',        (41, 'invalid cmdline opt (missing parameter)', [])),
+		('opt_invalid_6',        (41, 'invalid cmdline opt (missing parameter)', [])),
+		('opt_invalid_7',        (41, 'invalid cmdline opt (parameter not required)', [])),
+		('opt_invalid_8',        (41, 'invalid cmdline opt (non-existent option)', [])),
+		('opt_invalid_9',        (41, 'invalid cmdline opt (non-existent option)', [])),
+		('opt_invalid_10',       (41, 'invalid cmdline opt (missing parameter)', [])),
+		('opt_invalid_11',       (41, 'invalid cmdline opt (missing parameter)', [])),
+		('opt_invalid_12',       (41, 'invalid cmdline opt (non-existent option)', [])),
+		('opt_invalid_13',       (41, 'invalid cmdline opt (ambiguous long opt substring)', [])),
+		('opt_invalid_14',       (41, 'invalid cmdline opt (long opt substring too short)', [])),
+		('opt_invalid_15',       (41, 'invalid cmdline (too many args)', [])),
+		('opt_invalid_16',       (41, 'invalid cmdline (overlong arg)', [])),
 	)
 
 	def spawn_prog(self, args, exit_val=None):
 		return self.spawn('test/misc/opts.py', args, cmd_dir='.', exit_val=exit_val)
 
-	def check_vals(self,args,vals):
+	def check_vals(self, args, vals):
 		t = self.spawn_prog(args)
-		for k,v in vals:
-			t.expect(rf'{k}:\s+{v}',regex=True)
+		for k, v in vals:
+			t.expect(rf'{k}:\s+{v}', regex=True)
 		return t
 
-	def do_run(self,args,expect,exit_val,regex=False):
+	def do_run(self, args, expect, exit_val, regex=False):
 		t = self.spawn_prog(args, exit_val=exit_val or None)
-		t.expect(expect,regex=regex)
+		t.expect(expect, regex=regex)
 		return t
 
 	def opt_helpscreen(self):
 		expect = r'OPTS.PY: Opts test.*USAGE:\s+opts.py'
 		if not cfg.pexpect_spawn:
 			expect += r'.*--minconf.*NOTES FOR THIS.*a note'
-		t = self.do_run( ['--help'], expect, 0, regex=True )
+		t = self.do_run(['--help'], expect, 0, regex=True)
 		if t.pexpect_spawn:
 			time.sleep(0.4)
 			t.send('q')
@@ -88,74 +88,74 @@ class CmdTestOpts(CmdTestBase):
 
 	def opt_noargs(self):
 		return self.check_vals(
-				[],
-				(
-					('cfg.foo',                 'None'),         # added opt
-					('cfg.print_checksum',      'None'),         # sets 'quiet'
-					('cfg.quiet',               'False'),        # _incompatible_opts
-					('cfg.verbose',             'False'),        # _incompatible_opts
-					('cfg.passwd_file',         ''),             # _infile_opts - check_infile()
-					('cfg.outdir',              ''),             # check_outdir()
-					('cfg.cached_balances',     'False'),
-					('cfg.minconf',             '1'),
-					('cfg.coin',                'BTC'),
-					('cfg.pager',               'False'),
-					('cfg.fee_estimate_mode',   'conservative'), # _autoset_opts
-				))
+			[],
+			(
+				('cfg.foo',                 'None'),         # added opt
+				('cfg.print_checksum',      'None'),         # sets 'quiet'
+				('cfg.quiet',               'False'),        # _incompatible_opts
+				('cfg.verbose',             'False'),        # _incompatible_opts
+				('cfg.passwd_file',         ''),             # _infile_opts - check_infile()
+				('cfg.outdir',              ''),             # check_outdir()
+				('cfg.cached_balances',     'False'),
+				('cfg.minconf',             '1'),
+				('cfg.coin',                'BTC'),
+				('cfg.pager',               'False'),
+				('cfg.fee_estimate_mode',   'conservative'), # _autoset_opts
+			))
 
 	def opt_good1(self):
 		pf_base = 'testfile'
-		pf = os.path.join(self.tmpdir,pf_base)
-		self.write_to_tmpfile(pf_base,'')
+		pf = os.path.join(self.tmpdir, pf_base)
+		self.write_to_tmpfile(pf_base, '')
 		return self.check_vals(
-				[
-					'--print-checksum',
-					'--fee-estimate-mode=E',
-					'--passwd-file='+pf,
-					'--outdir='+self.tmpdir,
-					'--cached-balances',
-					f'--hidden-incog-input-params={pf},123',
-				], (
-					('cfg.print_checksum',           'True'),
-					('cfg.quiet',                    'True'), # set by print_checksum
-					('cfg.passwd_file',              pf),
-					('cfg.outdir',                   self.tmpdir),
-					('cfg.cached_balances',          'True'),
-					('cfg.hidden_incog_input_params', pf+',123'),
-					('cfg.fee_estimate_mode',         'economical'),
-				))
+			[
+				'--print-checksum',
+				'--fee-estimate-mode=E',
+				'--passwd-file='+pf,
+				'--outdir='+self.tmpdir,
+				'--cached-balances',
+				f'--hidden-incog-input-params={pf},123',
+			], (
+				('cfg.print_checksum',           'True'),
+				('cfg.quiet',                    'True'), # set by print_checksum
+				('cfg.passwd_file',              pf),
+				('cfg.outdir',                   self.tmpdir),
+				('cfg.cached_balances',          'True'),
+				('cfg.hidden_incog_input_params', pf+',123'),
+				('cfg.fee_estimate_mode',         'economical'),
+			))
 
 	def opt_good2(self):
 		return self.check_vals(
-				[
-					'--print-checksum',
-					'-qX',
-					f'--outdir={self.tmpdir}',
-					'-p5',
-					'-m', '0',
-					'--seed-len=256',
-					'-L--my-label',
-					'--seed-len', '128',
-					'--min-temp=-30',
-					'-T-10',
-					'--',
-					'x', 'y', '12345'
-				], (
-					('cfg.print_checksum',  'True'),
-					('cfg.quiet',           'True'),
-					('cfg.outdir',          self.tmpdir),
-					('cfg.cached_balances', 'True'),
-					('cfg.minconf',         '0'),
-					('cfg.keep_label',      'None'),
-					('cfg.seed_len',        '128'),
-					('cfg.hash_preset',     '5'),
-					('cfg.label',           '--my-label'),
-					('cfg.min_temp',     '-30'),
-					('cfg.max_temp',     '-10'),
-					('arg1',           'x'),
-					('arg2',           'y'),
-					('arg3',           '12345'),
-				))
+			[
+				'--print-checksum',
+				'-qX',
+				f'--outdir={self.tmpdir}',
+				'-p5',
+				'-m', '0',
+				'--seed-len=256',
+				'-L--my-label',
+				'--seed-len', '128',
+				'--min-temp=-30',
+				'-T-10',
+				'--',
+				'x', 'y', '12345'
+			], (
+				('cfg.print_checksum',  'True'),
+				('cfg.quiet',           'True'),
+				('cfg.outdir',          self.tmpdir),
+				('cfg.cached_balances', 'True'),
+				('cfg.minconf',         '0'),
+				('cfg.keep_label',      'None'),
+				('cfg.seed_len',        '128'),
+				('cfg.hash_preset',     '5'),
+				('cfg.label',           '--my-label'),
+				('cfg.min_temp',        '-30'),
+				('cfg.max_temp',        '-10'),
+				('arg1',                'x'),
+				('arg2',                'y'),
+				('arg3',                '12345'),
+			))
 
 	def opt_good3(self):
 		return self.check_vals(['m'] * 256, (('arg256', 'm'),))
@@ -212,18 +212,18 @@ class CmdTestOpts(CmdTestBase):
 		return self.do_run(['--pager=1'], 'no parameter', 1)
 
 	def opt_bad_infile(self):
-		pf = os.path.join(self.tmpdir,'fubar')
-		return self.do_run(['--passwd-file='+pf],'not found',1)
+		pf = os.path.join(self.tmpdir, 'fubar')
+		return self.do_run(['--passwd-file='+pf], 'not found', 1)
 
 	def opt_bad_outdir(self):
 		bo = self.tmpdir+'_fubar'
-		return self.do_run(['--outdir='+bo],'not found',1)
+		return self.do_run(['--outdir='+bo], 'not found', 1)
 
 	def opt_bad_incompatible(self):
-		return self.do_run(['--label=Label','--keep-label'],'Conflicting options',1)
+		return self.do_run(['--label=Label', '--keep-label'], 'Conflicting options', 1)
 
 	def opt_bad_autoset(self):
-		return self.do_run(['--fee-estimate-mode=Fubar'],'not unique substring',1)
+		return self.do_run(['--fee-estimate-mode=Fubar'], 'not unique substring', 1)
 
 	def opt_invalid(self, args, expect, exit_val):
 		t = self.spawn_prog(args, exit_val=exit_val)

+ 134 - 119
test/cmdtest_py_d/ct_ref.py

@@ -51,11 +51,11 @@ from .ct_shared import CmdTestShared
 
 wpasswd = 'reference password'
 
-class CmdTestRef(CmdTestBase,CmdTestShared):
+class CmdTestRef(CmdTestBase, CmdTestShared):
 	'saved reference address, password and transaction files'
 	tmpdir_nums = [8]
-	networks = ('btc','btc_tn','ltc','ltc_tn')
-	passthru_opts = ('daemon_data_dir','rpc_port','coin','testnet')
+	networks = ('btc', 'btc_tn', 'ltc', 'ltc_tn')
+	passthru_opts = ('daemon_data_dir', 'rpc_port', 'coin', 'testnet')
 	need_daemon = True
 	sources = {
 		'ref_addrfile':    '98831F3A{}[1,31-33,500-501,1010-1011]{}.addrs',
@@ -77,17 +77,30 @@ class CmdTestRef(CmdTestBase,CmdTestShared):
 		'ref_passwdfile_xmrseed_25': '98831F3A-фубар@crypto.org-xmrseed-25[1,4,1100].pws',
 		'ref_passwdfile_hex2bip39_12': '98831F3A-фубар@crypto.org-hex2bip39-12[1,4,1100].pws',
 		'ref_tx_file': { # data shared with ref_altcoin, autosign
-			'btc': ('0B8D5A[15.31789,14,tl=1320969600].rawtx',
-					'0C7115[15.86255,14,tl=1320969600].testnet.rawtx'),
-			'ltc': ('AF3CDF-LTC[620.76194,1453,tl=1320969600].rawtx',
-					'A5A1E0-LTC[1454.64322,1453,tl=1320969600].testnet.rawtx'),
-			'bch': ('460D4D-BCH[10.19764,tl=1320969600].rawtx',
-					'359FD5-BCH[6.68868,tl=1320969600].testnet.rawtx'),
-			'eth': ('88FEFD-ETH[23.45495,40000].rawtx',
-					'B472BD-ETH[23.45495,40000].testnet.rawtx'),
-			'mm1': ('5881D2-MM1[1.23456,50000].rawtx',
-					'6BDB25-MM1[1.23456,50000].testnet.rawtx'),
-			'etc': ('ED3848-ETC[1.2345,40000].rawtx','')
+			'btc': (
+				'0B8D5A[15.31789,14,tl=1320969600].rawtx',
+				'0C7115[15.86255,14,tl=1320969600].testnet.rawtx'
+			),
+			'ltc': (
+				'AF3CDF-LTC[620.76194,1453,tl=1320969600].rawtx',
+				'A5A1E0-LTC[1454.64322,1453,tl=1320969600].testnet.rawtx'
+			),
+			'bch': (
+				'460D4D-BCH[10.19764,tl=1320969600].rawtx',
+				'359FD5-BCH[6.68868,tl=1320969600].testnet.rawtx'
+			),
+			'eth': (
+				'88FEFD-ETH[23.45495,40000].rawtx',
+				'B472BD-ETH[23.45495,40000].testnet.rawtx'
+			),
+			'mm1': (
+				'5881D2-MM1[1.23456,50000].rawtx',
+				'6BDB25-MM1[1.23456,50000].testnet.rawtx'
+			),
+			'etc': (
+				'ED3848-ETC[1.2345,40000].rawtx',
+				''
+			)
 		},
 	}
 	chk_data = {
@@ -96,82 +109,84 @@ class CmdTestRef(CmdTestBase,CmdTestShared):
 			'98831F3A:1S':'20D95B09',
 		},
 		'ref_addrfile_chksum': {
-			'btc': ('6FEF 6FB9 7B13 5D91','424E 4326 CFFE 5F51'),
-			'ltc': ('AD52 C3FE 8924 AAF0','4EBE 2E85 E969 1B30'),
+			'btc': ('6FEF 6FB9 7B13 5D91', '424E 4326 CFFE 5F51'),
+			'ltc': ('AD52 C3FE 8924 AAF0', '4EBE 2E85 E969 1B30'),
 		},
 		'ref_segwitaddrfile_chksum': {
-			'btc': ('06C1 9C87 F25C 4EE6','072C 8B07 2730 CB7A'),
-			'ltc': ('63DF E42A 0827 21C3','5DD1 D186 DBE1 59F2'),
+			'btc': ('06C1 9C87 F25C 4EE6', '072C 8B07 2730 CB7A'),
+			'ltc': ('63DF E42A 0827 21C3', '5DD1 D186 DBE1 59F2'),
 		},
 		'ref_bech32addrfile_chksum': {
-			'btc': ('9D2A D4B6 5117 F02E','0527 9C39 6C1B E39A'),
-			'ltc': ('FF1C 7939 5967 AB82','ED3D 8AA4 BED4 0B40'),
+			'btc': ('9D2A D4B6 5117 F02E', '0527 9C39 6C1B E39A'),
+			'ltc': ('FF1C 7939 5967 AB82', 'ED3D 8AA4 BED4 0B40'),
 		},
 		'ref_keyaddrfile_chksum': {
-			'btc': ('9F2D D781 1812 8BAD','88CC 5120 9A91 22C2'),
-			'ltc': ('B804 978A 8796 3ED4','98B5 AC35 F334 0398'),
+			'btc': ('9F2D D781 1812 8BAD', '88CC 5120 9A91 22C2'),
+			'ltc': ('B804 978A 8796 3ED4', '98B5 AC35 F334 0398'),
 		},
-		'ref_passwdfile_b32_12_chksum': '7252 CD8D EF0D 3DB1',
-		'ref_passwdfile_b32_24_chksum': '8D56 3845 A072 A5B9',
-		'ref_passwdfile_b58_10_chksum': '534F CC1A 6701 9FED',
-		'ref_passwdfile_b58_20_chksum': 'DDD9 44B0 CA28 183F',
-		'ref_passwdfile_hex_32_chksum': '05C7 3678 E25E BC32',
-		'ref_passwdfile_hex_48_chksum': '7DBB FFD0 633E DE6F',
-		'ref_passwdfile_hex_64_chksum': 'F11D CB0A 8AE3 4D21',
-		'ref_passwdfile_bip39_12_chksum': 'BF57 02A3 5229 CF18',
-		'ref_passwdfile_bip39_18_chksum': '31D3 1656 B7DC 27CF',
-		'ref_passwdfile_bip39_24_chksum': 'E565 3A59 7D91 4671',
-		'ref_passwdfile_xmrseed_25_chksum': 'B488 21D3 4539 968D',
+		'ref_passwdfile_b32_12_chksum':       '7252 CD8D EF0D 3DB1',
+		'ref_passwdfile_b32_24_chksum':       '8D56 3845 A072 A5B9',
+		'ref_passwdfile_b58_10_chksum':       '534F CC1A 6701 9FED',
+		'ref_passwdfile_b58_20_chksum':       'DDD9 44B0 CA28 183F',
+		'ref_passwdfile_hex_32_chksum':       '05C7 3678 E25E BC32',
+		'ref_passwdfile_hex_48_chksum':       '7DBB FFD0 633E DE6F',
+		'ref_passwdfile_hex_64_chksum':       'F11D CB0A 8AE3 4D21',
+		'ref_passwdfile_bip39_12_chksum':     'BF57 02A3 5229 CF18',
+		'ref_passwdfile_bip39_18_chksum':     '31D3 1656 B7DC 27CF',
+		'ref_passwdfile_bip39_24_chksum':     'E565 3A59 7D91 4671',
+		'ref_passwdfile_xmrseed_25_chksum':   'B488 21D3 4539 968D',
 		'ref_passwdfile_hex2bip39_12_chksum': '93AD 4AE2 03D1 8A0A',
 	}
 	cmd_group = ( # TODO: move to tooltest2
-		('ref_words_to_subwallet_chk1','subwallet generation from reference words file (long subseed)'),
-		('ref_words_to_subwallet_chk2','subwallet generation from reference words file (short subseed)'),
-		('ref_subwallet_addrgen1','subwallet address file generation (long subseed)'),
-		('ref_subwallet_addrgen2','subwallet address file generation (short subseed)'),
-		('ref_subwallet_keygen1','subwallet key-address file generation (long subseed)'),
-		('ref_subwallet_keygen2','subwallet key-address file generation (short subseed)'),
-		('ref_addrfile_chk',   'saved reference address file'),
-		('ref_segwitaddrfile_chk','saved reference address file (segwit)'),
-		('ref_bech32addrfile_chk','saved reference address file (bech32)'),
-		('ref_keyaddrfile_chk','saved reference key-address file'),
-
-		('ref_passwdfile_chk_b58_20','saved reference password file (base58, 20 chars)'),
-		('ref_passwdfile_chk_b58_10','saved reference password file (base58, 10 chars)'),
-		('ref_passwdfile_chk_b32_24','saved reference password file (base32, 24 chars)'),
-		('ref_passwdfile_chk_b32_12','saved reference password file (base32, 12 chars)'),
-		('ref_passwdfile_chk_hex_32','saved reference password file (hexadecimal, 32 chars)'),
-		('ref_passwdfile_chk_hex_48','saved reference password file (hexadecimal, 48 chars)'),
-		('ref_passwdfile_chk_hex_64','saved reference password file (hexadecimal, 64 chars)'),
-		('ref_passwdfile_chk_bip39_12','saved reference password file (BIP39, 12 words)'),
-		('ref_passwdfile_chk_bip39_18','saved reference password file (BIP39, 18 words)'),
-		('ref_passwdfile_chk_bip39_24','saved reference password file (BIP39, 24 words)'),
-		('ref_passwdfile_chk_xmrseed_25','saved reference password file (Monero new-style mnemonic, 25 words)'),
-		('ref_passwdfile_chk_hex2bip39_12','saved reference password file (hex-to-BIP39, 12 words)'),
+		('ref_words_to_subwallet_chk1',     'subwallet generation from reference words file (long subseed)'),
+		('ref_words_to_subwallet_chk2',     'subwallet generation from reference words file (short subseed)'),
+		('ref_subwallet_addrgen1',          'subwallet address file generation (long subseed)'),
+		('ref_subwallet_addrgen2',          'subwallet address file generation (short subseed)'),
+		('ref_subwallet_keygen1',           'subwallet key-address file generation (long subseed)'),
+		('ref_subwallet_keygen2',           'subwallet key-address file generation (short subseed)'),
+		('ref_addrfile_chk',                'saved reference address file'),
+		('ref_segwitaddrfile_chk',          'saved reference address file (segwit)'),
+		('ref_bech32addrfile_chk',          'saved reference address file (bech32)'),
+		('ref_keyaddrfile_chk',             'saved reference key-address file'),
+
+		('ref_passwdfile_chk_b58_20',       'saved reference password file (base58, 20 chars)'),
+		('ref_passwdfile_chk_b58_10',       'saved reference password file (base58, 10 chars)'),
+		('ref_passwdfile_chk_b32_24',       'saved reference password file (base32, 24 chars)'),
+		('ref_passwdfile_chk_b32_12',       'saved reference password file (base32, 12 chars)'),
+		('ref_passwdfile_chk_hex_32',       'saved reference password file (hexadecimal, 32 chars)'),
+		('ref_passwdfile_chk_hex_48',       'saved reference password file (hexadecimal, 48 chars)'),
+		('ref_passwdfile_chk_hex_64',       'saved reference password file (hexadecimal, 64 chars)'),
+		('ref_passwdfile_chk_bip39_12',     'saved reference password file (BIP39, 12 words)'),
+		('ref_passwdfile_chk_bip39_18',     'saved reference password file (BIP39, 18 words)'),
+		('ref_passwdfile_chk_bip39_24',     'saved reference password file (BIP39, 24 words)'),
+		('ref_passwdfile_chk_xmrseed_25',   'saved reference password file (Monero new-style mnemonic, 25 words)'),
+		('ref_passwdfile_chk_hex2bip39_12', 'saved reference password file (hex-to-BIP39, 12 words)'),
 
 #	Create the fake inputs:
 #	('txcreate8',          'transaction creation (8)'),
-		('ref_tx_chk',         'signing saved reference tx file'),
-		('ref_brain_chk_spc3', 'saved brainwallet (non-standard spacing)'),
-		('ref_dieroll_chk_seedtruncate','saved dieroll wallet with extra entropy bits'),
-		('ref_tool_decrypt',   'decryption of saved MMGen-encrypted file'),
+		('ref_tx_chk',                   'signing saved reference tx file'),
+		('ref_brain_chk_spc3',           'saved brainwallet (non-standard spacing)'),
+		('ref_dieroll_chk_seedtruncate', 'saved dieroll wallet with extra entropy bits'),
+		('ref_tool_decrypt',             'decryption of saved MMGen-encrypted file'),
 	)
 
 	@property
 	def nw_desc(self):
 		return '{} {}'.format(
 			self.proto.coin,
-			('Mainnet','Testnet')[self.proto.testnet] )
+			('Mainnet','Testnet')[self.proto.testnet])
 
 	def _get_ref_subdir_by_coin(self,coin):
-		return {'btc': '',
-				'bch': '',
-				'ltc': 'litecoin',
-				'eth': 'ethereum',
-				'etc': 'ethereum_classic',
-				'xmr': 'monero',
-				'zec': 'zcash',
-				'dash': 'dash' }[coin.lower()]
+		return {
+			'btc':  '',
+			'bch':  '',
+			'ltc':  'litecoin',
+			'eth':  'ethereum',
+			'etc':  'ethereum_classic',
+			'xmr':  'monero',
+			'zec':  'zcash',
+			'dash': 'dash'
+		}[coin.lower()]
 
 	@property
 	def ref_subdir(self):
@@ -183,10 +198,10 @@ class CmdTestRef(CmdTestBase,CmdTestShared):
 	def ref_words_to_subwallet_chk2(self):
 		return self.ref_words_to_subwallet_chk('1S')
 
-	def ref_words_to_subwallet_chk(self,ss_idx):
+	def ref_words_to_subwallet_chk(self, ss_idx):
 		wf = dfl_words_file
 		ocls = get_wallet_cls('words')
-		args = ['-d',self.tr.trash_dir,'-o',ocls.fmt_codes[-1],wf,ss_idx]
+		args = ['-d', self.tr.trash_dir, '-o', ocls.fmt_codes[-1], wf, ss_idx]
 
 		t = self.spawn(
 			'mmgen-subwalletgen',
@@ -196,7 +211,7 @@ class CmdTestRef(CmdTestBase,CmdTestShared):
 		t.expect(f'Generating subseed {ss_idx}')
 		chk_sid = self.chk_data['ref_subwallet_sid'][f'98831F3A:{ss_idx}']
 		fn = t.written_to_file(capfirst(ocls.desc))
-		assert chk_sid in fn,f'incorrect filename: {fn} (does not contain {chk_sid})'
+		assert chk_sid in fn, f'incorrect filename: {fn} (does not contain {chk_sid})'
 		ok()
 
 		t = self.spawn(
@@ -204,22 +219,22 @@ class CmdTestRef(CmdTestBase,CmdTestShared):
 			self.testnet_opt + [fn],
 			extra_desc       = '(check subwallet)',
 			no_passthru_opts = True)
-		t.expect(r'Valid MMGen native mnemonic data for Seed ID ([0-9A-F]*)\b',regex=True)
+		t.expect(r'Valid MMGen native mnemonic data for Seed ID ([0-9A-F]*)\b', regex=True)
 		sid = t.p.match.group(1)
-		assert sid == chk_sid,f'subseed ID {sid} does not match expected value {chk_sid}'
+		assert sid == chk_sid, f'subseed ID {sid} does not match expected value {chk_sid}'
 		return t
 
-	def ref_subwallet_addrgen(self,ss_idx,target='addr'):
+	def ref_subwallet_addrgen(self, ss_idx, target='addr'):
 		wf = dfl_words_file
-		args = ['-d',self.tr.trash_dir,'--subwallet='+ss_idx,wf,'1-10']
-		t = self.spawn(f'mmgen-{target}gen',args)
+		args = ['-d', self.tr.trash_dir, '--subwallet='+ss_idx, wf, '1-10']
+		t = self.spawn(f'mmgen-{target}gen', args)
 		t.expect(f'Generating subseed {ss_idx}')
 		chk_sid = self.chk_data['ref_subwallet_sid'][f'98831F3A:{ss_idx}']
-		assert chk_sid == t.expect_getend('Checksum for .* data ',regex=True)[:8]
+		assert chk_sid == t.expect_getend('Checksum for .* data ', regex=True)[:8]
 		if target == 'key':
-			t.expect('Encrypt key list? (y/N): ','n')
-		fn = t.written_to_file(('Addresses','Secret keys')[target=='key'])
-		assert chk_sid in fn,f'incorrect filename: {fn} (does not contain {chk_sid})'
+			t.expect('Encrypt key list? (y/N): ', 'n')
+		fn = t.written_to_file(('Addresses', 'Secret keys')[target=='key'])
+		assert chk_sid in fn, f'incorrect filename: {fn} (does not contain {chk_sid})'
 		return t
 
 	def ref_subwallet_addrgen1(self):
@@ -229,10 +244,10 @@ class CmdTestRef(CmdTestBase,CmdTestShared):
 		return self.ref_subwallet_addrgen('1S')
 
 	def ref_subwallet_keygen1(self):
-		return self.ref_subwallet_addrgen('32L',target='key')
+		return self.ref_subwallet_addrgen('32L', target='key')
 
 	def ref_subwallet_keygen2(self):
-		return self.ref_subwallet_addrgen('1S',target='key')
+		return self.ref_subwallet_addrgen('1S', target='key')
 
 	def ref_addrfile_chk(
 			self,
@@ -246,90 +261,90 @@ class CmdTestRef(CmdTestBase,CmdTestShared):
 
 		pat = pat or f'{self.nw_desc}.*Legacy'
 		af_key = f'ref_{ftype}file' + ('_' + id_key if id_key else '')
-		af_fn = CmdTestRef.sources[af_key].format(pfx or self.altcoin_pfx,'' if coin else self.tn_ext)
-		af = joinpath(ref_dir,(subdir or self.ref_subdir,'')[ftype=='passwd'],af_fn)
+		af_fn = CmdTestRef.sources[af_key].format(pfx or self.altcoin_pfx, '' if coin else self.tn_ext)
+		af = joinpath(ref_dir, (subdir or self.ref_subdir, '')[ftype=='passwd'], af_fn)
 		coin_arg = [] if coin is None else ['--coin='+coin]
-		tool_cmd = ftype.replace('segwit','').replace('bech32','')+'file_chksum'
-		t = self.spawn( 'mmgen-tool', coin_arg + ['--verbose','-p1',tool_cmd,af] )
+		tool_cmd = ftype.replace('segwit', '').replace('bech32', '')+'file_chksum'
+		t = self.spawn('mmgen-tool', coin_arg + ['--verbose', '-p1', tool_cmd, af])
 		if ftype == 'keyaddr':
-			t.do_decrypt_ka_data(pw=ref_kafile_pass,have_yes_opt=True)
-		chksum_key = '_'.join([af_key,'chksum'] + ([coin.lower()] if coin else []) + ([mmtype] if mmtype else []))
+			t.do_decrypt_ka_data(pw=ref_kafile_pass, have_yes_opt=True)
+		chksum_key = '_'.join([af_key, 'chksum'] + ([coin.lower()] if coin else []) + ([mmtype] if mmtype else []))
 		rc = self.chk_data[chksum_key]
 		ref_chksum = rc if (ftype == 'passwd' or coin) else rc[self.proto.base_coin.lower()][self.proto.testnet]
 		if pat:
-			t.expect(pat,regex=True)
-		t.expect(chksum_pat,regex=True)
+			t.expect(pat, regex=True)
+		t.expect(chksum_pat, regex=True)
 		m = t.p.match.group(0)
-		cmp_or_die(ref_chksum,m)
+		cmp_or_die(ref_chksum, m)
 		return t
 
 	def ref_segwitaddrfile_chk(self):
 		if not 'S' in self.proto.mmtypes:
 			return skip(f'not supported by {self.proto.cls_name} protocol')
-		return self.ref_addrfile_chk(ftype='segwitaddr',pat=f'{self.nw_desc}.*Segwit')
+		return self.ref_addrfile_chk(ftype='segwitaddr', pat=f'{self.nw_desc}.*Segwit')
 
 	def ref_bech32addrfile_chk(self):
 		if not 'B' in self.proto.mmtypes:
 			return skip(f'not supported by {self.proto.cls_name} protocol')
-		return self.ref_addrfile_chk(ftype='bech32addr',pat=f'{self.nw_desc}.*Bech32')
+		return self.ref_addrfile_chk(ftype='bech32addr', pat=f'{self.nw_desc}.*Bech32')
 
 	def ref_keyaddrfile_chk(self):
 		return self.ref_addrfile_chk(ftype='keyaddr')
 
-	def ref_passwdfile_chk(self,key,pat):
-		return self.ref_addrfile_chk(ftype='passwd',id_key=key,pat=pat)
+	def ref_passwdfile_chk(self, key, pat):
+		return self.ref_addrfile_chk(ftype='passwd', id_key=key, pat=pat)
 
 	def ref_passwdfile_chk_b58_20(self):
-		return self.ref_passwdfile_chk(key='b58_20',pat=r'Base58.*len.* 20\b')
+		return self.ref_passwdfile_chk(key='b58_20', pat=r'Base58.*len.* 20\b')
 	def ref_passwdfile_chk_b58_10(self):
-		return self.ref_passwdfile_chk(key='b58_10',pat=r'Base58.*len.* 10\b')
+		return self.ref_passwdfile_chk(key='b58_10', pat=r'Base58.*len.* 10\b')
 	def ref_passwdfile_chk_b32_24(self):
-		return self.ref_passwdfile_chk(key='b32_24',pat=r'Base32.*len.* 24\b')
+		return self.ref_passwdfile_chk(key='b32_24', pat=r'Base32.*len.* 24\b')
 	def ref_passwdfile_chk_b32_12(self):
-		return self.ref_passwdfile_chk(key='b32_12',pat=r'Base32.*len.* 12\b')
+		return self.ref_passwdfile_chk(key='b32_12', pat=r'Base32.*len.* 12\b')
 	def ref_passwdfile_chk_hex_32(self):
-		return self.ref_passwdfile_chk(key='hex_32',pat=r'Hexadec.*len.* 32\b')
+		return self.ref_passwdfile_chk(key='hex_32', pat=r'Hexadec.*len.* 32\b')
 	def ref_passwdfile_chk_hex_48(self):
-		return self.ref_passwdfile_chk(key='hex_48',pat=r'Hexadec.*len.* 48\b')
+		return self.ref_passwdfile_chk(key='hex_48', pat=r'Hexadec.*len.* 48\b')
 	def ref_passwdfile_chk_hex_64(self):
-		return self.ref_passwdfile_chk(key='hex_64',pat=r'Hexadec.*len.* 64\b')
+		return self.ref_passwdfile_chk(key='hex_64', pat=r'Hexadec.*len.* 64\b')
 	def ref_passwdfile_chk_bip39_12(self):
-		return self.ref_passwdfile_chk(key='bip39_12',pat=r'BIP39.*len.* 12\b')
+		return self.ref_passwdfile_chk(key='bip39_12', pat=r'BIP39.*len.* 12\b')
 	def ref_passwdfile_chk_bip39_18(self):
-		return self.ref_passwdfile_chk(key='bip39_18',pat=r'BIP39.*len.* 18\b')
+		return self.ref_passwdfile_chk(key='bip39_18', pat=r'BIP39.*len.* 18\b')
 	def ref_passwdfile_chk_bip39_24(self):
-		return self.ref_passwdfile_chk(key='bip39_24',pat=r'BIP39.*len.* 24\b')
+		return self.ref_passwdfile_chk(key='bip39_24', pat=r'BIP39.*len.* 24\b')
 	def ref_passwdfile_chk_xmrseed_25(self):
-		return self.ref_passwdfile_chk(key='xmrseed_25',pat=r'Mon.*len.* 25\b')
+		return self.ref_passwdfile_chk(key='xmrseed_25', pat=r'Mon.*len.* 25\b')
 	def ref_passwdfile_chk_hex2bip39_12(self):
-		return self.ref_passwdfile_chk(key='hex2bip39_12',pat=r'BIP39.*len.* 12\b')
+		return self.ref_passwdfile_chk(key='hex2bip39_12', pat=r'BIP39.*len.* 12\b')
 
 	def ref_tx_chk(self):
 		fn = self.sources['ref_tx_file'][self.coin][bool(self.tn_ext)]
 		if not fn:
 			return
-		tf = joinpath(ref_dir,self.ref_subdir,fn)
+		tf = joinpath(ref_dir, self.ref_subdir, fn)
 		wf = dfl_words_file
-		self.write_to_tmpfile(pwfile,wpasswd)
-		return self.txsign(wf,tf,save=False,has_label=True,view='y')
+		self.write_to_tmpfile(pwfile, wpasswd)
+		return self.txsign(wf, tf, save=False, has_label=True, view='y')
 
 	def ref_brain_chk_spc3(self):
 		return self.ref_brain_chk(bw_file=ref_bw_file_spc)
 
 	def ref_dieroll_chk_seedtruncate(self):
-		wf = joinpath(ref_dir,'overflow128.b6d')
-		return self.walletchk(wf,sid='8EC6D4A2')
+		wf = joinpath(ref_dir, 'overflow128.b6d')
+		return self.walletchk(wf, sid='8EC6D4A2')
 
 	def ref_tool_decrypt(self):
-		f = joinpath(ref_dir,ref_enc_fn)
-		dec_file = joinpath(self.tmpdir,'famous.txt')
+		f = joinpath(ref_dir, ref_enc_fn)
+		dec_file = joinpath(self.tmpdir, 'famous.txt')
 		t = self.spawn(
 			'mmgen-tool',
-			['-q','decrypt',f,'outfile='+dec_file,'hash_preset=1'],
-			env = os.environ if cfg.debug_utf8 else get_env_without_debug_vars() )
-		t.passphrase('data',tool_enc_passwd)
+			['-q', 'decrypt', f, 'outfile='+dec_file, 'hash_preset=1'],
+			env = os.environ if cfg.debug_utf8 else get_env_without_debug_vars())
+		t.passphrase('data', tool_enc_passwd)
 		t.written_to_file('Decrypted data')
 		dec_txt = read_from_file(dec_file)
 		imsg_r(dec_txt)
-		cmp_or_die(sample_text+'\n',dec_txt) # file adds a newline to sample_text
+		cmp_or_die(sample_text+'\n', dec_txt) # file adds a newline to sample_text
 		return t

+ 119 - 119
test/cmdtest_py_d/ct_ref_3seed.py

@@ -23,10 +23,10 @@ test.cmdtest_py_d.ct_ref_3seed: Saved and generated reference file tests for 128
 
 import os
 
-from mmgen.util import msg,capfirst
+from mmgen.util import msg, capfirst
 from mmgen.wallet import get_wallet_cls
 
-from ..include.common import cfg,cmp_or_die,joinpath
+from ..include.common import cfg, cmp_or_die, joinpath
 from .common import (
 	pwfile,
 	ref_wallet_hash_preset,
@@ -39,66 +39,66 @@ from .ct_base import CmdTestBase
 from .ct_shared import CmdTestShared
 from .ct_wallet import CmdTestWalletConv
 
-class CmdTestRef3Seed(CmdTestBase,CmdTestShared):
+class CmdTestRef3Seed(CmdTestBase, CmdTestShared):
 	'saved wallet files for 128-, 192- and 256-bit seeds + generated filename checks'
 	networks = ('btc',)
 	mmtypes = (None,)
-	tmpdir_nums = [6,7,8]
+	tmpdir_nums = [6, 7, 8]
 	addr_idx_list_in = '1010,500-501,31-33,1,33,500,1011'
 	pass_idx_list_in = '1,4,9-11,1100'
 	chk_data = {
 		'lens': (128, 192, 256),
 		'sids': ('FE3C6545', '1378FC64', '98831F3A'),
 	}
-	shared_deps = ['mmdat',pwfile]
+	shared_deps = ['mmdat', pwfile]
 	skip_cmds = (
 		'ref_xmrseed_25_passwdgen_1',
 		'ref_xmrseed_25_passwdgen_2',
 	)
 	cmd_group = (
 		# reading saved reference wallets
-		('ref_wallet_chk',  ([],'saved reference wallet')),
-		('ref_seed_chk',    ([],'saved seed file')),
-		('ref_hex_chk',     ([],'saved mmhex file')),
-		('ref_plainhex_chk',([],'saved hex file')),
-		('ref_dieroll_chk', ([],'saved dieroll (b6d) file')),
-		('ref_mn_chk',      ([],'saved native MMGen mnemonic file')),
-		('ref_bip39_chk',   ([],'saved BIP39 mnemonic file')),
-		('ref_hincog_chk',  ([],'saved hidden incog reference wallet')),
-		('ref_brain_chk',   ([],'saved brainwallet')), # in ct_shared
+		('ref_wallet_chk',   ([], 'saved reference wallet')),
+		('ref_seed_chk',     ([], 'saved seed file')),
+		('ref_hex_chk',      ([], 'saved mmhex file')),
+		('ref_plainhex_chk', ([], 'saved hex file')),
+		('ref_dieroll_chk',  ([], 'saved dieroll (b6d) file')),
+		('ref_mn_chk',       ([], 'saved native MMGen mnemonic file')),
+		('ref_bip39_chk',    ([], 'saved BIP39 mnemonic file')),
+		('ref_hincog_chk',   ([], 'saved hidden incog reference wallet')),
+		('ref_brain_chk',    ([], 'saved brainwallet')),                    # in ct_shared
 
 		# generating new reference ('abc' brainwallet) wallets for filename checks:
-		('ref_walletgen_brain',        ([],'generating new reference wallet + filename check (brain)')),
-		('ref_walletconv_words',       ([],'wallet filename (native mnemonic)')),
-		('ref_walletconv_bip39',       ([],'wallet filename (bip39)')),
-		('ref_walletconv_seed',        ([],'wallet filename (seed)')),
-		('ref_walletconv_hexseed',     ([],'wallet filename (hex seed)')),
-		('ref_walletconv_plainhexseed',([],'wallet filename (plain hex seed)')),
-		('ref_walletconv_dieroll',     ([],'wallet filename (dieroll (b6d) seed)')),
-		('ref_walletconv_incog',       ([],'wallet filename (incog)')),
-		('ref_walletconv_hexincog',    ([],'wallet filename (hex incog)')),
+		('ref_walletgen_brain',         ([], 'generating new reference wallet + filename check (brain)')),
+		('ref_walletconv_words',        ([], 'wallet filename (native mnemonic)')),
+		('ref_walletconv_bip39',        ([], 'wallet filename (bip39)')),
+		('ref_walletconv_seed',         ([], 'wallet filename (seed)')),
+		('ref_walletconv_hexseed',      ([], 'wallet filename (hex seed)')),
+		('ref_walletconv_plainhexseed', ([], 'wallet filename (plain hex seed)')),
+		('ref_walletconv_dieroll',      ([], 'wallet filename (dieroll (b6d) seed)')),
+		('ref_walletconv_incog',        ([], 'wallet filename (incog)')),
+		('ref_walletconv_hexincog',     ([], 'wallet filename (hex incog)')),
 	)
 
-	def __init__(self,trunner,cfgs,spawn):
-		for k,_ in self.cmd_group:
-			for n in (1,2,3): # 128,192,256 bits
-				setattr(self,f'{k}_{n}',getattr(self,k))
+	def __init__(self, trunner, cfgs, spawn):
+		for k, _ in self.cmd_group:
+			for n in (1, 2, 3): # 128, 192, 256 bits
+				setattr(self, f'{k}_{n}', getattr(self, k))
 		if cfgs:
 			for n in self.tmpdir_nums:
 				cfgs[str(n)]['addr_idx_list'] = self.addr_idx_list_in
 				cfgs[str(n)]['pass_idx_list'] = self.pass_idx_list_in
-		CmdTestBase.__init__(self,trunner,cfgs,spawn)
+		CmdTestBase.__init__(self, trunner, cfgs, spawn)
 
 	def ref_wallet_chk(self):
-		wf = joinpath(ref_dir,CmdTestWalletConv.sources[str(self.seed_len)]['ref_wallet'])
-		return self.walletchk(wf,sid=self.seed_id)
+		wf = joinpath(ref_dir, CmdTestWalletConv.sources[str(self.seed_len)]['ref_wallet'])
+		return self.walletchk(wf, sid=self.seed_id)
 
-	def ref_ss_chk(self,ss_type):
+	def ref_ss_chk(self, ss_type):
 		ss = get_wallet_cls(ss_type)
 		return self.walletchk(
-			wf   = joinpath(ref_dir,f'{self.seed_id}.{ss.ext}'),
+			wf   = joinpath(ref_dir, f'{self.seed_id}.{ss.ext}'),
 			wcls = ss,
-			sid  = self.seed_id )
+			sid  = self.seed_id)
 
 	def ref_seed_chk(self):
 		return self.ref_ss_chk('seed')
@@ -118,14 +118,14 @@ class CmdTestRef3Seed(CmdTestBase,CmdTestShared):
 	def ref_bip39_chk(self):
 		return self.ref_ss_chk('bip39')
 
-	def ref_hincog_chk(self,desc='hidden incognito data'):
+	def ref_hincog_chk(self, desc='hidden incognito data'):
 		source = CmdTestWalletConv.sources[str(self.seed_len)]
-		for wtype,edesc,of_arg in (
-				('hic_wallet',    '',            []),
-				('hic_wallet_old','(old format)',['-O']) ):
+		for wtype, edesc, of_arg in (
+				('hic_wallet',     '',             []),
+				('hic_wallet_old', '(old format)', ['-O'])):
 			ic_arg = ['-H{},{}'.format(
-				joinpath(ref_dir,source[wtype]),
-				ref_wallet_incog_offset )
+				joinpath(ref_dir, source[wtype]),
+				ref_wallet_incog_offset)
 			]
 			slarg = [f'-l{self.seed_len} ']
 			hparg = ['-p1']
@@ -134,11 +134,11 @@ class CmdTestRef3Seed(CmdTestBase,CmdTestShared):
 			t = self.spawn('mmgen-walletchk',
 				slarg + hparg + of_arg + ic_arg,
 				extra_desc=edesc)
-			t.passphrase(desc,self.wpasswd+'\n')
+			t.passphrase(desc, self.wpasswd+'\n')
 			if wtype == 'hic_wallet_old':
-				t.expect('Is the Seed ID correct? (Y/n): ','\n')
+				t.expect('Is the Seed ID correct? (Y/n): ', '\n')
 			chk = t.expect_getend('Seed ID: ')
-			cmp_or_die(self.seed_id,chk)
+			cmp_or_die(self.seed_id, chk)
 			ok_msg()
 		t.skip_ok = True
 		return t
@@ -148,14 +148,14 @@ class CmdTestRef3Seed(CmdTestBase,CmdTestShared):
 		hp_arg = f'-p{ref_wallet_hash_preset}'
 		label = f'ref. wallet (pw {ref_wallet_brainpass!r}, seed len {self.seed_len}) α'
 		bf = 'ref.mmbrain'
-		args = ['-d',self.tmpdir,hp_arg,sl_arg,'-ibw','-L',label]
-		self.write_to_tmpfile(bf,ref_wallet_brainpass)
-		self.write_to_tmpfile(pwfile,self.wpasswd)
+		args = ['-d', self.tmpdir, hp_arg, sl_arg, '-ibw', '-L', label]
+		self.write_to_tmpfile(bf, ref_wallet_brainpass)
+		self.write_to_tmpfile(pwfile, self.wpasswd)
 		t = self.spawn('mmgen-walletconv', self.testnet_opt + args + [self.usr_rand_arg], no_passthru_opts=True)
 		t.license()
 		t.expect('Enter brainwallet: ', ref_wallet_brainpass+'\n')
 		ocls = get_wallet_cls('mmgen')
-		t.passphrase_new('new '+ocls.desc,self.wpasswd)
+		t.passphrase_new('new '+ocls.desc, self.wpasswd)
 		t.usr_rand(self.usr_rand_chars)
 		fn = os.path.split(t.written_to_file(capfirst(ocls.desc)))[-1]
 		import re
@@ -164,15 +164,15 @@ class CmdTestRef3Seed(CmdTestBase,CmdTestShared):
 			self.chk_data['sids'][idx],
 			self.chk_data['lens'][idx],
 			'-α' if cfg.debug_utf8 else '')
-		assert re.match(pat,fn), f'{pat} != {fn}'
+		assert re.match(pat, fn), f'{pat} != {fn}'
 		sid = os.path.basename(fn.split('-')[0])
-		cmp_or_die(sid,self.seed_id,desc='Seed ID')
+		cmp_or_die(sid, self.seed_id, desc='Seed ID')
 		return t
 
-	def ref_walletconv(self,ofmt,extra_args=[],re_pat=None):
+	def ref_walletconv(self, ofmt, extra_args=[], re_pat=None):
 		wf = self.get_file_with_ext('mmdat')
-		pf = joinpath(self.tmpdir,pwfile)
-		t = self.spawn('mmgen-walletconv',extra_args+['-d','test/trash','-o',ofmt,'-P'+pf,wf])
+		pf = joinpath(self.tmpdir, pwfile)
+		t = self.spawn('mmgen-walletconv', extra_args+['-d', 'test/trash', '-o', ofmt, '-P'+pf, wf])
 		wcls = get_wallet_cls(fmt_code=ofmt)
 		fn = os.path.split(t.written_to_file(capfirst(wcls.desc)))[-1]
 		idx = int(self.test_name[-1]) - 1
@@ -180,15 +180,15 @@ class CmdTestRef3Seed(CmdTestBase,CmdTestShared):
 		slen = self.chk_data['lens'][idx]
 		if re_pat:
 			import re
-			pat = re_pat.format(sid,slen)
-			assert re.match(pat,fn), f'{pat} != {fn}'
+			pat = re_pat.format(sid, slen)
+			assert re.match(pat, fn), f'{pat} != {fn}'
 		else:
 			cmp_or_die('{}[{}]{}.{}'.format(
 				sid,
 				slen,
 				'-α' if cfg.debug_utf8 else '',
 				wcls.ext),
-				fn )
+				fn)
 		return t
 
 	def ref_walletconv_words(self):
@@ -204,13 +204,13 @@ class CmdTestRef3Seed(CmdTestBase,CmdTestShared):
 	def ref_walletconv_dieroll(self):
 		return self.ref_walletconv(ofmt='dieroll')
 
-	def ref_walletconv_incog(self,ofmt='incog',ext='mmincog'):
-		args = ['-r0','-p1']
+	def ref_walletconv_incog(self, ofmt='incog', ext='mmincog'):
+		args = ['-r0', '-p1']
 		pat = r'{}-[0-9A-F]{{8}}-[0-9A-F]{{8}}\[{},1\]' + ('-α' if cfg.debug_utf8 else '') + '.' + ext
-		return self.ref_walletconv(ofmt=ofmt,extra_args=args,re_pat=pat)
+		return self.ref_walletconv(ofmt=ofmt, extra_args=args, re_pat=pat)
 
 	def ref_walletconv_hexincog(self):
-		return self.ref_walletconv_incog(ofmt='incog_hex',ext='mmincox')
+		return self.ref_walletconv_incog(ofmt='incog_hex', ext='mmincox')
 
 class CmdTestRef3Addr(CmdTestRef3Seed):
 	'generated reference address and key-address files for 128-, 192- and 256-bit seeds'
@@ -223,112 +223,112 @@ class CmdTestRef3Addr(CmdTestRef3Seed):
 		'lens': (128, 192, 256),
 		'sids': ('FE3C6545', '1378FC64', '98831F3A'),
 		'refaddrgen_legacy_1': {
-			'btc': ('B230 7526 638F 38CB','A9DC 5A13 12CB 1317'),
-			'bch': ('026D AFE0 8C60 6CFF','B406 4937 D884 6E48'),
-			'ltc': ('2B23 5E97 848A B961','AEC3 E774 0B21 0202'),
+			'btc': ('B230 7526 638F 38CB', 'A9DC 5A13 12CB 1317'),
+			'bch': ('026D AFE0 8C60 6CFF', 'B406 4937 D884 6E48'),
+			'ltc': ('2B23 5E97 848A B961', 'AEC3 E774 0B21 0202'),
 		},
 		'refaddrgen_segwit_1': {
-			'btc': ('9914 6D10 2307 F348','83C8 A6B6 ADA8 25B2'),
-			'ltc': ('CC09 A190 B7DF B7CD','0425 7893 C6F1 ECA3'),
+			'btc': ('9914 6D10 2307 F348', '83C8 A6B6 ADA8 25B2'),
+			'ltc': ('CC09 A190 B7DF B7CD', '0425 7893 C6F1 ECA3'),
 		},
 		'refaddrgen_bech32_1': {
-			'btc': ('C529 D686 31AA ACD4','21D0 26AD 3A22 5465'),
-			'ltc': ('3DFB CFCC E180 DC9D','8C72 D5C2 07E0 5F7B'),
+			'btc': ('C529 D686 31AA ACD4', '21D0 26AD 3A22 5465'),
+			'ltc': ('3DFB CFCC E180 DC9D', '8C72 D5C2 07E0 5F7B'),
 		},
 		'refaddrgen_compressed_1': {
-			'btc': ('95EB 8CC0 7B3B 7856','16E6 6170 154D 2202'),
-			'bch': ('C560 A343 CEAB 118E','3F56 8DC5 0383 CD78'),
-			'ltc': ('35D5 8ECA 9A42 46C3','15B3 5492 D3D3 6854'),
+			'btc': ('95EB 8CC0 7B3B 7856', '16E6 6170 154D 2202'),
+			'bch': ('C560 A343 CEAB 118E', '3F56 8DC5 0383 CD78'),
+			'ltc': ('35D5 8ECA 9A42 46C3', '15B3 5492 D3D3 6854'),
 		},
 		'refkeyaddrgen_legacy_1': {
-			'btc': ('CF83 32FB 8A8B 08E2','1F67 B73A FF8C 5D15'),
-			'bch': ('6909 4C64 119A 7681','7E48 5071 5E41 D1AE'),
-			'ltc': ('1896 A26C 7F14 2D01','FA0E CD4E ADAF DBF4'),
+			'btc': ('CF83 32FB 8A8B 08E2', '1F67 B73A FF8C 5D15'),
+			'bch': ('6909 4C64 119A 7681', '7E48 5071 5E41 D1AE'),
+			'ltc': ('1896 A26C 7F14 2D01', 'FA0E CD4E ADAF DBF4'),
 		},
 		'refkeyaddrgen_compressed_1': {
-			'btc': ('E43A FA46 5751 720A','FDEE 8E45 1C0A 02AD'),
-			'bch': ('7068 9B37 8ABF 3E31','C688 29A5 BA4C 21B2'),
-			'ltc': ('7603 2FE3 2145 FFAD','3FE0 5A8E 5FBE FF3E'),
+			'btc': ('E43A FA46 5751 720A', 'FDEE 8E45 1C0A 02AD'),
+			'bch': ('7068 9B37 8ABF 3E31', 'C688 29A5 BA4C 21B2'),
+			'ltc': ('7603 2FE3 2145 FFAD', '3FE0 5A8E 5FBE FF3E'),
 		},
 		'refkeyaddrgen_segwit_1': {
-			'btc': ('C13B F717 D4E8 CF59','BB71 175C 5416 19D8'),
-			'ltc': ('054B 9794 55B4 5D82','DE85 3CF3 9636 FE2E'),
+			'btc': ('C13B F717 D4E8 CF59', 'BB71 175C 5416 19D8'),
+			'ltc': ('054B 9794 55B4 5D82', 'DE85 3CF3 9636 FE2E'),
 		},
 		'refkeyaddrgen_bech32_1': {
-			'btc': ('934F 1C33 6C06 B18C','A283 5BAB 7AF3 3EA4'),
-			'ltc': ('A6AD DF53 5968 7B6A','9572 43E0 A4DC 0B2E'),
+			'btc': ('934F 1C33 6C06 B18C', 'A283 5BAB 7AF3 3EA4'),
+			'ltc': ('A6AD DF53 5968 7B6A', '9572 43E0 A4DC 0B2E'),
 		},
 		'refaddrgen_legacy_2': {
-			'btc': ('8C17 A5FA 0470 6E89','764C 66F9 7502 AAEA'),
-			'bch': ('8117 24B6 3FDA 6B40','E58C A8A4 C371 66AE'),
-			'ltc': ('2B77 A009 D5D0 22AD','51D1 979D 0A35 F24B'),
+			'btc': ('8C17 A5FA 0470 6E89', '764C 66F9 7502 AAEA'),
+			'bch': ('8117 24B6 3FDA 6B40', 'E58C A8A4 C371 66AE'),
+			'ltc': ('2B77 A009 D5D0 22AD', '51D1 979D 0A35 F24B'),
 		},
 		'refaddrgen_compressed_2': {
-			'btc': ('2615 8401 2E98 7ECA','A386 EE07 A356 906D'),
-			'bch': ('3364 0F9D 8355 2A53','3451 F741 0A8A FA56'),
-			'ltc': ('197C C48C 3C37 AB0F','8DDC 5FE3 BFF9 1226'),
+			'btc': ('2615 8401 2E98 7ECA', 'A386 EE07 A356 906D'),
+			'bch': ('3364 0F9D 8355 2A53', '3451 F741 0A8A FA56'),
+			'ltc': ('197C C48C 3C37 AB0F', '8DDC 5FE3 BFF9 1226'),
 		},
 		'refaddrgen_segwit_2': {
-			'btc': ('91C4 0414 89E4 2089','BF9F C67F ED22 A47B'),
-			'ltc': ('8F12 FA7B 9F12 594C','2609 8494 A23C F836'),
+			'btc': ('91C4 0414 89E4 2089', 'BF9F C67F ED22 A47B'),
+			'ltc': ('8F12 FA7B 9F12 594C', '2609 8494 A23C F836'),
 		},
 		'refaddrgen_bech32_2': {
-			'btc': ('2AA3 78DF B965 82EB','027B 1C1F 7FB2 D859'),
-			'ltc': ('951C 8FB2 FCA5 87D1','4A5D 67E0 8210 FEF2'),
+			'btc': ('2AA3 78DF B965 82EB', '027B 1C1F 7FB2 D859'),
+			'ltc': ('951C 8FB2 FCA5 87D1', '4A5D 67E0 8210 FEF2'),
 		},
 		'refkeyaddrgen_legacy_2': {
-			'btc': ('9648 5132 B98E 3AD9','1BD3 5A36 D51C 256D'),
-			'bch': ('C4D8 7C36 DC77 F8C2','953D 245C 8CFF AC72'),
-			'ltc': ('DBD4 FAB6 7E46 CD07','8822 3FDF FEC0 6A8C'),
+			'btc': ('9648 5132 B98E 3AD9', '1BD3 5A36 D51C 256D'),
+			'bch': ('C4D8 7C36 DC77 F8C2', '953D 245C 8CFF AC72'),
+			'ltc': ('DBD4 FAB6 7E46 CD07', '8822 3FDF FEC0 6A8C'),
 		},
 		'refkeyaddrgen_compressed_2': {
-			'btc': ('6D6D 3D35 04FD B9C3','94BF 4BCF 10B2 394B'),
-			'bch': ('3E7F C369 2AB9 BD58','0C99 14CD 5ADE 6782'),
-			'ltc': ('F5DA 9D60 6798 C4E9','7918 88DE 9096 DD7A'),
+			'btc': ('6D6D 3D35 04FD B9C3', '94BF 4BCF 10B2 394B'),
+			'bch': ('3E7F C369 2AB9 BD58', '0C99 14CD 5ADE 6782'),
+			'ltc': ('F5DA 9D60 6798 C4E9', '7918 88DE 9096 DD7A'),
 		},
 		'refkeyaddrgen_segwit_2': {
-			'btc': ('C98B DF08 A3D5 204B','7E7F DF50 FE04 6F68'),
-			'ltc': ('1829 7FE7 2567 CB91','BE92 D19C 7589 EF30'),
+			'btc': ('C98B DF08 A3D5 204B', '7E7F DF50 FE04 6F68'),
+			'ltc': ('1829 7FE7 2567 CB91', 'BE92 D19C 7589 EF30'),
 		},
 		'refkeyaddrgen_bech32_2': {
-			'btc': ('4A6B 3762 DF30 9368','12DD 1888 36BA 85F7'),
-			'ltc': ('5C12 FDD4 17AB F179','E195 B28C 59C4 C5EC'),
+			'btc': ('4A6B 3762 DF30 9368', '12DD 1888 36BA 85F7'),
+			'ltc': ('5C12 FDD4 17AB F179', 'E195 B28C 59C4 C5EC'),
 		},
 		'refaddrgen_legacy_3': {
-			'btc': ('6FEF 6FB9 7B13 5D91','424E 4326 CFFE 5F51'),
-			'bch': ('E580 43BB 0F96 AA93','630E 174A 8DDE 1BCE'),
-			'ltc': ('AD52 C3FE 8924 AAF0','4EBE 2E85 E969 1B30'),
+			'btc': ('6FEF 6FB9 7B13 5D91', '424E 4326 CFFE 5F51'),
+			'bch': ('E580 43BB 0F96 AA93', '630E 174A 8DDE 1BCE'),
+			'ltc': ('AD52 C3FE 8924 AAF0', '4EBE 2E85 E969 1B30'),
 		},
 		'refaddrgen_compressed_3': {
-			'btc': ('A33C 4FDE F515 F5BC','6C48 AA57 2056 C8C8'),
-			'bch': ('E37B AF41 7997 A28C','0D5D 9A58 D6E9 92EE'),
-			'ltc': ('3FC0 8F03 C2D6 BD19','4C0A 49B6 2DD1 1BE0'),
+			'btc': ('A33C 4FDE F515 F5BC', '6C48 AA57 2056 C8C8'),
+			'bch': ('E37B AF41 7997 A28C', '0D5D 9A58 D6E9 92EE'),
+			'ltc': ('3FC0 8F03 C2D6 BD19', '4C0A 49B6 2DD1 1BE0'),
 		},
 		'refaddrgen_segwit_3': {
-			'btc': ('06C1 9C87 F25C 4EE6','072C 8B07 2730 CB7A'),
-			'ltc': ('63DF E42A 0827 21C3','5DD1 D186 DBE1 59F2'),
+			'btc': ('06C1 9C87 F25C 4EE6', '072C 8B07 2730 CB7A'),
+			'ltc': ('63DF E42A 0827 21C3', '5DD1 D186 DBE1 59F2'),
 		},
 		'refaddrgen_bech32_3': {
-			'btc': ('9D2A D4B6 5117 F02E','0527 9C39 6C1B E39A'),
-			'ltc': ('FF1C 7939 5967 AB82','ED3D 8AA4 BED4 0B40'),
+			'btc': ('9D2A D4B6 5117 F02E', '0527 9C39 6C1B E39A'),
+			'ltc': ('FF1C 7939 5967 AB82', 'ED3D 8AA4 BED4 0B40'),
 		},
 		'refkeyaddrgen_legacy_3': {
-			'btc': ('9F2D D781 1812 8BAD','88CC 5120 9A91 22C2'),
-			'bch': ('A0EE B039 48F4 24AE','B014 E0AB 5F87 EC64'),
-			'ltc': ('B804 978A 8796 3ED4','98B5 AC35 F334 0398'),
+			'btc': ('9F2D D781 1812 8BAD', '88CC 5120 9A91 22C2'),
+			'bch': ('A0EE B039 48F4 24AE', 'B014 E0AB 5F87 EC64'),
+			'ltc': ('B804 978A 8796 3ED4', '98B5 AC35 F334 0398'),
 		},
 		'refkeyaddrgen_compressed_3': {
-			'btc': ('420A 8EB5 A9E2 7814','F43A CB4A 81F3 F735'),
-			'bch': ('33E7 5C06 88CF 2792','6E09 FF73 B7C8 00D4'),
-			'ltc': ('8D1C 781F EB7F 44BC','05F3 5C68 FD31 FCEF'),
+			'btc': ('420A 8EB5 A9E2 7814', 'F43A CB4A 81F3 F735'),
+			'bch': ('33E7 5C06 88CF 2792', '6E09 FF73 B7C8 00D4'),
+			'ltc': ('8D1C 781F EB7F 44BC', '05F3 5C68 FD31 FCEF'),
 		},
 		'refkeyaddrgen_segwit_3': {
-			'btc': ('A447 12C2 DD14 5A9B','C770 7391 C415 21F9'),
-			'ltc': ('E8A3 9F6E E164 A521','D3D5 BFDD F5D5 20BD'),
+			'btc': ('A447 12C2 DD14 5A9B', 'C770 7391 C415 21F9'),
+			'ltc': ('E8A3 9F6E E164 A521', 'D3D5 BFDD F5D5 20BD'),
 		},
 		'refkeyaddrgen_bech32_3': {
-			'btc': ('D0DD BDE3 87BE 15AE','7552 D70C AAB8 DEAA'),
-			'ltc': ('74A0 7DD5 963B 6326','2CDA A007 4B9F E9A5'),
+			'btc': ('D0DD BDE3 87BE 15AE', '7552 D70C AAB8 DEAA'),
+			'ltc': ('74A0 7DD5 963B 6326', '2CDA A007 4B9F E9A5'),
 		},
 	}
 
@@ -446,7 +446,7 @@ class CmdTestRef3Passwd(CmdTestRef3Seed):
 			no_passthru_opts = True)
 
 	def refpasswdgen(self):
-		return self.pwgen('pass','alice@crypto.org')
+		return self.pwgen('pass', 'alice@crypto.org')
 
 	def refpasswdgen_half(self):
 		return self.pwgen('pass', 'alice@crypto.org', pwlen='h')

+ 91 - 87
test/cmdtest_py_d/ct_ref_altcoin.py

@@ -22,62 +22,60 @@ test.cmdtest_py_d.ct_ref_altcoin: Altcoin reference file tests for the cmdtest.p
 
 from mmgen.color import set_vt100
 
-from .common import pwfile,dfl_wpasswd,ref_dir,dfl_words_file,dfl_addr_idx_list
-from ..include.common import cfg,joinpath,start_test_daemons,stop_test_daemons,cmp_or_die
+from .common import pwfile, dfl_wpasswd, ref_dir, dfl_words_file, dfl_addr_idx_list
+from ..include.common import cfg, joinpath, start_test_daemons, stop_test_daemons, cmp_or_die
 from .ct_ref import CmdTestRef
 from .ct_base import CmdTestBase
 
-class CmdTestRefAltcoin(CmdTestRef,CmdTestBase):
+class CmdTestRefAltcoin(CmdTestRef, CmdTestBase):
 	'saved and generated altcoin reference files'
 	tmpdir_nums = [8]
 	networks = ('btc',)
 	chk_data = {
-		'ref_addrfile_chksum_zec': '903E 7225 DD86 6E01',
-		'ref_addrfile_chksum_zec_z': '9C7A 72DC 3D4A B3AF',
-		'ref_addrfile_chksum_xmr': '4369 0253 AC2C 0E38',
-		'ref_addrfile_chksum_dash':'FBC1 6B6A 0988 4403',
-		'ref_addrfile_chksum_eth': 'E554 076E 7AF6 66A3',
-		'ref_addrfile_chksum_etc': 'E97A D796 B495 E8BC',
-		'ref_keyaddrfile_chksum_zec': 'F05A 5A5C 0C8E 2617',
-		'ref_keyaddrfile_chksum_zec_z': '6B87 9B2D 0D8D 8D1E',
-		'ref_keyaddrfile_chksum_xmr': 'E0D7 9612 3D67 404A',
+		'ref_addrfile_chksum_zec':        '903E 7225 DD86 6E01',
+		'ref_addrfile_chksum_zec_z':      '9C7A 72DC 3D4A B3AF',
+		'ref_addrfile_chksum_xmr':        '4369 0253 AC2C 0E38',
+		'ref_addrfile_chksum_dash':       'FBC1 6B6A 0988 4403',
+		'ref_addrfile_chksum_eth':        'E554 076E 7AF6 66A3',
+		'ref_addrfile_chksum_etc':        'E97A D796 B495 E8BC',
+		'ref_keyaddrfile_chksum_zec':     'F05A 5A5C 0C8E 2617',
+		'ref_keyaddrfile_chksum_zec_z':   '6B87 9B2D 0D8D 8D1E',
+		'ref_keyaddrfile_chksum_xmr':     'E0D7 9612 3D67 404A',
 		'ref_viewkeyaddrfile_chksum_xmr': '40C9 0E61 B743 229C',
-		'ref_keyaddrfile_chksum_dash': 'E83D 2C63 FEA2 4142',
-		'ref_keyaddrfile_chksum_eth': 'E400 70D9 0AE3 C7C2',
-		'ref_keyaddrfile_chksum_etc': 'EF49 967D BD6C FE45',
+		'ref_keyaddrfile_chksum_dash':    'E83D 2C63 FEA2 4142',
+		'ref_keyaddrfile_chksum_eth':     'E400 70D9 0AE3 C7C2',
+		'ref_keyaddrfile_chksum_etc':     'EF49 967D BD6C FE45',
 	}
 	cmd_group = (
-		('ref_altcoin_tx_chk',    'signing saved reference tx files'),
-		('ref_addrfile_gen_eth',  'generate address file (ETH)'),
-		('ref_addrfile_gen_etc',  'generate address file (ETC)'),
-		('ref_addrfile_gen_dash', 'generate address file (DASH)'),
-		('ref_addrfile_gen_zec',  'generate address file (ZEC-T)'),
-		('ref_addrfile_gen_zec_z','generate address file (ZEC-Z)'),
-		('ref_addrfile_gen_xmr',  'generate address file (XMR)'),
-		# we test the unoptimized ed25519 mod in unit_tests.py, so skip this
-#		('ref_addrfile_gen_xmr_slow','generate address file (XMR - unoptimized ed25519 module)'),
-
-		('ref_keyaddrfile_gen_eth',  'generate key-address file (ETH)'),
-		('ref_keyaddrfile_gen_etc',  'generate key-address file (ETC)'),
-		('ref_keyaddrfile_gen_dash', 'generate key-address file (DASH)'),
-		('ref_keyaddrfile_gen_zec',  'generate key-address file (ZEC-T)'),
-		('ref_keyaddrfile_gen_zec_z','generate key-address file (ZEC-Z)'),
-		('ref_keyaddrfile_gen_xmr',  'generate key-address file (XMR)'),
-		('ref_viewkeyaddrfile_gen_xmr','generate viewkey-address file (XMR)'),
-
-		('ref_addrfile_chk_eth', 'reference address file (ETH)'),
-		('ref_addrfile_chk_etc', 'reference address file (ETC)'),
-		('ref_addrfile_chk_dash','reference address file (DASH)'),
-		('ref_addrfile_chk_zec', 'reference address file (ZEC-T)'),
-		('ref_addrfile_chk_zec_z','reference address file (ZEC-Z)'),
-		('ref_addrfile_chk_xmr', 'reference address file (XMR)'),
-
-		('ref_keyaddrfile_chk_eth', 'reference key-address file (ETH)'),
-		('ref_keyaddrfile_chk_etc', 'reference key-address file (ETC)'),
-		('ref_keyaddrfile_chk_dash','reference key-address file (DASH)'),
-		('ref_keyaddrfile_chk_zec', 'reference key-address file (ZEC-T)'),
-		('ref_keyaddrfile_chk_zec_z','reference key-address file (ZEC-Z)'),
-		('ref_keyaddrfile_chk_xmr', 'reference key-address file (XMR)'),
+		('ref_altcoin_tx_chk',          'signing saved reference tx files'),
+		('ref_addrfile_gen_eth',        'generate address file (ETH)'),
+		('ref_addrfile_gen_etc',        'generate address file (ETC)'),
+		('ref_addrfile_gen_dash',       'generate address file (DASH)'),
+		('ref_addrfile_gen_zec',        'generate address file (ZEC-T)'),
+		('ref_addrfile_gen_zec_z',      'generate address file (ZEC-Z)'),
+		('ref_addrfile_gen_xmr',        'generate address file (XMR)'),
+
+		('ref_keyaddrfile_gen_eth',     'generate key-address file (ETH)'),
+		('ref_keyaddrfile_gen_etc',     'generate key-address file (ETC)'),
+		('ref_keyaddrfile_gen_dash',    'generate key-address file (DASH)'),
+		('ref_keyaddrfile_gen_zec',     'generate key-address file (ZEC-T)'),
+		('ref_keyaddrfile_gen_zec_z',   'generate key-address file (ZEC-Z)'),
+		('ref_keyaddrfile_gen_xmr',     'generate key-address file (XMR)'),
+		('ref_viewkeyaddrfile_gen_xmr', 'generate viewkey-address file (XMR)'),
+
+		('ref_addrfile_chk_eth',        'reference address file (ETH)'),
+		('ref_addrfile_chk_etc',        'reference address file (ETC)'),
+		('ref_addrfile_chk_dash',       'reference address file (DASH)'),
+		('ref_addrfile_chk_zec',        'reference address file (ZEC-T)'),
+		('ref_addrfile_chk_zec_z',      'reference address file (ZEC-Z)'),
+		('ref_addrfile_chk_xmr',        'reference address file (XMR)'),
+
+		('ref_keyaddrfile_chk_eth',     'reference key-address file (ETH)'),
+		('ref_keyaddrfile_chk_etc',     'reference key-address file (ETC)'),
+		('ref_keyaddrfile_chk_dash',    'reference key-address file (DASH)'),
+		('ref_keyaddrfile_chk_zec',     'reference key-address file (ZEC-T)'),
+		('ref_keyaddrfile_chk_zec_z',   'reference key-address file (ZEC-Z)'),
+		('ref_keyaddrfile_chk_xmr',     'reference key-address file (XMR)'),
 		('ref_viewkeyaddrfile_chk_xmr', 'reference viewkey-address file (XMR)'),
 	)
 
@@ -87,11 +85,11 @@ class CmdTestRefAltcoin(CmdTestRef,CmdTestBase):
 		Though this basically duplicates the autosign test, here we do everything
 		via the command line, so it's worth doing
 		"""
-		self.write_to_tmpfile(pwfile,dfl_wpasswd)
-		passfile = joinpath(self.tmpdir,pwfile)
+		self.write_to_tmpfile(pwfile, dfl_wpasswd)
+		passfile = joinpath(self.tmpdir, pwfile)
 		from mmgen.tx.file import MMGenTxFile
 		src = CmdTestRef.sources['ref_tx_file']
-		for coin,files in src.items():
+		for coin, files in src.items():
 			if coin == 'mm1':
 				coin = 'eth'
 				token_desc = ':MM1'
@@ -103,14 +101,14 @@ class CmdTestRefAltcoin(CmdTestRef,CmdTestBase):
 				txfile = joinpath(
 					ref_dir,
 					self._get_ref_subdir_by_coin(coin),
-					fn )
-				proto = MMGenTxFile.get_proto(cfg,txfile,quiet_open=True)
+					fn)
+				proto = MMGenTxFile.get_proto(cfg, txfile, quiet_open=True)
 				if proto.sign_mode == 'daemon':
 					start_test_daemons(proto.network_id)
 					set_vt100()
 				t = self.spawn(
 					'mmgen-txsign',
-					['--outdir=test/trash','--yes', f'--passwd-file={passfile}', dfl_words_file, txfile],
+					['--outdir=test/trash', '--yes', f'--passwd-file={passfile}', dfl_words_file, txfile],
 					extra_desc = f'{proto.coin}{token_desc} {proto.network}')
 				t.read()
 				t.ok()
@@ -118,64 +116,71 @@ class CmdTestRefAltcoin(CmdTestRef,CmdTestBase):
 					stop_test_daemons(proto.network_id)
 		return 'ok'
 
-	def ref_altcoin_addrgen(self,coin,mmtype,gen_what='addr',coin_suf='',add_args=[],addr_idx_list=None):
+	def ref_altcoin_addrgen(
+			self,
+			coin,
+			mmtype,
+			gen_what      = 'addr',
+			coin_suf      = '',
+			add_args      = [],
+			addr_idx_list = None):
 		wf = dfl_words_file
 		t = self.spawn(
 				'mmgen-keygen' if 'key' in gen_what else 'mmgen-addrgen',
-				['-Sq','--coin='+coin] +
+				['-Sq', '--coin='+coin] +
 				(['--type='+mmtype] if mmtype else []) +
 				add_args +
-				[wf,addr_idx_list or dfl_addr_idx_list])
+				[wf, addr_idx_list or dfl_addr_idx_list])
 		if 'key' in gen_what:
-			t.expect('Encrypt key list? (y/N): ','N')
-		chk = t.expect_getend(r'.* data checksum for \S*: ',regex=True)
+			t.expect('Encrypt key list? (y/N): ', 'N')
+		chk = t.expect_getend(r'.* data checksum for \S*: ', regex=True)
 		chk_ref = self.chk_data[
 			'ref_{}addrfile_chksum_{}{}'.format(
 				(gen_what if 'key' in gen_what else ''),
 				coin.lower(),
-				coin_suf )
+				coin_suf)
 		]
-		cmp_or_die(chk,chk_ref,desc=f'{gen_what}list data checksum')
+		cmp_or_die(chk, chk_ref, desc=f'{gen_what}list data checksum')
 		return t
 
 	def ref_addrfile_gen_eth(self):
-		return self.ref_altcoin_addrgen(coin='ETH',mmtype='ethereum')
+		return self.ref_altcoin_addrgen(coin='ETH', mmtype='ethereum')
 
 	def ref_addrfile_gen_etc(self):
-		return self.ref_altcoin_addrgen(coin='ETC',mmtype='ethereum')
+		return self.ref_altcoin_addrgen(coin='ETC', mmtype='ethereum')
 
 	def ref_addrfile_gen_dash(self):
-		return self.ref_altcoin_addrgen(coin='DASH',mmtype='compressed')
+		return self.ref_altcoin_addrgen(coin='DASH', mmtype='compressed')
 
 	def ref_addrfile_gen_zec(self):
-		return self.ref_altcoin_addrgen(coin='ZEC',mmtype='compressed')
+		return self.ref_altcoin_addrgen(coin='ZEC', mmtype='compressed')
 
 	def ref_addrfile_gen_zec_z(self):
-		return self.ref_altcoin_addrgen(coin='ZEC',mmtype='zcash_z',coin_suf='_z')
+		return self.ref_altcoin_addrgen(coin='ZEC', mmtype='zcash_z', coin_suf='_z')
 
 	def ref_addrfile_gen_xmr(self):
-		return self.ref_altcoin_addrgen(coin='XMR',mmtype='monero')
+		return self.ref_altcoin_addrgen(coin='XMR', mmtype='monero')
 
 	def ref_addrfile_gen_xmr_slow(self):
-		return self.ref_altcoin_addrgen(coin='XMR',mmtype='monero',add_args=['--keygen-backend=2'])
+		return self.ref_altcoin_addrgen(coin='XMR', mmtype='monero', add_args=['--keygen-backend=2'])
 
 	def ref_keyaddrfile_gen_eth(self):
-		return self.ref_altcoin_addrgen(coin='ETH',mmtype='ethereum',gen_what='key')
+		return self.ref_altcoin_addrgen(coin='ETH', mmtype='ethereum', gen_what='key')
 
 	def ref_keyaddrfile_gen_etc(self):
-		return self.ref_altcoin_addrgen(coin='ETC',mmtype='ethereum',gen_what='key')
+		return self.ref_altcoin_addrgen(coin='ETC', mmtype='ethereum', gen_what='key')
 
 	def ref_keyaddrfile_gen_dash(self):
-		return self.ref_altcoin_addrgen(coin='DASH',mmtype='compressed',gen_what='key')
+		return self.ref_altcoin_addrgen(coin='DASH', mmtype='compressed', gen_what='key')
 
 	def ref_keyaddrfile_gen_zec(self):
-		return self.ref_altcoin_addrgen(coin='ZEC',mmtype='compressed',gen_what='key')
+		return self.ref_altcoin_addrgen(coin='ZEC', mmtype='compressed', gen_what='key')
 
 	def ref_keyaddrfile_gen_zec_z(self):
-		return self.ref_altcoin_addrgen(coin='ZEC',mmtype='zcash_z',coin_suf='_z',gen_what='key')
+		return self.ref_altcoin_addrgen(coin='ZEC', mmtype='zcash_z', coin_suf='_z', gen_what='key')
 
 	def ref_keyaddrfile_gen_xmr(self):
-		return self.ref_altcoin_addrgen(coin='XMR',mmtype='monero',gen_what='key')
+		return self.ref_altcoin_addrgen(coin='XMR', mmtype='monero', gen_what='key')
 
 	def ref_viewkeyaddrfile_gen_xmr(self):
 		return self.ref_altcoin_addrgen(
@@ -183,57 +188,56 @@ class CmdTestRefAltcoin(CmdTestRef,CmdTestBase):
 			mmtype        = 'monero',
 			gen_what      = 'viewkey',
 			add_args      = ['--viewkeys'],
-			addr_idx_list = '1-3' )
+			addr_idx_list = '1-3')
 
 	def ref_addrfile_chk_eth(self):
-		return self.ref_addrfile_chk(ftype='addr',coin='ETH',subdir='ethereum',pfx='-ETH',
+		return self.ref_addrfile_chk(ftype='addr', coin='ETH', subdir='ethereum', pfx='-ETH',
 				pat='ETH Mainnet.*Ethereum')
 
 	def ref_addrfile_chk_etc(self):
-		return self.ref_addrfile_chk(ftype='addr',coin='ETC',subdir='ethereum_classic',pfx='-ETC',
+		return self.ref_addrfile_chk(ftype='addr', coin='ETC', subdir='ethereum_classic', pfx='-ETC',
 				pat='ETH Mainnet.*Ethereum')
 
 	def ref_addrfile_chk_dash(self):
-		return self.ref_addrfile_chk(ftype='addr',coin='DASH',subdir='dash',pfx='-DASH-C',
+		return self.ref_addrfile_chk(ftype='addr', coin='DASH', subdir='dash', pfx='-DASH-C',
 				pat='DASH Mainnet.*Compressed')
 
 	def ref_addrfile_chk_zec(self):
-		return self.ref_addrfile_chk(ftype='addr',coin='ZEC',subdir='zcash',pfx='-ZEC-C',
+		return self.ref_addrfile_chk(ftype='addr', coin='ZEC', subdir='zcash', pfx='-ZEC-C',
 				pat='ZEC Mainnet.*Compressed')
 
 	def ref_addrfile_chk_zec_z(self):
-		return self.ref_addrfile_chk(ftype='addr',coin='ZEC',subdir='zcash',pfx='-ZEC-Z',mmtype='z',
+		return self.ref_addrfile_chk(ftype='addr', coin='ZEC', subdir='zcash', pfx='-ZEC-Z', mmtype='z',
 				pat='ZEC Mainnet.*Zcash_z')
 
 	def ref_addrfile_chk_xmr(self):
-		return self.ref_addrfile_chk(ftype='addr',coin='XMR',subdir='monero',pfx='-XMR-M',
+		return self.ref_addrfile_chk(ftype='addr', coin='XMR', subdir='monero', pfx='-XMR-M',
 				pat='XMR Mainnet.*Monero')
 
-
 	def ref_keyaddrfile_chk_eth(self):
-		return self.ref_addrfile_chk(ftype='keyaddr',coin='ETH',subdir='ethereum',pfx='-ETH',
+		return self.ref_addrfile_chk(ftype='keyaddr', coin='ETH', subdir='ethereum', pfx='-ETH',
 				pat='ETH Mainnet.*Ethereum')
 
 	def ref_keyaddrfile_chk_etc(self):
-		return self.ref_addrfile_chk(ftype='keyaddr',coin='ETC',subdir='ethereum_classic',pfx='-ETC',
+		return self.ref_addrfile_chk(ftype='keyaddr', coin='ETC', subdir='ethereum_classic', pfx='-ETC',
 				pat='ETH Mainnet.*Ethereum')
 
 	def ref_keyaddrfile_chk_dash(self):
-		return self.ref_addrfile_chk(ftype='keyaddr',coin='DASH',subdir='dash',pfx='-DASH-C',
+		return self.ref_addrfile_chk(ftype='keyaddr', coin='DASH', subdir='dash', pfx='-DASH-C',
 				pat='DASH Mainnet.*Compressed')
 
 	def ref_keyaddrfile_chk_zec(self):
-		return self.ref_addrfile_chk(ftype='keyaddr',coin='ZEC',subdir='zcash',pfx='-ZEC-C',
+		return self.ref_addrfile_chk(ftype='keyaddr', coin='ZEC', subdir='zcash', pfx='-ZEC-C',
 				pat='ZEC Mainnet.*Compressed')
 
 	def ref_keyaddrfile_chk_zec_z(self):
-		return self.ref_addrfile_chk(ftype='keyaddr',coin='ZEC',subdir='zcash',pfx='-ZEC-Z',mmtype='z',
+		return self.ref_addrfile_chk(ftype='keyaddr', coin='ZEC', subdir='zcash', pfx='-ZEC-Z', mmtype='z',
 				pat='ZEC Mainnet.*Zcash_z')
 
 	def ref_keyaddrfile_chk_xmr(self):
-		return self.ref_addrfile_chk(ftype='keyaddr',coin='XMR',subdir='monero',pfx='-XMR-M',
+		return self.ref_addrfile_chk(ftype='keyaddr', coin='XMR', subdir='monero', pfx='-XMR-M',
 				pat='XMR Mainnet.*Monero')
 
 	def ref_viewkeyaddrfile_chk_xmr(self):
-		return self.ref_addrfile_chk(ftype='viewkeyaddr',coin='XMR',subdir='monero',pfx='-XMR-M',
+		return self.ref_addrfile_chk(ftype='viewkeyaddr', coin='XMR', subdir='monero', pfx='-XMR-M',
 				pat='XMR Mainnet.*Monero')

File diff suppressed because it is too large
+ 250 - 244
test/cmdtest_py_d/ct_regtest.py


+ 100 - 100
test/cmdtest_py_d/ct_seedsplit.py

@@ -25,7 +25,7 @@ import os
 from mmgen.wallet import get_wallet_cls
 from mmgen.util import capfirst
 
-from ..include.common import strip_ansi_escapes,cmp_or_die
+from ..include.common import strip_ansi_escapes, cmp_or_die
 from .common import get_file_with_ext
 from .ct_base import CmdTestBase
 
@@ -41,85 +41,85 @@ class CmdTestSeedSplit(CmdTestBase):
 	tmpdir_nums = [23]
 	color = True
 	cmd_group = (
-		('ss_walletgen',                'wallet generation'),
-		('ss_2way_A_dfl1',              '2-way seed split (share A)'),
-		('ss_2way_B_dfl1',              '2-way seed split (share B)'),
-		('ss_2way_join_dfl1',           '2-way seed join'),
-		('ss_2way_A_dfl2',              "2-way seed split 'default' (share A)"),
-		('ss_2way_B_dfl2',              "2-way seed split 'default' (share B)"),
-		('ss_2way_join_dfl2',           "2-way seed join 'default'"),
-		('ss_2way_A_alice',             "2-way seed split 'alice' (share A)"),
-		('ss_2way_B_alice',             "2-way seed split 'alice' (share B)"),
-		('ss_2way_join_alice',          "2-way seed join 'alice'"),
-		('ss_2way_join_alice_mix',      "2-way seed join 'alice' (out of order)"),
-		('ss_2way_A_dfl_master3',       '2-way seed split with master share #3 (share A)'),
-		('ss_2way_B_dfl_master3',       '2-way seed split with master share #3 (share B)'),
-		('ss_2way_join_dfl_master3',    '2-way seed join with master share #3'),
-		('ss_2way_A_dfl_usw',           '2-way seed split of user-specified wallet (share A)'),
-		('ss_2way_B_dfl_usw',           '2-way seed split of user-specified wallet (share B)'),
-		('ss_2way_join_dfl_usw',        '2-way seed join of user-specified wallet'),
-		('ss_3way_A_dfl',               '3-way seed split (share A)'),
-		('ss_3way_B_dfl',               '3-way seed split (share B)'),
-		('ss_3way_C_dfl',               '3-way seed split (share C)'),
-		('ss_3way_join_dfl',            '3-way seed join'),
-		('ss_3way_join_dfl_mix',        '3-way seed join (out of order)'),
-		('ss_3way_A_foobar_master7',    "3-way seed split 'φυβαρ' with master share #7 (share A)"),
-		('ss_3way_B_foobar_master7',    "3-way seed split 'φυβαρ' with master share #7 (share B)"),
-		('ss_3way_C_foobar_master7',    "3-way seed split 'φυβαρ' with master share #7 (share C)"),
-		('ss_3way_join_foobar_master7', "3-way seed join 'φυβαρ' with master share #7"),
-		('ss_3way_join_foobar_master7_mix',"3-way seed join 'φυβαρ' with master share #7 (out of order)"),
-
-		('ss_3way_join_dfl_bad_invocation',"bad invocation of 'mmgen-seedjoin' - --id-str with non-master join"),
-		('ss_bad_invocation1',          "bad invocation of 'mmgen-seedsplit' - no arguments"),
-		('ss_bad_invocation2',          "bad invocation of 'mmgen-seedsplit' - master share with split specifier"),
-		('ss_bad_invocation3',          "bad invocation of 'mmgen-seedsplit' - nonexistent file"),
-		('ss_bad_invocation4',          "bad invocation of 'mmgen-seedsplit' - invalid file extension"),
-		('ss_bad_invocation5',          "bad invocation of 'mmgen-seedjoin' - no arguments"),
-		('ss_bad_invocation6',          "bad invocation of 'mmgen-seedjoin' - one file argument"),
-		('ss_bad_invocation7',          "bad invocation of 'mmgen-seedjoin' - invalid file extension"),
-		('ss_bad_invocation8',          "bad invocation of 'mmgen-seedjoin' - nonexistent file"),
-		('ss_bad_invocation9',          "bad invocation of 'mmgen-seedsplit' - bad specifier"),
-		('ss_bad_invocation10',         "bad invocation of 'mmgen-seedsplit' - nonexistent file"),
-		('ss_bad_invocation11',         "bad invocation of 'mmgen-seedsplit' - invalid file extension"),
+		('ss_walletgen',             'wallet generation'),
+		('ss_2way_A_dfl1',           '2-way seed split (share A)'),
+		('ss_2way_B_dfl1',           '2-way seed split (share B)'),
+		('ss_2way_join_dfl1',        '2-way seed join'),
+		('ss_2way_A_dfl2',           '2-way seed split ‘default’ (share A)'),
+		('ss_2way_B_dfl2',           '2-way seed split ‘default’ (share B)'),
+		('ss_2way_join_dfl2',        '2-way seed join ‘default’'),
+		('ss_2way_A_alice',          '2-way seed split ‘alice’ (share A)'),
+		('ss_2way_B_alice',          '2-way seed split ‘alice’ (share B)'),
+		('ss_2way_join_alice',       '2-way seed join ‘alice’'),
+		('ss_2way_join_alice_mix',   '2-way seed join ‘alice’ (out of order)'),
+		('ss_2way_A_dfl_master3',    '2-way seed split with master share #3 (share A)'),
+		('ss_2way_B_dfl_master3',    '2-way seed split with master share #3 (share B)'),
+		('ss_2way_join_dfl_master3', '2-way seed join with master share #3'),
+		('ss_2way_A_dfl_usw',        '2-way seed split of user-specified wallet (share A)'),
+		('ss_2way_B_dfl_usw',        '2-way seed split of user-specified wallet (share B)'),
+		('ss_2way_join_dfl_usw',     '2-way seed join of user-specified wallet'),
+		('ss_3way_A_dfl',            '3-way seed split (share A)'),
+		('ss_3way_B_dfl',            '3-way seed split (share B)'),
+		('ss_3way_C_dfl',            '3-way seed split (share C)'),
+		('ss_3way_join_dfl',         '3-way seed join'),
+		('ss_3way_join_dfl_mix',     '3-way seed join (out of order)'),
+		('ss_3way_A_foobar_master7', '3-way seed split ‘φυβαρ’ with master share #7 (share A)'),
+		('ss_3way_B_foobar_master7', '3-way seed split ‘φυβαρ’ with master share #7 (share B)'),
+		('ss_3way_C_foobar_master7', '3-way seed split ‘φυβαρ’ with master share #7 (share C)'),
+		('ss_3way_join_foobar_master7', '3-way seed join ‘φυβαρ’ with master share #7'),
+		('ss_3way_join_foobar_master7_mix', '3-way seed join ‘φυβαρ’ with master share #7 (out of order)'),
+
+		('ss_3way_join_dfl_bad_invocation', 'bad invocation of ‘mmgen-seedjoin’ - --id-str with non-master join'),
+		('ss_bad_invocation1',       'bad invocation of ‘mmgen-seedsplit’ - no arguments'),
+		('ss_bad_invocation2',       'bad invocation of ‘mmgen-seedsplit’ - master share with split specifier'),
+		('ss_bad_invocation3',       'bad invocation of ‘mmgen-seedsplit’ - nonexistent file'),
+		('ss_bad_invocation4',       'bad invocation of ‘mmgen-seedsplit’ - invalid file extension'),
+		('ss_bad_invocation5',       'bad invocation of ‘mmgen-seedjoin’ - no arguments'),
+		('ss_bad_invocation6',       'bad invocation of ‘mmgen-seedjoin’ - one file argument'),
+		('ss_bad_invocation7',       'bad invocation of ‘mmgen-seedjoin’ - invalid file extension'),
+		('ss_bad_invocation8',       'bad invocation of ‘mmgen-seedjoin’ - nonexistent file'),
+		('ss_bad_invocation9',       'bad invocation of ‘mmgen-seedsplit’ - bad specifier'),
+		('ss_bad_invocation10',      'bad invocation of ‘mmgen-seedsplit’ - nonexistent file'),
+		('ss_bad_invocation11',      'bad invocation of ‘mmgen-seedsplit’ - invalid file extension'),
 	)
 
-	def get_tmp_subdir(self,subdir):
-		return os.path.join(self.tmpdir,subdir)
+	def get_tmp_subdir(self, subdir):
+		return os.path.join(self.tmpdir, subdir)
 
 	def ss_walletgen(self):
-		t = self.spawn('mmgen-walletgen', ['-r0','-p1'])
-		t.passphrase_new('new '+dfl_wcls.desc,wpasswd)
+		t = self.spawn('mmgen-walletgen', ['-r0', '-p1'])
+		t.passphrase_new('new '+dfl_wcls.desc, wpasswd)
 		t.label()
-		self.write_to_tmpfile('dfl.sid',strip_ansi_escapes(t.expect_getend('Seed ID: ')))
-		t.expect('move it to the data directory? (Y/n): ','y')
+		self.write_to_tmpfile('dfl.sid', strip_ansi_escapes(t.expect_getend('Seed ID: ')))
+		t.expect('move it to the data directory? (Y/n): ', 'y')
 		t.written_to_file(capfirst(dfl_wcls.desc))
 		return t
 
-	def ss_splt(self,tdir,ofmt,spec,add_args=[],wf=None,master=None):
+	def ss_splt(self, tdir, ofmt, spec, add_args=[], wf=None, master=None):
 		try:
 			os.mkdir(self.get_tmp_subdir(tdir))
 		except:
 			pass
 		t = self.spawn('mmgen-seedsplit',
-				['-q','-d',self.get_tmp_subdir(tdir),'-r0','-o',ofmt]
-				+ (['-L',(spec or 'label')] if ofmt == 'w' else [])
+				['-q', '-d', self.get_tmp_subdir(tdir), '-r0', '-o', ofmt]
+				+ (['-L', (spec or 'label')] if ofmt == 'w' else [])
 				+ add_args
 				+ ([f'--master-share={master}'] if master else [])
 				+ ([wf] if wf else [])
 				+ ([spec] if spec else []))
 		if not wf:
-			t.passphrase(dfl_wcls.desc,wpasswd)
+			t.passphrase(dfl_wcls.desc, wpasswd)
 		if spec:
 			from mmgen.seedsplit import SeedSplitSpecifier
 			sss = SeedSplitSpecifier(spec)
 			pat = rf'Processing .*\b{sss.idx}\b of \b{sss.count}\b of .* id .*‘{sss.id}’'
 		else:
 			pat = f'master share #{master}'
-		t.expect(pat,regex=True)
+		t.expect(pat, regex=True)
 		ocls = get_wallet_cls(fmt_code=ofmt)
 		if ocls.enc:
-			t.hash_preset('new '+ocls.desc,'1')
-			t.passphrase_new('new '+ocls.desc,sh1_passwd)
+			t.hash_preset('new '+ocls.desc, '1')
+			t.passphrase_new('new '+ocls.desc, sh1_passwd)
 			if ocls.type == 'incog_hidden':
 				t.hincog_create(1234)
 		t.written_to_file(capfirst(ocls.desc))
@@ -136,119 +136,119 @@ class CmdTestSeedSplit(CmdTestBase):
 			master   = None,
 			id_str   = None):
 		td = self.get_tmp_subdir(tdir)
-		shares = [get_file_with_ext(td,f) for f in in_exts]
+		shares = [get_file_with_ext(td, f) for f in in_exts]
 		if not sid:
 			sid = self.read_from_tmpfile('dfl.sid')
 		t = self.spawn('mmgen-seedjoin',
 				add_args
 				+ ([f'--master-share={master}'] if master else [])
 				+ ([f'--id-str={id_str}'] if id_str else [])
-				+ ['-d',td,'-o',ofmt]
-				+ (['--label','Joined Wallet Label','-r0'] if ofmt == 'w' else [])
+				+ ['-d', td, '-o', ofmt]
+				+ (['--label', 'Joined Wallet Label', '-r0'] if ofmt == 'w' else [])
 				+ shares,
 				exit_val = exit_val)
 		if exit_val:
 			return t
-		icls = ( dfl_wcls if 'mmdat' in in_exts
+		icls = (dfl_wcls if 'mmdat' in in_exts
 			else get_wallet_cls('incog') if 'mmincog' in in_exts
 			else get_wallet_cls('incog_hex') if 'mmincox' in in_exts
 			else get_wallet_cls('incog_hidden') if '-H' in add_args
-			else None )
+			else None)
 		if icls.type.startswith('incog'):
-			t.hash_preset(icls.desc,'1')
+			t.hash_preset(icls.desc, '1')
 		if icls:
-			t.passphrase(icls.desc,sh1_passwd)
+			t.passphrase(icls.desc, sh1_passwd)
 		if master:
 			fs = "master share #{}, split id.*‘{}’.*, share count {}"
 			pat = fs.format(
 				master,
 				id_str or 'default',
-				len(shares) + (icls.type=='incog_hidden') )
-			t.expect(pat,regex=True)
+				len(shares) + (icls.type=='incog_hidden'))
+			t.expect(pat, regex=True)
 		sid_cmp = strip_ansi_escapes(t.expect_getend('Joined Seed ID: '))
-		cmp_or_die(sid,sid_cmp)
+		cmp_or_die(sid, sid_cmp)
 		ocls = get_wallet_cls(fmt_code=ofmt)
 		if ocls.type == 'mmgen':
-			t.hash_preset('new '+ocls.desc,'1')
-			t.passphrase_new('new '+ocls.desc,wpasswd)
+			t.hash_preset('new '+ocls.desc, '1')
+			t.passphrase_new('new '+ocls.desc, wpasswd)
 		t.written_to_file(capfirst(ocls.desc))
 		return t
 
-	def get_hincog_arg(self,tdir,suf='-default-2of2'):
+	def get_hincog_arg(self, tdir, suf='-default-2of2'):
 		sid = self.read_from_tmpfile('dfl.sid')
-		return os.path.join(self.tmpdir,tdir,sid+suf+'.hincog') + ',123'
+		return os.path.join(self.tmpdir, tdir, sid+suf+'.hincog') + ',123'
 
 	def ss_2way_A_dfl1(self):
-		return self.ss_splt('2way_dfl1','w','1:2')
+		return self.ss_splt('2way_dfl1', 'w', '1:2')
 	def ss_2way_B_dfl1(self):
-		return self.ss_splt('2way_dfl1','bip39','2:2')
+		return self.ss_splt('2way_dfl1', 'bip39', '2:2')
 	def ss_2way_join_dfl1(self):
-		return self.ss_join('2way_dfl1','w',['mmdat','bip39'])
+		return self.ss_join('2way_dfl1', 'w', ['mmdat', 'bip39'])
 
 	def ss_2way_A_dfl2(self):
-		return self.ss_splt('2way_dfl2','seed','default:1:2')
+		return self.ss_splt('2way_dfl2', 'seed', 'default:1:2')
 	def ss_2way_B_dfl2(self):
-		return self.ss_splt('2way_dfl2','hincog','default:2:2',['-J',self.get_hincog_arg('2way_dfl2')])
+		return self.ss_splt('2way_dfl2', 'hincog', 'default:2:2', ['-J', self.get_hincog_arg('2way_dfl2')])
 	def ss_2way_join_dfl2(self):
-		return self.ss_join('2way_dfl2','mmhex',['mmseed'],['-H',self.get_hincog_arg('2way_dfl2')])
+		return self.ss_join('2way_dfl2', 'mmhex', ['mmseed'], ['-H', self.get_hincog_arg('2way_dfl2')])
 
 	def ss_2way_A_alice(self):
-		return self.ss_splt('2way_alice','w','alice:1:2')
+		return self.ss_splt('2way_alice', 'w', 'alice:1:2')
 	def ss_2way_B_alice(self):
-		return self.ss_splt('2way_alice','mmhex','alice:2:2')
+		return self.ss_splt('2way_alice', 'mmhex', 'alice:2:2')
 	def ss_2way_join_alice(self):
-		return self.ss_join('2way_alice','seed',['mmdat','mmhex'])
+		return self.ss_join('2way_alice', 'seed', ['mmdat', 'mmhex'])
 	def ss_2way_join_alice_mix(self):
-		return self.ss_join('2way_alice','seed',['mmhex','mmdat'])
+		return self.ss_join('2way_alice', 'seed', ['mmhex', 'mmdat'])
 
 	def ss_2way_A_dfl_usw(self):
-		return self.ss_splt('2way_dfl_usw','words','1:2',[],wf=ref_wf)
+		return self.ss_splt('2way_dfl_usw', 'words', '1:2', [], wf=ref_wf)
 	def ss_2way_B_dfl_usw(self):
-		return self.ss_splt('2way_dfl_usw','incog','2:2',[],wf=ref_wf)
+		return self.ss_splt('2way_dfl_usw', 'incog', '2:2', [], wf=ref_wf)
 	def ss_2way_join_dfl_usw(self):
-		return self.ss_join('2way_dfl_usw','mmhex',['mmwords','mmincog'],sid=ref_sid)
+		return self.ss_join('2way_dfl_usw', 'mmhex', ['mmwords', 'mmincog'], sid=ref_sid)
 
 	def ss_3way_A_dfl(self):
-		return self.ss_splt('3way_dfl','words','1:3')
+		return self.ss_splt('3way_dfl', 'words', '1:3')
 	def ss_3way_B_dfl(self):
-		return self.ss_splt('3way_dfl','incog_hex','2:3')
+		return self.ss_splt('3way_dfl', 'incog_hex', '2:3')
 	def ss_3way_C_dfl(self):
-		return self.ss_splt('3way_dfl','bip39','3:3')
+		return self.ss_splt('3way_dfl', 'bip39', '3:3')
 	def ss_3way_join_dfl(self):
-		return self.ss_join('3way_dfl','mmhex',['mmwords','mmincox','bip39'])
+		return self.ss_join('3way_dfl', 'mmhex', ['mmwords', 'mmincox', 'bip39'])
 	def ss_3way_join_dfl_mix(self):
-		return self.ss_join('3way_dfl','mmhex',['bip39','mmwords','mmincox'])
+		return self.ss_join('3way_dfl', 'mmhex', ['bip39', 'mmwords', 'mmincox'])
 
 	def ss_2way_A_dfl_master3(self):
-		return self.ss_splt('2way_dfl_master3','w','',master=3)
+		return self.ss_splt('2way_dfl_master3', 'w', '', master=3)
 	def ss_2way_B_dfl_master3(self):
-		return self.ss_splt('2way_dfl_master3','bip39','2:2',master=3)
+		return self.ss_splt('2way_dfl_master3', 'bip39', '2:2', master=3)
 	def ss_2way_join_dfl_master3(self):
-		return self.ss_join('2way_dfl_master3','mmhex',['mmdat','bip39'],master=3)
+		return self.ss_join('2way_dfl_master3', 'mmhex', ['mmdat', 'bip39'], master=3)
 
 	tdir2 = '3way_foobar_master7'
 	def ss_3way_C_foobar_master7(self):
-		return self.ss_splt(self.tdir2,'hincog','',
-					['-J',self.get_hincog_arg(self.tdir2,'-master7')],master=7)
+		return self.ss_splt(self.tdir2, 'hincog', '',
+					['-J', self.get_hincog_arg(self.tdir2, '-master7')], master=7)
 	def ss_3way_B_foobar_master7(self):
-		return self.ss_splt(self.tdir2,'bip39','φυβαρ:2:3',master=7)
+		return self.ss_splt(self.tdir2, 'bip39', 'φυβαρ:2:3', master=7)
 	def ss_3way_A_foobar_master7(self):
-		return self.ss_splt(self.tdir2,'mmhex','φυβαρ:3:3',master=7)
+		return self.ss_splt(self.tdir2, 'mmhex', 'φυβαρ:3:3', master=7)
 	def ss_3way_join_foobar_master7(self):
-		return self.ss_join(self.tdir2,'seed', ['bip39','mmhex'],
-							['-H',self.get_hincog_arg(self.tdir2,'-master7')],master=7,id_str='φυβαρ')
+		return self.ss_join(self.tdir2, 'seed', ['bip39', 'mmhex'],
+							['-H', self.get_hincog_arg(self.tdir2, '-master7')], master=7, id_str='φυβαρ')
 	def ss_3way_join_foobar_master7_mix(self):
-		return self.ss_join(self.tdir2,'seed', ['mmhex','bip39'],
-							['-H',self.get_hincog_arg(self.tdir2,'-master7')],master=7,id_str='φυβαρ')
+		return self.ss_join(self.tdir2, 'seed', ['mmhex', 'bip39'],
+							['-H', self.get_hincog_arg(self.tdir2, '-master7')], master=7, id_str='φυβαρ')
 
-	def ss_bad_invocation(self,cmd,args,exit_val,errmsg):
+	def ss_bad_invocation(self, cmd, args, exit_val, errmsg):
 		t = self.spawn(cmd, args, exit_val=exit_val)
 		t.expect(errmsg, regex=True)
 		return t
 
 	def ss_3way_join_dfl_bad_invocation(self):
-		t = self.ss_join('3way_dfl','mmhex',
-			['mmwords','mmincox','bip39'],
+		t = self.ss_join('3way_dfl', 'mmhex',
+			['mmwords', 'mmincox', 'bip39'],
 			id_str   = 'foo',
 			exit_val = 1)
 		t.expect('option meaningless')

+ 56 - 56
test/cmdtest_py_d/ct_shared.py

@@ -26,14 +26,14 @@ from mmgen.addrlist import AddrList
 from mmgen.passwdlist import PasswordList
 
 from ..include.common import cfg, cmp_or_die, strip_ansi_escapes, joinpath, silence, end_silence
-from .common import ref_bw_file,ref_bw_hash_preset,ref_dir
+from .common import ref_bw_file, ref_bw_hash_preset, ref_dir
 
 class CmdTestShared:
 	'shared methods for the cmdtest.py test suite'
 
 	@property
 	def segwit_mmtype(self):
-		return ('segwit','bech32')[bool(cfg.bech32)] if self.segwit else None
+		return ('segwit', 'bech32')[bool(cfg.bech32)] if self.segwit else None
 
 	@property
 	def segwit_arg(self):
@@ -66,48 +66,48 @@ class CmdTestShared:
 		confirm_pat = r'Is this what you want.*:.'
 
 		if used_chg_addr_resp is not None:
-			t.expect('reuse harms your privacy.*:.*',used_chg_addr_resp,regex=True)
+			t.expect('reuse harms your privacy.*:.*', used_chg_addr_resp, regex=True)
 
 		if auto_chg_addr is not None:
 			e1 = 'Choose a change address:.*Enter a number> '
 			e2 = fr'Using .*{auto_chg_addr}.* as.*address'
-			res = t.expect([e1,e2],regex=True)
+			res = t.expect([e1, e2], regex=True)
 			if res == 0:
 				choice = [s.split(')')[0].lstrip() for s in t.p.match[0].split('\n') if auto_chg_addr in s][0]
 				t.send(f'{choice}\n')
-				t.expect(e2,regex=True)
+				t.expect(e2, regex=True)
 			t.send('y')
 
 		pat = expect_pat
 		for choice in menu + ['q']:
-			t.expect(pat,choice,regex=True)
+			t.expect(pat, choice, regex=True)
 			if self.proto.base_proto == 'Ethereum':
 				pat = confirm_pat if pat == delete_pat else delete_pat if choice == 'D' else expect_pat
 
 		if bad_input_sels:
-			for r in ('x','3-1','9999'):
-				t.expect(input_sels_prompt+': ',r+'\n')
+			for r in ('x', '3-1', '9999'):
+				t.expect(input_sels_prompt+': ', r+'\n')
 
-		t.expect(input_sels_prompt+': ',inputs+'\n')
+		t.expect(input_sels_prompt+': ', inputs+'\n')
 
-		have_est_fee = t.expect([f'{fee_desc}: ','OK? (Y/n): ']) == 1
+		have_est_fee = t.expect([f'{fee_desc}: ', 'OK? (Y/n): ']) == 1
 
 		if have_est_fee and not interactive_fee:
 			t.send('y')
 		else:
 			if have_est_fee:
 				t.send('n')
-				t.expect(f'{fee_desc}: ',interactive_fee+'\n')
+				t.expect(f'{fee_desc}: ', interactive_fee+'\n')
 			else:
 				t.send(interactive_fee+'\n')
 			if fee_info_pat:
-				t.expect(fee_info_pat,regex=True)
-			t.expect('OK? (Y/n): ','y')
+				t.expect(fee_info_pat, regex=True)
+			t.expect('OK? (Y/n): ', 'y')
 
-		t.expect('(Y/n): ','\n') # chg amt OK prompt
+		t.expect('(Y/n): ', '\n') # chg amt OK prompt
 
 		if 'confirm_non_mmgen' in tweaks:
-			t.expect('Continue? (Y/n)','\n')
+			t.expect('Continue? (Y/n)', '\n')
 
 		t.do_comment(add_comment)
 
@@ -116,7 +116,7 @@ class CmdTestShared:
 
 		t.view_tx(view)
 		if not txdo:
-			t.expect('(y/N): ',('n','y')[save])
+			t.expect('(y/N): ', ('n', 'y')[save])
 			t.written_to_file(file_desc)
 
 		return t
@@ -136,12 +136,12 @@ class CmdTestShared:
 		txdo = (caller or self.test_name)[:4] == 'txdo'
 
 		if do_passwd:
-			t.passphrase('MMGen wallet',self.wpasswd)
+			t.passphrase('MMGen wallet', self.wpasswd)
 
 		if not ni and not txdo:
 			t.view_tx(view)
-			t.do_comment(add_comment,has_label=has_label)
-			t.expect('(Y/n): ',('n','y')[save])
+			t.do_comment(add_comment, has_label=has_label)
+			t.expect('(Y/n): ', ('n', 'y')[save])
 
 		t.written_to_file(file_desc)
 
@@ -164,9 +164,9 @@ class CmdTestShared:
 		if not txdo:
 			t.license() # MMGEN_NO_LICENSE is set, so does nothing
 			t.view_tx(view)
-			t.do_comment(add_comment,has_label=has_label)
+			t.do_comment(add_comment, has_label=has_label)
 
-		self._do_confirm_send(t,quiet=quiet,confirm_send=confirm_send)
+		self._do_confirm_send(t, quiet=quiet, confirm_send=confirm_send)
 
 		if bogus_send:
 			txid = ''
@@ -179,10 +179,10 @@ class CmdTestShared:
 
 		return txid
 
-	def txsign_end(self,t,tnum=None,has_label=False):
+	def txsign_end(self, t, tnum=None, has_label=False):
 		t.expect('Signing transaction')
-		t.do_comment(False,has_label=has_label)
-		t.expect(r'Save signed transaction.*?\? \(Y/n\): ','y',regex=True)
+		t.do_comment(False, has_label=has_label)
+		t.expect(r'Save signed transaction.*?\? \(Y/n\): ', 'y', regex=True)
 		t.written_to_file('Signed transaction' + (' #' + tnum if tnum else ''))
 		return t
 
@@ -196,7 +196,7 @@ class CmdTestShared:
 			extra_desc = '',
 			view       = 'n',
 			dfl_wallet = False):
-		opts = extra_opts + ['-d',self.tmpdir,txfile] + ([wf] if wf else [])
+		opts = extra_opts + ['-d', self.tmpdir, txfile] + ([wf] if wf else [])
 		wcls = get_wallet_cls(ext = 'mmdat' if dfl_wallet else get_extension(wf))
 		t = self.spawn(
 			'mmgen-txsign',
@@ -206,19 +206,19 @@ class CmdTestShared:
 		t.license()
 		t.view_tx(view)
 		if wcls.enc and wcls.type != 'brain':
-			t.passphrase(wcls.desc,self.wpasswd)
+			t.passphrase(wcls.desc, self.wpasswd)
 		if save:
-			self.txsign_end(t,has_label=has_label)
+			self.txsign_end(t, has_label=has_label)
 		else:
-			t.do_comment(False,has_label=has_label)
-			t.expect('Save signed transaction? (Y/n): ','n')
+			t.do_comment(False, has_label=has_label)
+			t.expect('Save signed transaction? (Y/n): ', 'n')
 			t.expect('not saved')
 		return t
 
-	def ref_brain_chk(self,bw_file=ref_bw_file):
-		wf = joinpath(ref_dir,bw_file)
+	def ref_brain_chk(self, bw_file=ref_bw_file):
+		wf = joinpath(ref_dir, bw_file)
 		add_args = [f'-l{self.seed_len}', f'-p{ref_bw_hash_preset}']
-		return self.walletchk(wf,add_args=add_args,sid=self.ref_bw_seed_id)
+		return self.walletchk(wf, add_args=add_args, sid=self.ref_bw_seed_id)
 
 	def walletchk(
 			self,
@@ -228,21 +228,21 @@ class CmdTestShared:
 			sid        = None,
 			extra_desc = '',
 			dfl_wallet = False):
-		hp = self.hash_preset if hasattr(self,'hash_preset') else '1'
+		hp = self.hash_preset if hasattr(self, 'hash_preset') else '1'
 		wcls = wcls or get_wallet_cls(ext=get_extension(wf))
 		t = self.spawn(
 				'mmgen-walletchk',
-				([] if dfl_wallet else ['-i',wcls.fmt_codes[0]])
+				([] if dfl_wallet else ['-i', wcls.fmt_codes[0]])
 				+ self.testnet_opt
-				+ add_args + ['-p',hp]
+				+ add_args + ['-p', hp]
 				+ ([wf] if wf else []),
 				extra_desc       = extra_desc,
 				no_passthru_opts = True)
 		if wcls.type != 'incog_hidden':
 			t.expect(f"Getting {wcls.desc} from file ‘")
 		if wcls.enc and wcls.type != 'brain':
-			t.passphrase(wcls.desc,self.wpasswd)
-			t.expect(['Passphrase is OK', 'Passphrase.* are correct'],regex=True)
+			t.passphrase(wcls.desc, self.wpasswd)
+			t.expect(['Passphrase is OK', 'Passphrase.* are correct'], regex=True)
 		chksum = t.expect_getend(f'Valid {wcls.desc} for Seed ID ')[:8]
 		if sid:
 			cmp_or_die(chksum, sid)
@@ -265,19 +265,19 @@ class CmdTestShared:
 			mmtype = self.segwit_mmtype
 		t = self.spawn(
 				f'mmgen-{list_type}gen',
-				['-d',self.tmpdir] + extra_opts +
-				([],['--type='+str(mmtype)])[bool(mmtype)] +
-				([],['--stdout'])[stdout] +
-				([],[wf])[bool(wf)] +
-				([],[id_str])[bool(id_str)] +
-				[getattr(self,f'{list_type}_idx_list')],
-				extra_desc       = f'({mmtype})' if mmtype in ('segwit','bech32') else '',
+				['-d', self.tmpdir] + extra_opts +
+				([], ['--type='+str(mmtype)])[bool(mmtype)] +
+				([], ['--stdout'])[stdout] +
+				([], [wf])[bool(wf)] +
+				([], [id_str])[bool(id_str)] +
+				[getattr(self, f'{list_type}_idx_list')],
+				extra_desc       = f'({mmtype})' if mmtype in ('segwit', 'bech32') else '',
 				no_passthru_opts = no_passthru_opts)
 		t.license()
-		wcls = get_wallet_cls( ext = 'mmdat' if dfl_wallet else get_extension(wf) )
-		t.passphrase(wcls.desc,self.wpasswd)
+		wcls = get_wallet_cls(ext = 'mmdat' if dfl_wallet else get_extension(wf))
+		t.passphrase(wcls.desc, self.wpasswd)
 		t.expect('Passphrase is OK')
-		desc = ('address','password')[passgen]
+		desc = ('address', 'password')[passgen]
 		chksum = strip_ansi_escapes(t.expect_getend(rf'Checksum for {desc} data .*?: ', regex=True))
 		if check_ref:
 			chksum_chk = (
@@ -285,7 +285,7 @@ class CmdTestShared:
 				self.chk_data[self.test_name][self.fork][self.proto.testnet])
 			cmp_or_die(chksum, chksum_chk, desc=f'{ftype}list data checksum')
 		if passgen:
-			t.expect('Encrypt password list? (y/N): ','N')
+			t.expect('Encrypt password list? (y/N): ', 'N')
 		if stdout:
 			t.read()
 		else:
@@ -306,20 +306,20 @@ class CmdTestShared:
 				extra_desc = f'({mmtype})' if mmtype in ('segwit', 'bech32') else '')
 		t.license()
 		wcls = get_wallet_cls(ext=get_extension(wf))
-		t.passphrase(wcls.desc,self.wpasswd)
-		chksum = t.expect_getend(r'Checksum for key-address data .*?: ',regex=True)
+		t.passphrase(wcls.desc, self.wpasswd)
+		chksum = t.expect_getend(r'Checksum for key-address data .*?: ', regex=True)
 		if check_ref:
 			chksum_chk = self.chk_data[self.test_name][self.fork][self.proto.testnet]
 			cmp_or_die(chksum, chksum_chk, desc='key-address list data checksum')
-		t.expect('Encrypt key list? (y/N): ','y')
+		t.expect('Encrypt key list? (y/N): ', 'y')
 		t.usr_rand(self.usr_rand_chars)
-		t.hash_preset('new key-address list','1')
-		t.passphrase_new('new key-address list',self.kapasswd)
+		t.hash_preset('new key-address list', '1')
+		t.passphrase_new('new key-address list', self.kapasswd)
 		t.written_to_file('Encrypted secret keys')
 		return t
 
-	def _do_confirm_send(self,t,quiet=False,confirm_send=True,sure=True):
+	def _do_confirm_send(self, t, quiet=False, confirm_send=True, sure=True):
 		if sure:
 			t.expect('Are you sure you want to broadcast this')
-		m = ('YES, I REALLY WANT TO DO THIS','YES')[quiet]
-		t.expect(f'{m!r} to confirm: ',('',m)[confirm_send]+'\n')
+		m = ('YES, I REALLY WANT TO DO THIS', 'YES')[quiet]
+		t.expect(f'{m!r} to confirm: ', ('', m)[confirm_send]+'\n')

+ 52 - 36
test/cmdtest_py_d/ct_tool.py

@@ -10,7 +10,7 @@
 test.cmdtest_py_d.ct_tool: tool tests for the MMGen cmdtest.py test suite
 """
 
-import sys,os
+import sys, os
 
 from mmgen.util import suf
 from mmgen.color import cyan
@@ -24,35 +24,51 @@ from ..include.common import (
 	joinpath,
 	getrand
 )
-from .common import hincog_fn,incog_id_fn,hincog_offset,tool_enc_passwd,ref_dir
+from .common import hincog_fn, incog_id_fn, hincog_offset, tool_enc_passwd, ref_dir
 from .ct_base import CmdTestBase
 from .ct_main import CmdTestMain
 
-class CmdTestTool(CmdTestMain,CmdTestBase):
+class CmdTestTool(CmdTestMain, CmdTestBase):
 	"interactive 'mmgen-tool' commands"
 	networks = ('btc',)
 	segwit_opts_ok = False
 	tmpdir_nums = [9]
 	enc_infn = 'tool_encrypt.in'
 	cmd_group = (
-		('tool_find_incog_data', (9,"'mmgen-tool find_incog_data'", [[[hincog_fn],1],[[incog_id_fn],1]])),
-		('tool_rand2file',       (9,"'mmgen-tool rand2file'", [])),
-		('tool_encrypt',         (9,"'mmgen-tool encrypt' (random data)",     [])),
-		('tool_decrypt',         (9,"'mmgen-tool decrypt' (random data)", [[[enc_infn+'.mmenc'],9]])),
-		('tool_twview_bad_comment',(9,"'mmgen-tool twview' (with bad comment)", [])),
-		('tool_decrypt_keystore',(9,"'mmgen-tool decrypt_keystore'", [])),
-		('tool_decrypt_geth_keystore',(9,"'mmgen-tool decrypt_geth_keystore'", [])),
-		('tool_api',             (9,'tool API (initialization, config methods, wif2addr)',[])),
-		# ('tool_encrypt_ref', (9,"'mmgen-tool encrypt' (reference text)",  [])),
+		('tool_find_incog_data',
+			(9, '‘mmgen-tool find_incog_data’', [[[hincog_fn], 1], [[incog_id_fn], 1]])
+		),
+		('tool_rand2file',
+			(9, '‘mmgen-tool rand2file’', [])
+		),
+		('tool_encrypt',
+			(9, '‘mmgen-tool encrypt’ (random data)', [])
+		),
+		('tool_decrypt',
+			(9, '‘mmgen-tool decrypt’ (random data)', [[[enc_infn+'.mmenc'], 9]])
+		),
+		('tool_twview_bad_comment',
+			(9, '‘mmgen-tool twview’ (with bad comment)', [])
+		),
+		('tool_decrypt_keystore',
+			(9, '‘mmgen-tool decrypt_keystore’', [])
+		),
+		('tool_decrypt_geth_keystore',
+			(9, '‘mmgen-tool decrypt_geth_keystore’', [])
+		),
+		('tool_api',
+			(9, 'tool API (initialization, config methods, wif2addr)', [])
+		),
+		# ('tool_encrypt_ref', (9, '‘mmgen-tool encrypt’ (reference text)', [])),
 	)
 
 	def tool_rand2file(self):
 		from mmgen.util2 import parse_bytespec
-		for nbytes in ('1','1023','1K','1048575','1M','1048577','123M'):
+		for nbytes in ('1', '1023', '1K', '1048575', '1M', '1048577', '123M'):
 			t = self.spawn(
 				'mmgen-tool',
-				['-d',self.tmpdir,'-r0','rand2file','rand2file.out',nbytes],
-				extra_desc='({} byte{})'.format( nbytes, suf(parse_bytespec(nbytes)) )
+				['-d', self.tmpdir, '-r0', 'rand2file', 'rand2file.out', nbytes],
+				extra_desc='({} byte{})'.format(nbytes, suf(parse_bytespec(nbytes)))
 			)
 			t.expect('random data written to file')
 			t.read()
@@ -62,49 +78,49 @@ class CmdTestTool(CmdTestMain,CmdTestBase):
 		return t
 
 	def tool_encrypt(self):
-		infile = joinpath(self.tmpdir,self.enc_infn)
-		write_to_file(infile,getrand(1033),binary=True)
-		t = self.spawn('mmgen-tool',['-d',self.tmpdir,self.usr_rand_arg,'encrypt',infile])
+		infile = joinpath(self.tmpdir, self.enc_infn)
+		write_to_file(infile, getrand(1033), binary=True)
+		t = self.spawn('mmgen-tool', ['-d', self.tmpdir, self.usr_rand_arg, 'encrypt', infile])
 		t.usr_rand(self.usr_rand_chars)
-		t.hash_preset('data','1')
-		t.passphrase_new('data',tool_enc_passwd)
+		t.hash_preset('data', '1')
+		t.passphrase_new('data', tool_enc_passwd)
 		t.written_to_file('Encrypted data')
 		return t
 
-	def tool_decrypt(self,f1):
+	def tool_decrypt(self, f1):
 		out_fn = 'tool_encrypt.out'
-		t = self.spawn('mmgen-tool',['-d',self.tmpdir,'decrypt',f1,'outfile='+out_fn,'hash_preset=1'])
-		t.passphrase('data',tool_enc_passwd)
+		t = self.spawn('mmgen-tool', ['-d', self.tmpdir, 'decrypt', f1, 'outfile='+out_fn, 'hash_preset=1'])
+		t.passphrase('data', tool_enc_passwd)
 		t.written_to_file('Decrypted data')
-		d1 = self.read_from_tmpfile(self.enc_infn,binary=True)
-		d2 = self.read_from_tmpfile(out_fn,binary=True)
-		cmp_or_die(d1,d2)
+		d1 = self.read_from_tmpfile(self.enc_infn, binary=True)
+		d2 = self.read_from_tmpfile(out_fn, binary=True)
+		cmp_or_die(d1, d2)
 		return t
 
-	def tool_find_incog_data(self,f1,f2):
+	def tool_find_incog_data(self, f1, f2):
 		i_id = read_from_file(f2).rstrip()
 		vmsg(f'Incog ID: {cyan(i_id)}')
-		t = self.spawn('mmgen-tool',['-d',self.tmpdir,'find_incog_data',f1,i_id])
+		t = self.spawn('mmgen-tool', ['-d', self.tmpdir, 'find_incog_data', f1, i_id])
 		o = t.expect_getend(f'Incog data for ID {i_id} found at offset ')
 		if not sys.platform == 'win32':
 			os.unlink(f1) # causes problems with MSYS2
-		cmp_or_die(hincog_offset,int(o))
+		cmp_or_die(hincog_offset, int(o))
 		return t
 
 	def tool_twview_bad_comment(self): # test correct operation of get_tw_label()
 		t = self.spawn(
 			'mmgen-tool',
 			['twview'],
-			env = { 'MMGEN_BOGUS_UNSPENT_DATA': joinpath(ref_dir,'bad-comment-unspent.json') },
+			env = {'MMGEN_BOGUS_UNSPENT_DATA': joinpath(ref_dir, 'bad-comment-unspent.json')},
 			exit_val = 2)
 		t.expect('cannot be converted to TwComment')
 		return t
 
-	def _decrypt_keystore(self,cmd,fn,pw,chk):
+	def _decrypt_keystore(self, cmd, fn, pw, chk):
 		if cfg.no_altcoin:
 			return 'skip'
-		t = self.spawn('mmgen-tool',['-d',self.tmpdir,cmd,fn])
-		t.expect('Enter passphrase: ',pw+'\n')
+		t = self.spawn('mmgen-tool', ['-d', self.tmpdir, cmd, fn])
+		t.expect('Enter passphrase: ', pw+'\n')
 		t.expect(chk)
 		return t
 
@@ -113,7 +129,7 @@ class CmdTestTool(CmdTestMain,CmdTestBase):
 			cmd = 'decrypt_keystore',
 			fn  = 'test/ref/altcoin/98831F3A-keystore-wallet.json',
 			pw = 'abc',
-			chk = read_from_file('test/ref/98831F3A.bip39').strip() )
+			chk = read_from_file('test/ref/98831F3A.bip39').strip())
 
 	def tool_decrypt_geth_keystore(self):
 		return self._decrypt_keystore(
@@ -126,6 +142,6 @@ class CmdTestTool(CmdTestMain,CmdTestBase):
 		t = self.spawn(
 				'tool_api_test.py',
 				(['no_altcoin'] if cfg.no_altcoin else []),
-				cmd_dir = 'test/misc' )
-		t.expect('legacy.*compressed.*segwit.*bech32',regex=True)
+				cmd_dir = 'test/misc')
+		t.expect('legacy.*compressed.*segwit.*bech32', regex=True)
 		return t

+ 100 - 98
test/cmdtest_py_d/ct_wallet.py

@@ -22,84 +22,85 @@ test.cmdtest_py_d.ct_wallet: Wallet conversion tests for the cmdtest.py test sui
 
 import sys, os
 
-from mmgen.util import msg,capfirst,get_extension
+from mmgen.util import msg, capfirst, get_extension
 from mmgen.wallet import get_wallet_cls
 
 from ..include.common import cfg, joinpath, VirtBlockDevice
-from .common import ref_dir,ref_wallet_brainpass,ref_wallet_incog_offset,hincog_fn,hincog_bytes
+from .common import ref_dir, ref_wallet_brainpass, ref_wallet_incog_offset, hincog_fn, hincog_bytes
 from .ct_base import CmdTestBase
 from .ct_shared import CmdTestShared
 
-class CmdTestWalletConv(CmdTestBase,CmdTestShared):
+class CmdTestWalletConv(CmdTestBase, CmdTestShared):
 	'wallet conversion to and from reference data'
 	networks = ('btc',)
-	tmpdir_nums = [11,12,13]
-	sources = { '128': {
-					'ref_wallet':      'FE3C6545-D782B529[128,1].mmdat',
-					'ic_wallet':       'FE3C6545-E29303EA-5E229E30[128,1].mmincog',
-					'ic_wallet_hex':   'FE3C6545-BC4BE3F2-32586837[128,1].mmincox',
-
-					'hic_wallet':       'FE3C6545-161E495F-BEB7548E[128,1].incog-offset123',
-					'hic_wallet_old':   'FE3C6545-161E495F-9860A85B[128,1].incog-old.offset123',
-				},
-				'192': {
-					'ref_wallet':      '1378FC64-6F0F9BB4[192,1].mmdat',
-					'ic_wallet':       '1378FC64-2907DE97-F980D21F[192,1].mmincog',
-					'ic_wallet_hex':   '1378FC64-4DCB5174-872806A7[192,1].mmincox',
-
-					'hic_wallet':      '1378FC64-B55E9958-77256FC1[192,1].incog.offset123',
-					'hic_wallet_old':  '1378FC64-B55E9958-D85FF20C[192,1].incog-old.offset123',
-				},
-				'256': {
-					'ref_wallet':      '98831F3A-27F2BF93[256,1].mmdat',
-					'ic_wallet':       '98831F3A-5482381C-18460FB1[256,1].mmincog',
-					'ic_wallet_hex':   '98831F3A-1630A9F2-870376A9[256,1].mmincox',
-
-					'hic_wallet':       '98831F3A-F59B07A0-559CEF19[256,1].incog.offset123',
-					'hic_wallet_old':   '98831F3A-F59B07A0-848535F3[256,1].incog-old.offset123',
-
-				},
-			}
+	tmpdir_nums = [11, 12, 13]
+	sources = {
+		'128': {
+			'ref_wallet':     'FE3C6545-D782B529[128,1].mmdat',
+			'ic_wallet':      'FE3C6545-E29303EA-5E229E30[128,1].mmincog',
+			'ic_wallet_hex':  'FE3C6545-BC4BE3F2-32586837[128,1].mmincox',
+
+			'hic_wallet':      'FE3C6545-161E495F-BEB7548E[128,1].incog-offset123',
+			'hic_wallet_old':  'FE3C6545-161E495F-9860A85B[128,1].incog-old.offset123',
+		},
+		'192': {
+			'ref_wallet':     '1378FC64-6F0F9BB4[192,1].mmdat',
+			'ic_wallet':      '1378FC64-2907DE97-F980D21F[192,1].mmincog',
+			'ic_wallet_hex':  '1378FC64-4DCB5174-872806A7[192,1].mmincox',
+
+			'hic_wallet':     '1378FC64-B55E9958-77256FC1[192,1].incog.offset123',
+			'hic_wallet_old': '1378FC64-B55E9958-D85FF20C[192,1].incog-old.offset123',
+		},
+		'256': {
+			'ref_wallet':     '98831F3A-27F2BF93[256,1].mmdat',
+			'ic_wallet':      '98831F3A-5482381C-18460FB1[256,1].mmincog',
+			'ic_wallet_hex':  '98831F3A-1630A9F2-870376A9[256,1].mmincox',
+
+			'hic_wallet':      '98831F3A-F59B07A0-559CEF19[256,1].incog.offset123',
+			'hic_wallet_old':  '98831F3A-F59B07A0-848535F3[256,1].incog-old.offset123',
+
+		},
+	}
 	cmd_group = (
 		# reading
-		('ref_wallet_conv',    'conversion of saved reference wallet'),
-		('ref_mn_conv',        'conversion of saved MMGen native mnemonic'),
-		('ref_bip39_conv',     'conversion of saved BIP39 mnemonic'),
-		('ref_seed_conv',      'conversion of saved seed file'),
-		('ref_hex_conv',       'conversion of saved MMGen hexadecimal seed file'),
-		('ref_plainhex_conv',  'conversion of saved plain hexadecimal seed file'),
-		('ref_dieroll_conv',   'conversion of saved dieroll (b6d) seed file'),
-		('ref_brain_conv',     'conversion of ref brainwallet'),
-		('ref_incog_conv',     'conversion of saved incog wallet'),
-		('ref_incox_conv',     'conversion of saved hex incog wallet'),
-		('ref_hincog_conv',    'conversion of saved hidden incog wallet'),
-		('ref_hincog_conv_old','conversion of saved hidden incog wallet (old format)'),
+		('ref_wallet_conv',            'conversion of saved reference wallet'),
+		('ref_mn_conv',                'conversion of saved MMGen native mnemonic'),
+		('ref_bip39_conv',             'conversion of saved BIP39 mnemonic'),
+		('ref_seed_conv',              'conversion of saved seed file'),
+		('ref_hex_conv',               'conversion of saved MMGen hexadecimal seed file'),
+		('ref_plainhex_conv',          'conversion of saved plain hexadecimal seed file'),
+		('ref_dieroll_conv',           'conversion of saved dieroll (b6d) seed file'),
+		('ref_brain_conv',             'conversion of ref brainwallet'),
+		('ref_incog_conv',             'conversion of saved incog wallet'),
+		('ref_incox_conv',             'conversion of saved hex incog wallet'),
+		('ref_hincog_conv',            'conversion of saved hidden incog wallet'),
+		('ref_hincog_conv_old',        'conversion of saved hidden incog wallet (old format)'),
 		# writing
-		('ref_wallet_conv_out', 'ref seed conversion to wallet'),
-		('ref_mn_conv_out',     'ref seed conversion to MMGen native mnemonic'),
-		('ref_bip39_conv_out',  'ref seed conversion to BIP39 mnemonic'),
-		('ref_hex_conv_out',    'ref seed conversion to MMGen hex seed'),
-		('ref_plainhex_conv_out','ref seed conversion to plain hex seed'),
-		('ref_dieroll_conv_out','ref seed conversion to dieroll (b6d) seed'),
-		('ref_seed_conv_out',   'ref seed conversion to seed'),
-		('ref_incog_conv_out',  'ref seed conversion to incog data'),
-		('ref_incox_conv_out',  'ref seed conversion to hex incog data'),
-		('ref_hincog_conv_out', 'ref seed conversion to hidden incog data'),
+		('ref_wallet_conv_out',        'ref seed conversion to wallet'),
+		('ref_mn_conv_out',            'ref seed conversion to MMGen native mnemonic'),
+		('ref_bip39_conv_out',         'ref seed conversion to BIP39 mnemonic'),
+		('ref_hex_conv_out',           'ref seed conversion to MMGen hex seed'),
+		('ref_plainhex_conv_out',      'ref seed conversion to plain hex seed'),
+		('ref_dieroll_conv_out',       'ref seed conversion to dieroll (b6d) seed'),
+		('ref_seed_conv_out',          'ref seed conversion to seed'),
+		('ref_incog_conv_out',         'ref seed conversion to incog data'),
+		('ref_incox_conv_out',         'ref seed conversion to hex incog data'),
+		('ref_hincog_conv_out',        'ref seed conversion to hidden incog data'),
 		('ref_hincog_blkdev_conv_out', 'ref seed conversion to hidden incog data on block device')
 	)
 
-	def __init__(self,trunner,cfgs,spawn):
-		for k,_ in self.cmd_group:
-			for n in (1,2,3):
-				setattr(self,f'{k}_{n}',getattr(self,k))
-		CmdTestBase.__init__(self,trunner,cfgs,spawn)
+	def __init__(self, trunner, cfgs, spawn):
+		for k, _ in self.cmd_group:
+			for n in (1, 2, 3):
+				setattr(self, f'{k}_{n}', getattr(self, k))
+		CmdTestBase.__init__(self, trunner, cfgs, spawn)
 
 	def ref_wallet_conv(self):
-		wf = joinpath(ref_dir,self.sources[str(self.seed_len)]['ref_wallet'])
+		wf = joinpath(ref_dir, self.sources[str(self.seed_len)]['ref_wallet'])
 		return self.walletconv_in(wf)
 
-	def ref_mn_conv(self,ext='mmwords'):
-		wf = joinpath(ref_dir,self.seed_id+'.'+ext)
+	def ref_mn_conv(self, ext='mmwords'):
+		wf = joinpath(ref_dir, self.seed_id+'.'+ext)
 		return self.walletconv_in(wf)
 
 	def ref_bip39_conv(self):
@@ -114,28 +115,28 @@ class CmdTestWalletConv(CmdTestBase,CmdTestShared):
 		return self.ref_mn_conv(ext='b6d')
 
 	def ref_brain_conv(self):
-		uopts = ['-i','bw','-p','1','-l',str(self.seed_len)]
-		return self.walletconv_in(None,uopts,icls=get_wallet_cls('brain'))
+		uopts = ['-i', 'bw', '-p', '1', '-l', str(self.seed_len)]
+		return self.walletconv_in(None, uopts, icls=get_wallet_cls('brain'))
 
-	def ref_incog_conv(self,wfk='ic_wallet',in_fmt='i'):
-		uopts = ['-i',in_fmt,'-p','1','-l',str(self.seed_len)]
-		wf = joinpath(ref_dir,self.sources[str(self.seed_len)][wfk])
-		return self.walletconv_in(wf,uopts)
+	def ref_incog_conv(self, wfk='ic_wallet', in_fmt='i'):
+		uopts = ['-i', in_fmt, '-p', '1', '-l', str(self.seed_len)]
+		wf = joinpath(ref_dir, self.sources[str(self.seed_len)][wfk])
+		return self.walletconv_in(wf, uopts)
 
 	def ref_incox_conv(self):
-		return self.ref_incog_conv(in_fmt='xi',wfk='ic_wallet_hex')
+		return self.ref_incog_conv(in_fmt='xi', wfk='ic_wallet_hex')
 
-	def ref_hincog_conv(self,wfk='hic_wallet',add_uopts=[]):
-		ic_f = joinpath(ref_dir,self.sources[str(self.seed_len)][wfk])
-		uopts = ['-i','hi','-p','1','-l',str(self.seed_len)] + add_uopts
-		hi_opt = ['-H',f'{ic_f},{ref_wallet_incog_offset}']
+	def ref_hincog_conv(self, wfk='hic_wallet', add_uopts=[]):
+		ic_f = joinpath(ref_dir, self.sources[str(self.seed_len)][wfk])
+		uopts = ['-i', 'hi', '-p', '1', '-l', str(self.seed_len)] + add_uopts
+		hi_opt = ['-H', f'{ic_f},{ref_wallet_incog_offset}']
 		return self.walletconv_in(
 			None,
 			uopts + hi_opt,
-			icls = get_wallet_cls('incog_hidden') )
+			icls = get_wallet_cls('incog_hidden'))
 
 	def ref_hincog_conv_old(self):
-		return self.ref_hincog_conv(wfk='hic_wallet_old',add_uopts=['-O'])
+		return self.ref_hincog_conv(wfk='hic_wallet_old', add_uopts=['-O'])
 
 	def ref_wallet_conv_out(self):
 		return self.walletconv_out('w')
@@ -156,14 +157,15 @@ class CmdTestWalletConv(CmdTestBase,CmdTestShared):
 	def ref_incox_conv_out(self):
 		return self.walletconv_out('xi')
 
-	def ref_hincog_conv_out(self,ic_f=None):
+	def ref_hincog_conv_out(self, ic_f=None):
 		if not ic_f:
-			ic_f = joinpath(self.tmpdir,hincog_fn)
+			ic_f = joinpath(self.tmpdir, hincog_fn)
 		hi_parms = f'{ic_f},{ref_wallet_incog_offset}'
 		sl_parm = '-l' + str(self.seed_len)
-		return self.walletconv_out('hi',
-									uopts     = ['-J',hi_parms,sl_parm],
-									uopts_chk = ['-H',hi_parms,sl_parm] )
+		return self.walletconv_out(
+			'hi',
+			uopts     = ['-J', hi_parms, sl_parm],
+			uopts_chk = ['-H', hi_parms, sl_parm])
 
 	def ref_hincog_blkdev_conv_out(self):
 
@@ -179,41 +181,41 @@ class CmdTestWalletConv(CmdTestBase,CmdTestShared):
 		return 'ok'
 
 	# wallet conversion tests
-	def walletconv_in(self,infile,uopts=[],icls=None):
+	def walletconv_in(self, infile, uopts=[], icls=None):
 		ocls = get_wallet_cls('words')
-		opts = ['-d',self.tmpdir,'-o',ocls.fmt_codes[0],self.usr_rand_arg]
+		opts = ['-d', self.tmpdir, '-o', ocls.fmt_codes[0], self.usr_rand_arg]
 		if_arg = [infile] if infile else []
 		d = '(convert)'
-		t = self.spawn('mmgen-walletconv',opts+uopts+if_arg,extra_desc=d)
+		t = self.spawn('mmgen-walletconv', opts+uopts+if_arg, extra_desc=d)
 		t.license()
 		icls = icls or get_wallet_cls(ext=get_extension(infile))
 		if icls.type == 'brain':
-			t.expect('Enter brainwallet: ',ref_wallet_brainpass+'\n')
+			t.expect('Enter brainwallet: ', ref_wallet_brainpass+'\n')
 		if icls.enc and icls.type != 'brain':
-			t.passphrase(icls.desc,self.wpasswd)
+			t.passphrase(icls.desc, self.wpasswd)
 			if self.test_name[:19] == 'ref_hincog_conv_old':
-				t.expect('Is the Seed ID correct? (Y/n): ','\n')
+				t.expect('Is the Seed ID correct? (Y/n): ', '\n')
 			else:
-				t.expect(['Passphrase is OK',' are correct'])
+				t.expect(['Passphrase is OK', ' are correct'])
 		wf = t.written_to_file(capfirst(ocls.desc))
 		t.p.wait()
 		# back check of result
 		msg('' if cfg.profile else ' OK')
 		return self.walletchk(
-				wf,
-				extra_desc = '(check)',
-				sid        = self.seed_id)
+			wf,
+			extra_desc = '(check)',
+			sid        = self.seed_id)
 
-	def walletconv_out(self,out_fmt='w',uopts=[],uopts_chk=[]):
+	def walletconv_out(self, out_fmt='w', uopts=[], uopts_chk=[]):
 		wcls = get_wallet_cls(fmt_code=out_fmt)
-		opts = ['-d',self.tmpdir,'-p1','-o',out_fmt] + uopts
-		infile = joinpath(ref_dir,self.seed_id+'.mmwords')
-		t = self.spawn('mmgen-walletconv',[self.usr_rand_arg]+opts+[infile],extra_desc='(convert)')
+		opts = ['-d', self.tmpdir, '-p1', '-o', out_fmt] + uopts
+		infile = joinpath(ref_dir, self.seed_id+'.mmwords')
+		t = self.spawn('mmgen-walletconv', [self.usr_rand_arg]+opts+[infile], extra_desc='(convert)')
 
 		add_args = [f'-l{self.seed_len}']
 		t.license()
 		if wcls.enc and wcls.type != 'brain':
-			t.passphrase_new('new '+wcls.desc,self.wpasswd)
+			t.passphrase_new('new '+wcls.desc, self.wpasswd)
 			t.usr_rand(self.usr_rand_chars)
 		if wcls.type.startswith('incog'):
 			for _ in range(3):
@@ -229,8 +231,8 @@ class CmdTestWalletConv(CmdTestBase,CmdTestShared):
 			wf = None
 		msg('' if cfg.profile else ' OK')
 		return self.walletchk(
-				wf,
-				wcls       = wcls,
-				extra_desc = '(check)',
-				sid        = self.seed_id,
-				add_args   = add_args)
+			wf,
+			wcls       = wcls,
+			extra_desc = '(check)',
+			sid        = self.seed_id,
+			add_args   = add_args)

+ 42 - 42
test/cmdtest_py_d/ct_xmr_autosign.py

@@ -30,9 +30,9 @@ def make_burn_addr():
 		cfg     = cfg,
 		cmdname = 'privhex2addr',
 		proto   = cfg._proto,
-		mmtype  = 'monero' ).privhex2addr('beadcafe'*8)
+		mmtype  = 'monero').privhex2addr('beadcafe'*8)
 
-class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
+class CmdTestXMRAutosign(CmdTestXMRWallet, CmdTestAutosignThreaded):
 	"""
 	Monero autosigning operations
 	"""
@@ -99,10 +99,10 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 		('check_tx_dirs',            'cleaning and checking signable file directories'),
 	)
 
-	def __init__(self,trunner,cfgs,spawn):
+	def __init__(self, trunner, cfgs, spawn):
 
-		CmdTestAutosignThreaded.__init__(self,trunner,cfgs,spawn)
-		CmdTestXMRWallet.__init__(self,trunner,cfgs,spawn)
+		CmdTestAutosignThreaded.__init__(self, trunner, cfgs, spawn)
+		CmdTestXMRWallet.__init__(self, trunner, cfgs, spawn)
 
 		if trunner is None:
 			return
@@ -123,7 +123,7 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 		self.spawn_env['MMGEN_TEST_SUITE_XMR_AUTOSIGN'] = '1'
 
 	def create_tmp_wallets(self):
-		self.spawn('',msg_only=True)
+		self.spawn('', msg_only=True)
 		data = self.users['alice']
 		from mmgen.wallet import Wallet
 		from mmgen.xmrwallet import op
@@ -133,22 +133,22 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 			cfg       = self.cfg,
 			proto     = self.proto,
 			addr_idxs = '1-2',
-			seed      = Wallet(cfg,data.mmwords).seed,
+			seed      = Wallet(cfg, data.mmwords).seed,
 			skip_chksum_msg = True,
-			key_address_validity_check = False )
+			key_address_validity_check = False)
 		kal.file.write(ask_overwrite=False)
-		fn = get_file_with_ext(data.udir,'akeys')
+		fn = get_file_with_ext(data.udir, 'akeys')
 		m = op('create', self.cfg, fn, '1-2')
 		async_run(m.main())
 		async_run(m.stop_wallet_daemon())
 		end_silence()
 		return 'ok'
 
-	def _new_addr_alice(self,*args):
+	def _new_addr_alice(self, *args):
 		data = self.users['alice']
 		return self.new_addr_alice(
 			*args,
-			kafile = get_file_with_ext(data.udir,'akeys') )
+			kafile = get_file_with_ext(data.udir, 'akeys'))
 
 	def new_account_alice(self):
 		return self._new_addr_alice(
@@ -174,7 +174,7 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 	def dump_wallets(self):
 		return self._dump_wallets(autosign=True)
 
-	def _dump_wallets(self,autosign):
+	def _dump_wallets(self, autosign):
 		data = self.users['alice']
 		self.insert_device_online()
 		t = self.spawn(
@@ -183,27 +183,27 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 			+ [f'--wallet-dir={data.udir}', f'--daemon=localhost:{data.md.rpc_port}']
 			+ (self.autosign_opts if autosign else [])
 			+ ['dump']
-			+ ([] if autosign else [get_file_with_ext(data.udir,'akeys')]) )
+			+ ([] if autosign else [get_file_with_ext(data.udir, 'akeys')]))
 		t.expect('2 wallets dumped')
 		t.read()
 		self.remove_device_online()
 		return t
 
-	def _delete_files(self,*ext_list):
+	def _delete_files(self, *ext_list):
 		data = self.users['alice']
-		self.spawn('',msg_only=True)
+		self.spawn('', msg_only=True)
 		for ext in ext_list:
-			get_file_with_ext(data.udir,ext,no_dot=True,delete_all=True)
+			get_file_with_ext(data.udir, ext, no_dot=True, delete_all=True)
 		return 'ok'
 
 	def delete_tmp_wallets(self):
-		return self._delete_files( 'MoneroWallet', 'MoneroWallet.keys', '.akeys' )
+		return self._delete_files('MoneroWallet', 'MoneroWallet.keys', '.akeys')
 
 	def delete_wallets(self):
-		return self._delete_files( 'MoneroWatchOnlyWallet', '.keys', '.address.txt' )
+		return self._delete_files('MoneroWatchOnlyWallet', '.keys', '.address.txt')
 
 	def delete_tmp_dump_files(self):
-		return self._delete_files( '.dump' )
+		return self._delete_files('.dump')
 
 	def gen_kafile_miner(self):
 		return self.gen_kafiles(['miner'])
@@ -212,7 +212,7 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 		return self.create_wallets_miner()
 
 	def delete_dump_files(self):
-		return self._delete_files( '.dump' )
+		return self._delete_files('.dump')
 
 	def fund_alice1(self):
 		return self.fund_alice(wallet=1)
@@ -279,7 +279,7 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 
 	create_transfer_tx2a = create_transfer_tx2
 
-	def _abort_tx(self,expect,send=None,exit_val=None):
+	def _abort_tx(self, expect, send=None, exit_val=None):
 		self.insert_device_online()
 		t = self.spawn('mmgen-xmrwallet', ['--autosign', 'abort'], exit_val=exit_val)
 		t.expect(expect)
@@ -312,40 +312,40 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 			+ self.autosign_opts
 			+ [f'--wallet-dir={data.udir}', f'--daemon=localhost:{data.md.rpc_port}']
 			+ add_opts
-			+ [ op ]
-			+ ([get_file_with_ext(self.asi.xmr_tx_dir,ext)] if ext else [])
+			+ [op]
+			+ ([get_file_with_ext(self.asi.xmr_tx_dir, ext)] if ext else [])
 			+ ([wallet_arg] if wallet_arg else [])
 		)
 		desc_pfx = f'{desc}, ' if desc else ''
 		self.insert_device_online() # device must be removed by calling method
-		return self.spawn( 'mmgen-xmrwallet', args, extra_desc=f'({desc_pfx}Alice)' )
+		return self.spawn('mmgen-xmrwallet', args, extra_desc=f'({desc_pfx}Alice)')
 
-	def _sync_chkbal(self,wallet_arg,bal_chk_func):
+	def _sync_chkbal(self, wallet_arg, bal_chk_func):
 		return self.sync_wallets(
 			'alice',
 			op           = 'sync',
 			wallets      = wallet_arg,
-			bal_chk_func = bal_chk_func )
+			bal_chk_func = bal_chk_func)
 
 	def sync_chkbal1(self):
-		return self._sync_chkbal( '1', lambda n,b,ub: b == ub and 1 < b < 1.12 )
+		return self._sync_chkbal('1', lambda n, b, ub: b == ub and 1 < b < 1.12)
 		# 1.234567891234 - 0.124 = 1.110567891234 (minus fees)
 
 	def sync_chkbal2(self):
-		return self._sync_chkbal( '1', lambda n,b,ub: b == ub and 0.8 < b < 0.86 )
+		return self._sync_chkbal('1', lambda n, b, ub: b == ub and 0.8 < b < 0.86)
 		# 1.234567891234 - 0.124 - 0.257 = 0.853567891234 (minus fees)
 
 	def sync_chkbal3(self):
 		return self._sync_chkbal(
 			'1-2',
-			lambda n,b,ub: b == ub and ((n == 1 and 0.8 < b < 0.86) or (n == 2 and b > 1.23)) )
+			lambda n, b, ub: b == ub and ((n == 1 and 0.8 < b < 0.86) or (n == 2 and b > 1.23)))
 
-	def _mine_chk(self,desc):
-		bal_type = {'locked':'b','unlocked':'ub'}[desc]
+	def _mine_chk(self, desc):
+		bal_type = {'locked':'b', 'unlocked':'ub'}[desc]
 		return self.mine_chk(
 			'alice', 1, 0,
-			lambda x: 0 < getattr(x,bal_type) < 1.234567891234,
-			f'{desc} balance 0 < 1.234567891234' )
+			lambda x: 0 < getattr(x, bal_type) < 1.234567891234,
+			f'{desc} balance 0 < 1.234567891234')
 
 	def submit_transfer_tx1(self):
 		return self._submit_transfer_tx()
@@ -357,16 +357,16 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 				check_bal  = False)
 
 	def submit_transfer_tx2(self):
-		return self._submit_transfer_tx( relay_parm=self.tx_relay_daemon_parm )
+		return self._submit_transfer_tx(relay_parm=self.tx_relay_daemon_parm)
 
-	def _submit_transfer_tx(self,relay_parm=None,ext=None,op='submit',check_bal=True):
+	def _submit_transfer_tx(self, relay_parm=None, ext=None, op='submit', check_bal=True):
 		t = self._xmr_autosign_op(
 			op            = op,
 			add_opts      = [f'--tx-relay-daemon={relay_parm}'] if relay_parm else [],
 			ext           = ext,
 			signable_desc = 'transaction',
 			wait_signed   = op == 'submit')
-		t.expect( f'{op.capitalize()} transaction? (y/N): ', 'y' )
+		t.expect(f'{op.capitalize()} transaction? (y/N): ', 'y')
 		t.written_to_file('Submitted transaction')
 		t.read()
 		self.remove_device_online() # device was inserted by _xmr_autosign_op()
@@ -395,7 +395,7 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 	def export_outputs3(self):
 		return self._export_outputs('1-2', op='export-outputs-sign')
 
-	def _import_key_images(self,wallet_arg):
+	def _import_key_images(self, wallet_arg):
 		t = self._xmr_autosign_op(
 			op            = 'import-key-images',
 			wallet_arg    = wallet_arg,
@@ -413,12 +413,12 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 
 	def txlist(self):
 		self.insert_device_online()
-		t = self.spawn( 'mmgen-xmrwallet', self.autosign_opts + ['txlist'] )
+		t = self.spawn('mmgen-xmrwallet', self.autosign_opts + ['txlist'])
 		t.match_expect_list([
 			'SUBMITTED',
-			'Network','Submitted',
-			'transfer 1:0','-> ext',
-			'transfer 1:0','-> ext'
+			'Network', 'Submitted',
+			'transfer 1:0', '-> ext',
+			'transfer 1:0', '-> ext'
 		])
 		t.read()
 		self.remove_device_online()
@@ -466,7 +466,7 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 		imsg(f'\nBefore cleaning:\n{before}')
 		imsg(f'\nAfter cleaning:\n{after}')
 		pat = r'xmr/tx: \s*\S+\.subtx \S+\.subtx\s+xmr/outputs:\s*$'
-		assert re.search( pat, after, re.DOTALL ), f'regex search for {pat} failed'
+		assert re.search(pat, after, re.DOTALL), f'regex search for {pat} failed'
 		return t
 
 	def view(self):

+ 167 - 170
test/cmdtest_py_d/ct_xmrwallet.py

@@ -20,14 +20,14 @@
 test.cmdtest_py_d.ct_xmrwallet: xmrwallet tests for the cmdtest.py test suite
 """
 
-import sys,os,time,re,atexit,asyncio,shutil
-from subprocess import run,PIPE
+import sys, os, time, re, atexit, asyncio, shutil
+from subprocess import run, PIPE
 from collections import namedtuple
 
-from mmgen.util import msg,fmt,async_run,capfirst,is_int,die,list_gen
+from mmgen.util import msg, fmt, async_run, capfirst, is_int, die, list_gen
 from mmgen.obj import MMGenRange
 from mmgen.amt import XMRAmt
-from mmgen.addrlist import ViewKeyAddrList,KeyAddrList,AddrIdxList
+from mmgen.addrlist import ViewKeyAddrList, KeyAddrList, AddrIdxList
 
 from ..include.common import (
 	cfg,
@@ -56,10 +56,10 @@ def stop_daemons(self):
 def stop_miner_wallet_daemon(self):
 	async_run(self.users['miner'].wd_rpc.stop_daemon())
 
-def kill_proxy(cls,args):
+def kill_proxy(cls, args):
 	if sys.platform in ('linux', 'darwin'):
 		omsg(f'Killing SSH SOCKS server at localhost:{cls.socks_port}')
-		cmd = [ 'pkill', '-f', ' '.join(args) ]
+		cmd = ['pkill', '-f', ' '.join(args)]
 		run(cmd)
 
 class CmdTestXMRWallet(CmdTestBase):
@@ -81,66 +81,66 @@ class CmdTestXMRWallet(CmdTestBase):
 		('bob',   '1378FC64', False, 140, None,  ['--restricted-rpc']),
 	)
 	tx_relay_user = 'bob'
-	datadir_base = os.path.join('test','daemons','xmrtest')
+	datadir_base = os.path.join('test', 'daemons', 'xmrtest')
 
 	cmd_group = (
-		('daemon_version',            'checking daemon version'),
-		('gen_kafiles_miner_alice',   'generating key-address files for Miner and Alice'),
-		('create_wallets_miner',      'creating Monero wallets (Miner)'),
-		('set_label_miner',           'setting an address label (Miner, primary account)'),
-		('mine_initial_coins',        'mining initial coins'),
-		('create_wallets_alice',      'creating Monero wallets (Alice)'),
-		('fund_alice',                'sending funds'),
-		('check_bal_alice',           'mining, checking balance'),
-
-		('sync_wallets_all',          'syncing all wallets'),
-		('new_account_alice',         'creating a new account (Alice)'),
-		('new_account_alice_label',   'creating a new account (Alice, with label)'),
-		('new_address_alice',         'creating a new address (Alice)'),
-		('new_address_alice_label',   'creating a new address (Alice, with label)'),
-		('remove_label_alice',        'removing an address label (Alice, subaddress)'),
-		('set_label_alice',           'setting an address label (Alice, subaddress)'),
-		('sync_wallets_selected',     'syncing selected wallets'),
-
-		('sweep_to_wallet',           'sweeping to new account in another wallet'),
-		('sweep_to_account',          'sweeping to specific account in same wallet'),
-		('sweep_to_wallet_account',   'sweeping to specific account in another wallet'),
+		('daemon_version',                'checking daemon version'),
+		('gen_kafiles_miner_alice',       'generating key-address files for Miner and Alice'),
+		('create_wallets_miner',          'creating Monero wallets (Miner)'),
+		('set_label_miner',               'setting an address label (Miner, primary account)'),
+		('mine_initial_coins',            'mining initial coins'),
+		('create_wallets_alice',          'creating Monero wallets (Alice)'),
+		('fund_alice',                    'sending funds'),
+		('check_bal_alice',               'mining, checking balance'),
+
+		('sync_wallets_all',              'syncing all wallets'),
+		('new_account_alice',             'creating a new account (Alice)'),
+		('new_account_alice_label',       'creating a new account (Alice, with label)'),
+		('new_address_alice',             'creating a new address (Alice)'),
+		('new_address_alice_label',       'creating a new address (Alice, with label)'),
+		('remove_label_alice',            'removing an address label (Alice, subaddress)'),
+		('set_label_alice',               'setting an address label (Alice, subaddress)'),
+		('sync_wallets_selected',         'syncing selected wallets'),
+
+		('sweep_to_wallet',               'sweeping to new account in another wallet'),
+		('sweep_to_account',              'sweeping to specific account in same wallet'),
+		('sweep_to_wallet_account',       'sweeping to specific account in another wallet'),
 		('sweep_to_wallet_account_proxy', 'sweeping to specific account in another wallet (via TX relay + proxy)'),
 		('sweep_to_same_account_noproxy', 'sweeping to same account (via TX relay, no proxy)'),
-		('transfer_to_miner_proxy',   'transferring funds to Miner (via TX relay + proxy)'),
-		('transfer_to_miner_noproxy', 'transferring funds to Miner (via TX relay, no proxy)'),
+		('transfer_to_miner_proxy',       'transferring funds to Miner (via TX relay + proxy)'),
+		('transfer_to_miner_noproxy',     'transferring funds to Miner (via TX relay, no proxy)'),
 
-		('transfer_to_miner_create1', 'transferring funds to Miner (create TX)'),
-		('transfer_to_miner_send1',   'transferring funds to Miner (send TX via proxy)'),
-		('transfer_to_miner_create2', 'transferring funds to Miner (create TX)'),
-		('transfer_to_miner_send2',   'transferring funds to Miner (send TX, no proxy)'),
+		('transfer_to_miner_create1',     'transferring funds to Miner (create TX)'),
+		('transfer_to_miner_send1',       'transferring funds to Miner (send TX via proxy)'),
+		('transfer_to_miner_create2',     'transferring funds to Miner (create TX)'),
+		('transfer_to_miner_send2',       'transferring funds to Miner (send TX, no proxy)'),
 
-		('sweep_create_and_send',     'sweeping to new account (create TX + send TX, in stages)'),
-		('list_wallets_all',          'listing wallets'),
-		('stop_daemons',              'stopping all wallet and coin daemons'),
+		('sweep_create_and_send',         'sweeping to new account (create TX + send TX, in stages)'),
+		('list_wallets_all',              'listing wallets'),
+		('stop_daemons',                  'stopping all wallet and coin daemons'),
 	)
 
-	def __init__(self,trunner,cfgs,spawn):
-		CmdTestBase.__init__(self,trunner,cfgs,spawn)
+	def __init__(self, trunner, cfgs, spawn):
+		CmdTestBase.__init__(self, trunner, cfgs, spawn)
 		if trunner is None:
 			return
 
 		from mmgen.protocol import init_proto
-		self.proto = init_proto( cfg, 'XMR', network='mainnet' )
+		self.proto = init_proto(cfg, 'XMR', network='mainnet')
 		self.extra_opts = ['--wallet-rpc-password=passw0rd']
 		self.init_users()
 		self.init_daemon_args()
 
 		for v in self.users.values():
-			run(['mkdir','-p',v.udir])
+			run(['mkdir', '-p', v.udir])
 
-		self.tx_relay_daemon_parm = 'localhost:{}'.format( self.users[self.tx_relay_user].md.rpc_port )
+		self.tx_relay_daemon_parm = 'localhost:{}'.format(self.users[self.tx_relay_user].md.rpc_port)
 		self.tx_relay_daemon_proxy_parm = (
-			self.tx_relay_daemon_parm + f':127.0.0.1:{self.socks_port}' ) # must be IP, not 'localhost'
+			self.tx_relay_daemon_parm + f':127.0.0.1:{self.socks_port}') # must be IP, not 'localhost'
 
 		if not cfg.no_daemon_stop:
-			atexit.register(stop_daemons,self)
-			atexit.register(stop_miner_wallet_daemon,self)
+			atexit.register(stop_daemons, self)
+			atexit.register(stop_miner_wallet_daemon, self)
 
 		if not cfg.no_daemon_autostart:
 			stop_daemons(self)
@@ -156,12 +156,12 @@ class CmdTestXMRWallet(CmdTestBase):
 	# init methods
 
 	@classmethod
-	def init_proxy(cls,external_call=False):
+	def init_proxy(cls, external_call=False):
 
 		def port_in_use(port):
 			import socket
 			try:
-				socket.create_connection(('localhost',port)).close()
+				socket.create_connection(('localhost', port)).close()
 			except:
 				return False
 			else:
@@ -172,16 +172,16 @@ class CmdTestXMRWallet(CmdTestBase):
 				run(a+b2)
 				omsg(f'SSH SOCKS server started, listening at localhost:{cls.socks_port}')
 
-		debug_file = os.path.join('' if external_call else cls.datadir_base,'txrelay-proxy.debug')
-		a = ['ssh','-x','-o','ExitOnForwardFailure=True','-D',f'localhost:{cls.socks_port}']
-		b0 = ['-o','PasswordAuthentication=False']
-		b1 = ['localhost','true']
-		b2 = ['-fN','-E', debug_file, 'localhost']
+		debug_file = os.path.join('' if external_call else cls.datadir_base, 'txrelay-proxy.debug')
+		a = ['ssh', '-x', '-o', 'ExitOnForwardFailure=True', '-D', f'localhost:{cls.socks_port}']
+		b0 = ['-o', 'PasswordAuthentication=False']
+		b1 = ['localhost', 'true']
+		b2 = ['-fN', '-E', debug_file, 'localhost']
 
 		if port_in_use(cls.socks_port):
 			omsg(f'Port {cls.socks_port} already in use.  Assuming SSH SOCKS server is running')
 		else:
-			cp = run(a+b0+b1,stdout=PIPE,stderr=PIPE)
+			cp = run(a+b0+b1, stdout=PIPE, stderr=PIPE)
 			err = cp.stderr.decode()
 			if err:
 				omsg(err)
@@ -189,12 +189,12 @@ class CmdTestXMRWallet(CmdTestBase):
 			if cp.returncode == 0:
 				start_proxy()
 			elif 'onnection refused' in err:
-				die(2,fmt("""
+				die(2, fmt("""
 					The SSH daemon must be running and listening on localhost in order to test
 					XMR TX relaying via SOCKS proxy.  If sshd is not running, please start it.
 					Otherwise, add the line 'ListenAddress 127.0.0.1' to your sshd_config, and
 					then restart the daemon.
-				""",indent='    '))
+				""", indent='    '))
 			elif 'ermission denied' in err:
 				msg(fmt(f"""
 					In order to test XMR TX relaying via SOCKS proxy, it’s desirable to enable
@@ -211,21 +211,21 @@ class CmdTestXMRWallet(CmdTestBase):
 					   following command, and restart the test:
 
 					      {' '.join(a+b2)}
-				""",indent='    ',strip_char='\t'))
+				""", indent='    ', strip_char='\t'))
 
 				from mmgen.ui import keypress_confirm
-				if keypress_confirm(cfg,'Continue?'):
+				if keypress_confirm(cfg, 'Continue?'):
 					start_proxy()
 				else:
-					die(1,'Exiting at user request')
+					die(1, 'Exiting at user request')
 			else:
-				die(2,fmt(f"""
+				die(2, fmt(f"""
 					Please start the SSH SOCKS proxy by entering the following command:
 
 						{' '.join(a+b2)}
 
 					Then restart the test.
-				""",indent='    '))
+				""", indent='    '))
 
 		if not (external_call or cfg.no_daemon_stop):
 			atexit.unregister(kill_proxy)
@@ -236,10 +236,10 @@ class CmdTestXMRWallet(CmdTestBase):
 	def init_users(self):
 		from mmgen.daemon import CoinDaemon
 		from mmgen.proto.xmr.daemon import MoneroWalletDaemon
-		from mmgen.proto.xmr.rpc import MoneroRPCClient,MoneroWalletRPCClient
+		from mmgen.proto.xmr.rpc import MoneroRPCClient, MoneroWalletRPCClient
 		self.users = {}
 		tmpdir_num = self.tmpdir_nums[0]
-		ud = namedtuple('user_data',[
+		ud = namedtuple('user_data', [
 			'sid',
 			'mmwords',
 			'autosign',
@@ -256,15 +256,16 @@ class CmdTestXMRWallet(CmdTestBase):
 			'add_coind_args',
 		])
 		# kal_range must be None, a single digit, or a single hyphenated range
-		for (   user,
+		for (
+				user,
 				sid,
 				autosign,
 				shift,
 				kal_range,
-				add_coind_args ) in self.user_data:
-			tmpdir = os.path.join('test','tmp',str(tmpdir_num))
-			udir = os.path.join(tmpdir,user)
-			datadir = os.path.join(self.datadir_base,user)
+				add_coind_args) in self.user_data:
+			tmpdir = os.path.join('test', 'tmp', str(tmpdir_num))
+			udir = os.path.join(tmpdir, user)
+			datadir = os.path.join(self.datadir_base, user)
 			md = CoinDaemon(
 				cfg        = cfg,
 				proto      = self.proto,
@@ -284,13 +285,13 @@ class CmdTestXMRWallet(CmdTestBase):
 				daemon = md,
 			)
 			wd = MoneroWalletDaemon(
-				cfg        = cfg,
-				proto      = self.proto,
-				test_suite = True,
-				wallet_dir = udir,
-				user       = 'foo',
-				passwd     = 'bar',
-				port_shift = shift,
+				cfg          = cfg,
+				proto        = self.proto,
+				test_suite   = True,
+				wallet_dir   = udir,
+				user         = 'foo',
+				passwd       = 'bar',
+				port_shift   = shift,
 				monerod_addr = f'127.0.0.1:{md.rpc_port}',
 			)
 			wd_rpc = MoneroWalletRPCClient(
@@ -307,53 +308,53 @@ class CmdTestXMRWallet(CmdTestBase):
 				fn_stem    = 'MoneroWallet'
 				kafile_dir = udir
 			self.users[user] = ud(
-				sid           = sid,
-				mmwords       = f'test/ref/{sid}.mmwords',
-				autosign      = autosign,
-				udir          = udir,
-				datadir       = datadir,
-				kal_range     = kal_range,
-				kafile        = f'{kafile_dir}/{sid}-XMR-M[{kal_range}].{kafile_suf}',
-				walletfile_fs = f'{udir}/{sid}-{{}}-{fn_stem}',
-				addrfile_fs   = f'{udir}/{sid}-{{}}-{fn_stem}.address.txt',
-				md            = md,
-				md_rpc        = md_rpc,
-				wd            = wd,
-				wd_rpc        = wd_rpc,
+				sid            = sid,
+				mmwords        = f'test/ref/{sid}.mmwords',
+				autosign       = autosign,
+				udir           = udir,
+				datadir        = datadir,
+				kal_range      = kal_range,
+				kafile         = f'{kafile_dir}/{sid}-XMR-M[{kal_range}].{kafile_suf}',
+				walletfile_fs  = f'{udir}/{sid}-{{}}-{fn_stem}',
+				addrfile_fs    = f'{udir}/{sid}-{{}}-{fn_stem}.address.txt',
+				md             = md,
+				md_rpc         = md_rpc,
+				wd             = wd,
+				wd_rpc         = wd_rpc,
 				add_coind_args = add_coind_args,
 			)
 
 	def init_daemon_args(self):
-		common_args = ['--p2p-bind-ip=127.0.0.1','--fixed-difficulty=1','--regtest'] # ,'--rpc-ssl-allow-any-cert']
+		common_args = ['--p2p-bind-ip=127.0.0.1', '--fixed-difficulty=1', '--regtest'] # --rpc-ssl-allow-any-cert
 		for u in self.users:
 			other_ports = [self.users[u2].md.p2p_port for u2 in self.users if u2 != u]
 			node_args = [f'--add-exclusive-node=127.0.0.1:{p}' for p in other_ports]
 			self.users[u].md.usr_coind_args = (
-				common_args +
-				node_args +
-				self.users[u].add_coind_args )
+				common_args
+				+ node_args
+				+ self.users[u].add_coind_args)
 
 	# cmd_group methods
 
 	def daemon_version(self):
 		rpc_port = self.users['miner'].md.rpc_port
-		return self.spawn( 'mmgen-tool', ['--coin=xmr', f'--rpc-port={rpc_port}', 'daemon_version'] )
+		return self.spawn('mmgen-tool', ['--coin=xmr', f'--rpc-port={rpc_port}', 'daemon_version'])
 
 	def gen_kafiles_miner_alice(self):
 		return self.gen_kafiles(['miner', 'alice'])
 
 	def gen_kafiles(self, users):
-		for user,data in self.users.items():
+		for user, data in self.users.items():
 			if not user in users:
 				continue
-			run(['mkdir','-p',data.udir])
-			run(f'rm -f {data.kafile}',shell=True)
+			run(['mkdir', '-p', data.udir])
+			run(f'rm -f {data.kafile}', shell=True)
 			t = self.spawn(
 				'mmgen-keygen', [
 					'-q', '--accept-defaults', '--coin=xmr',
 					f'--outdir={data.udir}', data.mmwords, data.kal_range
 				],
-				extra_desc = f'({capfirst(user)})' )
+				extra_desc = f'({capfirst(user)})')
 			t.read()
 			t.ok()
 		t.skip_ok = True
@@ -365,15 +366,15 @@ class CmdTestXMRWallet(CmdTestBase):
 	def create_wallets_alice(self):
 		return self.create_wallets('alice')
 
-	def create_wallets(self,user,wallet=None,add_opts=[],op='create'):
+	def create_wallets(self, user, wallet=None, add_opts=[], op='create'):
 		assert wallet is None or is_int(wallet), 'wallet arg'
 		data = self.users[user]
 		stem_glob = data.walletfile_fs.format(wallet or '*')
 		for glob in (
 				stem_glob,
 				stem_glob + '.keys',
-				stem_glob + '.address.txt' ):
-			run( f'rm -f {glob}', shell=True )
+				stem_glob + '.address.txt'):
+			run(f'rm -f {glob}', shell=True)
 		t = self.spawn(
 			'mmgen-xmrwallet',
 			[f'--wallet-dir={data.udir}']
@@ -393,15 +394,15 @@ class CmdTestXMRWallet(CmdTestBase):
 			)
 		return t
 
-	def new_addr_alice(self,spec,cfg,expect,kafile=None):
+	def new_addr_alice(self, spec, cfg, expect, kafile=None):
 		data = self.users['alice']
 		t = self.spawn(
 			'mmgen-xmrwallet',
 			self.extra_opts
 			+ [f'--wallet-dir={data.udir}']
 			+ [f'--daemon=localhost:{data.md.rpc_port}']
-			+ (['--no-start-wallet-daemon'] if cfg in ('continue','stop') else [])
-			+ (['--no-stop-wallet-daemon'] if cfg in ('start','continue') else [])
+			+ (['--no-start-wallet-daemon'] if cfg in ('continue', 'stop') else [])
+			+ (['--no-stop-wallet-daemon'] if cfg in ('start', 'continue') else [])
 			+ ['new', (kafile or data.kafile), spec])
 		t.expect(expect, 'y', regex=True)
 		return t
@@ -434,10 +435,10 @@ class CmdTestXMRWallet(CmdTestBase):
 
 	async def mine_initial_coins(self):
 		self.spawn('', msg_only=True, extra_desc='(opening wallet)')
-		await self.open_wallet_user('miner',1)
+		await self.open_wallet_user('miner', 1)
 		ok()
 		# NB: a large balance is required to avoid ‘insufficient outputs’ error
-		return await self.mine_chk('miner',1,0,lambda x: x.ub > 2000,'unlocked balance > 2000')
+		return await self.mine_chk('miner', 1, 0, lambda x: x.ub > 2000, 'unlocked balance > 2000')
 
 	async def fund_alice(self, wallet=1, amt=1234567891234):
 		self.spawn('', msg_only=True, extra_desc='(transferring funds from Miner wallet)')
@@ -451,7 +452,7 @@ class CmdTestXMRWallet(CmdTestBase):
 	async def check_bal_alice(self, wallet=1, bal='1.234567891234'):
 		return await self.mine_chk(
 			'alice', wallet, 0,
-			lambda x: str(x.ub) == bal,f'unlocked balance == {bal}',
+			lambda x: str(x.ub) == bal, f'unlocked balance == {bal}',
 			random_txs = self.dfl_random_txs
 		)
 
@@ -474,7 +475,7 @@ class CmdTestXMRWallet(CmdTestBase):
 			+ cmd_opts
 			+ ['label', data.kafile, label_spec]
 		)
-		t.expect('(y/N): ','y')
+		t.expect('(y/N): ', 'y')
 		t.expect(f'Label successfully {expect}')
 		return t
 
@@ -496,7 +497,7 @@ class CmdTestXMRWallet(CmdTestBase):
 	def sync_wallets_miner(self):
 		return self.sync_wallets('miner')
 
-	def sync_wallets(self,user,op='sync',wallets=None,add_opts=[],bal_chk_func=None):
+	def sync_wallets(self, user, op='sync', wallets=None, add_opts=[], bal_chk_func=None):
 		data = self.users[user]
 		if data.autosign:
 			self.insert_device_online()
@@ -515,22 +516,22 @@ class CmdTestXMRWallet(CmdTestBase):
 			+ ([wallets] if wallets else [])
 		)
 		wlist = AddrIdxList(wallets) if wallets else MMGenRange(data.kal_range).items
-		for n,wnum in enumerate(wlist,1):
+		for n, wnum in enumerate(wlist, 1):
 			t.expect('ing wallet {}/{} ({})'.format(
 				n,
 				len(wlist),
 				os.path.basename(data.walletfile_fs.format(wnum)),
 			))
-			if op in ('view','listview'):
+			if op in ('view', 'listview'):
 				t.expect('Wallet height: ')
 			else:
 				t.expect('Chain height: ')
 				t.expect('Wallet height: ')
 				res = strip_ansi_escapes(t.expect_getend('Balance: '))
 				if bal_chk_func:
-					m = re.match( r'(\S+) Unlocked balance: (\S+)', res, re.DOTALL )
+					m = re.match(r'(\S+) Unlocked balance: (\S+)', res, re.DOTALL)
 					amts = [XMRAmt(amt) for amt in m.groups()]
-					assert bal_chk_func(n,*amts), f'balance check for wallet {n} failed!'
+					assert bal_chk_func(n, *amts), f'balance check for wallet {n} failed!'
 		if data.autosign:
 			t.read()
 			self.remove_device_online()
@@ -567,27 +568,24 @@ class CmdTestXMRWallet(CmdTestBase):
 			+ [op]
 			+ ([] if data.autosign else [data.kafile])
 			+ [arg2],
-			extra_desc = f'({capfirst(user)}{add_desc})' )
+			extra_desc = f'({capfirst(user)}{add_desc})')
 
 		if op == 'sign':
 			return t
 
 		if op in ('sweep', 'sweep_all'):
 			desc = 'address' if re.match(r'.*:\d+$', arg2) else 'account'
-			t.expect(
-				rf'Create new {desc} .* \(y/N\): ',
-				('y','n')[use_existing],
-				regex=True )
+			t.expect(rf'Create new {desc} .* \(y/N\): ', ('y', 'n')[use_existing], regex=True)
 			if use_existing:
 				t.expect(rf'to last existing {desc} .* \(y/N\): ', 'y', regex=True)
 
 		dtype = 'unsigned' if data.autosign else 'signed'
-		t.expect(f'Save {dtype} transaction? (y/N): ','y')
+		t.expect(f'Save {dtype} transaction? (y/N): ', 'y')
 		t.written_to_file(f'{dtype.capitalize()} transaction')
 
 		if not no_relay:
-			t.expect(f'Relay {op} transaction? (y/N): ','y')
-			get_file_with_ext(self.users[user].udir,'sigtx',delete_all=True)
+			t.expect(f'Relay {op} transaction? (y/N): ', 'y')
+			get_file_with_ext(self.users[user].udir, 'sigtx', delete_all=True)
 
 		t.read()
 
@@ -616,22 +614,22 @@ class CmdTestXMRWallet(CmdTestBase):
 	async def transfer_to_miner_proxy(self):
 		addr = read_from_file(self.users['miner'].addrfile_fs.format(2))
 		amt = '0.135'
-		self.do_op('transfer','alice',f'2:1:{addr},{amt}',self.tx_relay_daemon_proxy_parm)
+		self.do_op('transfer', 'alice', f'2:1:{addr},{amt}', self.tx_relay_daemon_proxy_parm)
 		await self.stop_wallet_user('miner')
-		await self.open_wallet_user('miner',2)
-		await self.mine_chk('miner',2,0,lambda x: str(x.ub) == amt,f'unlocked balance == {amt}')
+		await self.open_wallet_user('miner', 2)
+		await self.mine_chk('miner', 2, 0, lambda x: str(x.ub) == amt, f'unlocked balance == {amt}')
 		ok()
-		return await self.mine_chk('alice',2,1,lambda x: x.ub > 0.9,'unlocked balance > 0.9')
+		return await self.mine_chk('alice', 2, 1, lambda x: x.ub > 0.9, 'unlocked balance > 0.9')
 
 	async def transfer_to_miner_noproxy(self):
 		addr = read_from_file(self.users['miner'].addrfile_fs.format(2))
 		self.do_op('transfer', 'alice', f'2:1:{addr},0.0995', self.tx_relay_daemon_parm, add_opts=['--full-address'])
-		await self.mine_chk('miner',2,0,lambda x: str(x.ub) == '0.2345','unlocked balance == 0.2345')
+		await self.mine_chk('miner', 2, 0, lambda x: str(x.ub) == '0.2345', 'unlocked balance == 0.2345')
 		ok()
-		return await self.mine_chk('alice',2,1,lambda x: x.ub > 0.9,'unlocked balance > 0.9')
+		return await self.mine_chk('alice', 2, 1, lambda x: x.ub > 0.9, 'unlocked balance > 0.9')
 
-	def transfer_to_miner_create(self,amt):
-		get_file_with_ext(self.users['alice'].udir,'sigtx',delete_all=True)
+	def transfer_to_miner_create(self, amt):
+		get_file_with_ext(self.users['alice'].udir, 'sigtx', delete_all=True)
 		addr = read_from_file(self.users['miner'].addrfile_fs.format(2))
 		return self.do_op('transfer', 'alice', f'2:1:{addr},{amt}', no_relay=True, do_ret=True, add_opts=['-Ee'])
 
@@ -641,31 +639,31 @@ class CmdTestXMRWallet(CmdTestBase):
 	def transfer_to_miner_create2(self):
 		return self.transfer_to_miner_create('0.0012')
 
-	def relay_tx(self,relay_opt,add_desc=None):
+	def relay_tx(self, relay_opt, add_desc=None):
 		user = 'alice'
 		data = self.users[user]
 		add_desc = (', ' + add_desc) if add_desc else ''
 		t = self.spawn(
 			'mmgen-xmrwallet',
 			self.extra_opts
-			+ [ relay_opt, 'relay', get_file_with_ext(data.udir,'sigtx') ],
-			extra_desc = f'(relaying TX, {capfirst(user)}{add_desc})' )
-		t.expect('Relay transaction? ','y')
+			+ [relay_opt, 'relay', get_file_with_ext(data.udir, 'sigtx')],
+			extra_desc = f'(relaying TX, {capfirst(user)}{add_desc})')
+		t.expect('Relay transaction? ', 'y')
 		t.read()
 		t.ok()
 		return t
 
 	async def transfer_to_miner_send1(self):
-		self.relay_tx(f'--tx-relay-daemon={self.tx_relay_daemon_proxy_parm}',add_desc='via proxy')
-		await self.mine_chk('miner',2,0,lambda x: str(x.ub) == '0.2456','unlocked balance == 0.2456')
+		self.relay_tx(f'--tx-relay-daemon={self.tx_relay_daemon_proxy_parm}', add_desc='via proxy')
+		await self.mine_chk('miner', 2, 0, lambda x: str(x.ub) == '0.2456', 'unlocked balance == 0.2456')
 		ok()
-		return await self.mine_chk('alice',2,1,lambda x: x.ub > 0.9,'unlocked balance > 0.9')
+		return await self.mine_chk('alice', 2, 1, lambda x: x.ub > 0.9, 'unlocked balance > 0.9')
 
 	async def transfer_to_miner_send2(self):
-		self.relay_tx(f'--tx-relay-daemon={self.tx_relay_daemon_parm}',add_desc='no proxy')
-		await self.mine_chk('miner',2,0,lambda x: str(x.ub) == '0.2468','unlocked balance == 0.2468')
+		self.relay_tx(f'--tx-relay-daemon={self.tx_relay_daemon_parm}', add_desc='no proxy')
+		await self.mine_chk('miner', 2, 0, lambda x: str(x.ub) == '0.2468', 'unlocked balance == 0.2468')
 		ok()
-		return await self.mine_chk('alice',2,1,lambda x: x.ub > 0.9,'unlocked balance > 0.9')
+		return await self.mine_chk('alice', 2, 1, lambda x: x.ub > 0.9, 'unlocked balance > 0.9')
 
 	async def sweep_create_and_send(self):
 		get_file_with_ext(self.users['alice'].udir, 'sigtx', delete_all=True)
@@ -680,7 +678,7 @@ class CmdTestXMRWallet(CmdTestBase):
 
 	# wallet methods
 
-	async def open_wallet_user(self,user,wnum):
+	async def open_wallet_user(self, user, wnum):
 		data = self.users[user]
 		if data.autosign:
 			self.insert_device_online()
@@ -691,7 +689,7 @@ class CmdTestXMRWallet(CmdTestBase):
 			proto    = self.proto,
 			addrfile = data.kafile,
 			skip_chksum_msg = True,
-			key_address_validity_check = False )
+			key_address_validity_check = False)
 		end_silence()
 		if data.autosign:
 			self.do_umount_online()
@@ -700,9 +698,9 @@ class CmdTestXMRWallet(CmdTestBase):
 		return data.wd_rpc.call(
 			'open_wallet',
 			filename = os.path.basename(data.walletfile_fs.format(wnum)),
-			password = kal.entry(wnum).wallet_passwd )
+			password = kal.entry(wnum).wallet_passwd)
 
-	async def stop_wallet_user(self,user):
+	async def stop_wallet_user(self, user):
 		await self.users[user].wd_rpc.stop_daemon(silent=not (cfg.exact_output or cfg.verbose))
 		return 'ok'
 
@@ -725,7 +723,7 @@ class CmdTestXMRWallet(CmdTestBase):
 					await self.start_mining()
 				else:
 					raise
-		die(2,'Restart attempt limit exceeded')
+		die(2, 'Restart attempt limit exceeded')
 
 	async def mine10(self):
 		return await self.mine(10)
@@ -736,7 +734,7 @@ class CmdTestXMRWallet(CmdTestBase):
 	async def mine100(self):
 		return await self.mine(100)
 
-	async def mine(self,nblks):
+	async def mine(self, nblks):
 		start_height = height = await self._get_height()
 		imsg(f'Height: {height}')
 		imsg_r(f'Mining {nblks} blocks...')
@@ -761,7 +759,7 @@ class CmdTestXMRWallet(CmdTestBase):
 				do_background_mining = False, # run mining in background or foreground
 				ignore_battery       = True,  # ignore battery state (on laptop)
 				miner_address        = addr,  # account address to mine to
-				threads_count        = 1 )    # number of mining threads to run
+				threads_count        = 1)    # number of mining threads to run
 			status = self.get_status(ret)
 			if status == 'OK':
 				return True
@@ -769,8 +767,8 @@ class CmdTestXMRWallet(CmdTestBase):
 				await asyncio.sleep(5)
 				omsg('Daemon busy.  Attempting to start mining...')
 			else:
-				die(2,f'Monerod returned status {status}')
-		die(2,'Max retries exceeded')
+				die(2, f'Monerod returned status {status}')
+		die(2, 'Max retries exceeded')
 
 	async def stop_mining(self):
 		ret = self.users['miner'].md_rpc.call_raw('stop_mining')
@@ -786,7 +784,7 @@ class CmdTestXMRWallet(CmdTestBase):
 			test2      = None,
 			test2_desc = None,
 			random_txs = None,
-			return_bal = False ):
+			return_bal = False):
 
 		"""
 		- open destination wallet
@@ -800,7 +798,7 @@ class CmdTestXMRWallet(CmdTestBase):
 		async def send_random_txs():
 			from mmgen.tool.api import tool_api
 			t = tool_api(cfg)
-			t.init_coin('XMR','mainnet')
+			t.init_coin('XMR', 'mainnet')
 			t.usr_randchars = 0
 			imsg_r('Sending random transactions: ')
 			for i in range(random_txs):
@@ -814,7 +812,7 @@ class CmdTestXMRWallet(CmdTestBase):
 				await asyncio.sleep(0.5)
 			imsg('')
 
-		def print_balance(dest,bal_info):
+		def print_balance(dest, bal_info):
 			imsg('Total balances in {}’s wallet {}, account #{}: {} (total), {} (unlocked)'.format(
 				capfirst(dest.user),
 				dest.wnum,
@@ -823,32 +821,31 @@ class CmdTestXMRWallet(CmdTestBase):
 				bal_info.ub.hl(),
 			))
 
-		async def get_balance(dest,count):
+		async def get_balance(dest, count):
 			data = self.users[dest.user]
 			data.wd_rpc.call('refresh')
 			if count and not count % 20:
 				data.wd_rpc.call('rescan_blockchain')
 			ret = data.wd_rpc.call('get_accounts')['subaddress_accounts'][dest.account]
-			d_tup = namedtuple('bal_info',['b','ub'])
+			d_tup = namedtuple('bal_info', ['b', 'ub'])
 			return d_tup(
-				b  = XMRAmt(ret['balance'],from_unit='atomic'),
-				ub = XMRAmt(ret['unlocked_balance'],from_unit='atomic')
-			)
+				b  = XMRAmt(ret['balance'], from_unit='atomic'),
+				ub = XMRAmt(ret['unlocked_balance'], from_unit='atomic'))
 
 		# start execution:
 
 		self.do_msg(extra_desc =
 			(f'sending {random_txs} random TXs, ' if random_txs else '') +
-			f'mining, checking wallet {user}:{wnum}:{account}' )
+			f'mining, checking wallet {user}:{wnum}:{account}')
 
 		dest = namedtuple(
-			'dest_info',['user','wnum','account','test','test_desc','test2','test2_desc'])(
-				user,wnum,account,test,test_desc,test2,test2_desc)
+			'dest_info', ['user', 'wnum', 'account', 'test', 'test_desc', 'test2', 'test2_desc'])(
+				user, wnum, account, test, test_desc, test2, test2_desc)
 
 		if dest.user != 'miner':
-			await self.open_wallet_user(dest.user,dest.wnum)
+			await self.open_wallet_user(dest.user, dest.wnum)
 
-		bal_info_start = await get_balance(dest,0)
+		bal_info_start = await get_balance(dest, 0)
 		chk_bal_chg = dest.test(bal_info_start) == 'chk_bal_chg'
 
 		if random_txs:
@@ -859,16 +856,16 @@ class CmdTestXMRWallet(CmdTestBase):
 		h = await self._get_height()
 		imsg_r(f'Chain height: {h} ')
 
-		max_iterations,min_height = (300,64) if sys.platform == 'win32' else (50,300)
+		max_iterations, min_height = (300, 64) if sys.platform == 'win32' else (50, 300)
 		verbose = False
 
 		for count in range(max_iterations):
-			bal_info = await get_balance(dest,count)
+			bal_info = await get_balance(dest, count)
 			if h > min_height:
 				if dest.test(bal_info) is True or (chk_bal_chg and bal_info.ub != bal_info_start.ub):
 					imsg('')
 					oqmsg_r('+')
-					print_balance(dest,bal_info)
+					print_balance(dest, bal_info)
 					if dest.test2:
 						assert dest.test2(bal_info) is True, f'test failed: {dest.test2_desc} ({bal_info})'
 					break
@@ -878,13 +875,13 @@ class CmdTestXMRWallet(CmdTestBase):
 				if not verbose:
 					imsg('')
 				imsg_r(f'Height: {h}, ')
-				print_balance(dest,bal_info)
+				print_balance(dest, bal_info)
 				verbose = True
 			else:
 				imsg_r(f'{h} ')
 				oqmsg_r('+')
 		else:
-			die(2,f'Timeout exceeded, balance {bal_info.ub!r}')
+			die(2, f'Timeout exceeded, balance {bal_info.ub!r}')
 
 		await self.stop_mining()
 
@@ -895,26 +892,26 @@ class CmdTestXMRWallet(CmdTestBase):
 
 	# util methods
 
-	def get_status(self,ret):
+	def get_status(self, ret):
 		if ret['status'] != 'OK':
-			imsg( 'RPC status: {}'.format( ret['status'] ))
+			imsg('RPC status: {}'.format(ret['status']))
 		return ret['status']
 
-	def do_msg(self,extra_desc=None):
+	def do_msg(self, extra_desc=None):
 		self.spawn(
 			'',
 			msg_only = True,
 			extra_desc = f'({extra_desc})' if extra_desc else None
 		)
 
-	async def transfer(self,user,amt,addr):
-		return self.users[user].wd_rpc.call('transfer',destinations=[{'amount':amt,'address':addr}])
+	async def transfer(self, user, amt, addr):
+		return self.users[user].wd_rpc.call('transfer', destinations=[{'amount':amt, 'address':addr}])
 
 	# daemon start/stop methods
 
 	def start_daemons(self):
 		for v in self.users.values():
-			run(['mkdir','-p',v.datadir])
+			run(['mkdir', '-p', v.datadir])
 			v.md.start()
 
 	def stop_daemons(self):

+ 12 - 12
test/cmdtest_py_d/input.py

@@ -14,13 +14,13 @@ import time
 from .common import randbool
 from ..include.common import getrand
 
-def stealth_mnemonic_entry(t,mne,mn,entry_mode,pad_entry=False):
+def stealth_mnemonic_entry(t, mne, mn, entry_mode, pad_entry=False):
 
-	def pad_mnemonic(mn,ss_len):
+	def pad_mnemonic(mn, ss_len):
 		def get_pad_chars(n):
 			ret = ''
 			for _ in range(n):
-				m = int.from_bytes(getrand(1),'big') % 32
+				m = int.from_bytes(getrand(1), 'big') % 32
 				ret += r'123579!@#$%^&*()_+-=[]{}"?/,.<>|'[m]
 			return ret
 		ret = []
@@ -36,13 +36,13 @@ def stealth_mnemonic_entry(t,mne,mn,entry_mode,pad_entry=False):
 						w += '\n'
 				else:
 					w = get_pad_chars(1) + w[0] + get_pad_chars(1) + w[1:]
-			elif len(w) > (3,5)[ss_len==12]:
+			elif len(w) > (3, 5)[ss_len==12]:
 				w = w + '\n'
 			else:
 				w = (
 					get_pad_chars(2 if randbool() and entry_mode != 'short' else 0)
 					+ w[0] + get_pad_chars(2) + w[1:]
-					+ get_pad_chars(9) )
+					+ get_pad_chars(9))
 				w = w[:ss_len+1]
 			ret.append(w)
 		return ret
@@ -57,22 +57,22 @@ def stealth_mnemonic_entry(t,mne,mn,entry_mode,pad_entry=False):
 				else:
 					yield w[0] + 'z\b' + '#' * (ssl-len(w)) + w[1:]
 		mn = list(gen_mn())
-	elif entry_mode in ('full','short'):
-		mn = ['fzr'] + mn[:5] + ['grd','grdbxm'] + mn[5:]
-		mn = pad_mnemonic(mn,mne.em.ss_len)
+	elif entry_mode in ('full', 'short'):
+		mn = ['fzr'] + mn[:5] + ['grd', 'grdbxm'] + mn[5:]
+		mn = pad_mnemonic(mn, mne.em.ss_len)
 		mn[10] = '@#$%*##' + mn[10]
 
 	wnum = 1
-	p_ok,p_err = mne.word_prompt
+	p_ok, p_err = mne.word_prompt
 	for w in mn:
-		ret = t.expect((p_ok.format(wnum),p_err.format(wnum-1)))
+		ret = t.expect((p_ok.format(wnum), p_err.format(wnum-1)))
 		if ret == 0:
 			wnum += 1
 		for char in w:
 			t.send(char)
 			time.sleep(0.005)
 
-def user_dieroll_entry(t,data):
+def user_dieroll_entry(t, data):
 	for s in data:
-		t.expect(r'Enter die roll #.+: ',s,regex=True)
+		t.expect(r'Enter die roll #.+: ', s, regex=True)
 		time.sleep(0.005)

Some files were not shown because too many files changed in this diff