From aad252a0774f7bddc526ffd68461e729b386df6b Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sat, 5 Feb 2022 13:32:56 +0000 Subject: [PATCH] handle MMGen exceptions via die() - exception module is imported only after an error occurs --- mmgen/base_proto/bitcoin/tx/base.py | 9 +++-- mmgen/base_proto/bitcoin/tx/new.py | 4 +-- mmgen/base_proto/bitcoin/tx/signed.py | 5 ++- mmgen/base_proto/bitcoin/tx/unsigned.py | 2 +- mmgen/base_proto/ethereum/contract.py | 2 +- mmgen/base_proto/ethereum/twctl.py | 9 +++-- mmgen/base_proto/ethereum/tx/new.py | 4 +-- mmgen/baseconv.py | 15 ++++---- mmgen/bip39.py | 11 +++--- mmgen/cfg.py | 7 ++-- mmgen/daemon.py | 3 +- mmgen/filename.py | 6 ++-- mmgen/fileutil.py | 7 ++-- mmgen/flags.py | 13 ++++--- mmgen/key.py | 6 ++-- mmgen/keygen.py | 5 +-- mmgen/led.py | 5 +-- mmgen/main.py | 1 + mmgen/main_tool.py | 2 +- mmgen/obj.py | 3 +- mmgen/objmethods.py | 9 ++--- mmgen/opts.py | 47 +++++++++++++------------ mmgen/passwdlist.py | 5 ++- mmgen/rpc.py | 13 ++++--- mmgen/seedsplit.py | 9 ++--- mmgen/subseed.py | 5 ++- mmgen/tw.py | 13 ++++--- mmgen/twaddrs.py | 3 +- mmgen/twctl.py | 8 ++--- mmgen/twuo.py | 3 +- mmgen/tx/base.py | 8 ++--- mmgen/txfile.py | 6 ++-- mmgen/util.py | 21 ++++++----- mmgen/wallet.py | 2 +- mmgen/xmrseed.py | 11 +++--- mmgen/xmrwallet.py | 2 +- test/include/common.py | 5 +-- test/objattrtest.py | 2 +- test/test.py | 3 +- test/test_py_d/ts_ethdev.py | 1 - test/test_py_d/ts_main.py | 6 ++-- test/test_py_d/ts_misc.py | 2 +- test/tooltest2.py | 2 +- test/unit_tests_d/ut_baseconv.py | 1 - test/unit_tests_d/ut_bip39.py | 1 - test/unit_tests_d/ut_daemon.py | 1 - test/unit_tests_d/ut_flags.py | 1 - test/unit_tests_d/ut_lockable.py | 1 - test/unit_tests_d/ut_rpc.py | 1 - test/unit_tests_d/ut_xmrseed.py | 1 - 50 files changed, 143 insertions(+), 169 deletions(-) diff --git a/mmgen/base_proto/bitcoin/tx/base.py b/mmgen/base_proto/bitcoin/tx/base.py index 1d1a4089..29c3e47e 100755 --- a/mmgen/base_proto/bitcoin/tx/base.py +++ b/mmgen/base_proto/bitcoin/tx/base.py @@ -17,7 +17,7 @@ from collections import namedtuple import mmgen.tx.base as TxBase from ....opts import opt from ....obj import MMGenObject,MMGenList,HexStr -from ....util import msg,dmsg,make_chksum_6 +from ....util import msg,dmsg,make_chksum_6,die def addr2pubhash(proto,addr): ap = proto.parse_addr(addr) @@ -100,7 +100,7 @@ def DeserializeTX(proto,txhex): if has_witness: u = bshift(2,skip=True).hex() if u != '0001': - raise IllegalWitnessFlagValue(f'{u!r}: Illegal value for flag in transaction!') + die( 'IllegalWitnessFlagValue', f'{u!r}: Illegal value for flag in transaction!' ) d['num_txins'] = readVInt() @@ -140,7 +140,7 @@ def DeserializeTX(proto,txhex): d['witness_size'] = 0 if len(tx) - var.idx != 4: - raise TxHexParseError('TX hex has invalid length: {} extra bytes'.format(len(tx)-var.idx-4)) + die( 'TxHexParseError', 'TX hex has invalid length: {} extra bytes'.format(len(tx)-var.idx-4) ) d['locktime'] = bytes2int(bshift(4)) d['unsigned_hex'] = var.raw_tx.hex() @@ -283,8 +283,7 @@ class Base(TxBase.Base): """ def do_error(errmsg): - from ....exception import TxHexMismatch - raise TxHexMismatch(errmsg+'\n'+hdr) + die( 'TxHexMismatch', errmsg+'\n'+hdr ) def check_equal(desc,hexio,mmio): if mmio != hexio: diff --git a/mmgen/base_proto/bitcoin/tx/new.py b/mmgen/base_proto/bitcoin/tx/new.py index 15dd28a4..225ab595 100755 --- a/mmgen/base_proto/bitcoin/tx/new.py +++ b/mmgen/base_proto/bitcoin/tx/new.py @@ -16,7 +16,7 @@ import mmgen.tx.new as TxBase from .base import Base from ....opts import opt from ....obj import HexStr,MMGenTxID -from ....util import dmsg,vmsg,make_chksum_6 +from ....util import dmsg,vmsg,make_chksum_6,die class New(Base,TxBase.New): usr_fee_prompt = 'Enter transaction fee: ' @@ -98,7 +98,7 @@ class New(Base,TxBase.New): fee = self.sum_inputs() - self.sum_outputs() if fee > self.proto.max_tx_fee: c = self.proto.coin - raise MaxFeeExceeded(f'Transaction fee of {fee} {c} too high! (> {self.proto.max_tx_fee} {c})') + die( 'MaxFeeExceeded', f'Transaction fee of {fee} {c} too high! (> {self.proto.max_tx_fee} {c})' ) def final_inputs_ok_msg(self,funds_left): return 'Transaction produces {} {} in change'.format( diff --git a/mmgen/base_proto/bitcoin/tx/signed.py b/mmgen/base_proto/bitcoin/tx/signed.py index 74958c3e..1b3b6441 100755 --- a/mmgen/base_proto/bitcoin/tx/signed.py +++ b/mmgen/base_proto/bitcoin/tx/signed.py @@ -14,7 +14,7 @@ base_proto.bitcoin.tx.signed: Bitcoin signed transaction class import mmgen.tx.signed as TxBase from .completed import Completed -from ....util import fmt,vmsg +from ....util import fmt,vmsg,die class Signed(Completed,TxBase.Signed): @@ -25,8 +25,7 @@ class Signed(Completed,TxBase.Signed): vmsg(f'\nVsize: {vsize} (true) {est_vsize} (estimated)') ratio = float(est_vsize) / vsize if not (0.95 < ratio < 1.05): # allow for 5% error - from ....exception import BadTxSizeEstimate - raise BadTxSizeEstimate(fmt(f""" + die( 'BadTxSizeEstimate', fmt(f""" Estimated transaction vsize is {ratio:1.2f} times the true vsize Your transaction fee estimates will be inaccurate Please re-create and re-sign the transaction using the option --vsize-adj={1/ratio:1.2f} diff --git a/mmgen/base_proto/bitcoin/tx/unsigned.py b/mmgen/base_proto/bitcoin/tx/unsigned.py index fe2e54c3..f244889d 100755 --- a/mmgen/base_proto/bitcoin/tx/unsigned.py +++ b/mmgen/base_proto/bitcoin/tx/unsigned.py @@ -73,7 +73,7 @@ class Unsigned(Completed,TxBase.Unsigned): new.compare_size_and_estimated_size(tx_decoded) new.coin_txid = CoinTxID(self.deserialized.txid) if not new.coin_txid == tx_decoded['txid']: - raise BadMMGenTxID('txid mismatch (after signing)') + die( 'BadMMGenTxID', 'txid mismatch (after signing)' ) msg('OK') return new except Exception as e: diff --git a/mmgen/base_proto/ethereum/contract.py b/mmgen/base_proto/ethereum/contract.py index 2c36f1e3..d0b37bf2 100755 --- a/mmgen/base_proto/ethereum/contract.py +++ b/mmgen/base_proto/ethereum/contract.py @@ -174,5 +174,5 @@ class TokenResolve(TokenCommon,metaclass=AsyncInit): self.addr = TokenAddr(proto,addr) decimals = await self.get_decimals() # requires self.addr! if not decimals: - raise TokenNotInBlockchain(f'Token {addr!r} not in blockchain') + die( 'TokenNotInBlockchain', f'Token {addr!r} not in blockchain' ) Token.__init__(self,proto,addr,decimals,rpc) diff --git a/mmgen/base_proto/ethereum/twctl.py b/mmgen/base_proto/ethereum/twctl.py index 6214895e..1df5f2f0 100755 --- a/mmgen/base_proto/ethereum/twctl.py +++ b/mmgen/base_proto/ethereum/twctl.py @@ -20,7 +20,7 @@ altcoins.base_proto.ethereum.twctl: Ethereum tracking wallet control class """ -from ...util import msg,ymsg,write_mode +from ...util import msg,ymsg,write_mode,die from ...twctl import TrackingWallet from ...addr import is_coin_addr,is_mmgen_id from ...amt import ETHAmt @@ -160,13 +160,12 @@ class EthereumTokenTrackingWallet(EthereumTrackingWallet): if self.importing and token_addr: if not is_coin_addr(proto,token_addr): - raise InvalidTokenAddress(f'{token_addr!r}: invalid token address') + die( 'InvalidTokenAddress', f'{token_addr!r}: invalid token address' ) else: assert token_addr == None,'EthereumTokenTrackingWallet_chk1' token_addr = await self.sym2addr(proto.tokensym) # returns None on failure if not is_coin_addr(proto,token_addr): - from ...exception import UnrecognizedTokenSymbol - raise UnrecognizedTokenSymbol(f'Specified token {proto.tokensym!r} could not be resolved!') + die( 'UnrecognizedTokenSymbol', f'Specified token {proto.tokensym!r} could not be resolved!' ) from ...addr import TokenAddr self.token = TokenAddr(proto,token_addr) @@ -175,7 +174,7 @@ class EthereumTokenTrackingWallet(EthereumTrackingWallet): if self.importing: await self.import_token(self.token) else: - raise TokenNotInWallet(f'Specified token {self.token!r} not in wallet!') + die( 'TokenNotInWallet', f'Specified token {self.token!r} not in wallet!' ) self.decimals = self.get_param('decimals') self.symbol = self.get_param('symbol') diff --git a/mmgen/base_proto/ethereum/tx/new.py b/mmgen/base_proto/ethereum/tx/new.py index fa73c787..11e10fe3 100755 --- a/mmgen/base_proto/ethereum/tx/new.py +++ b/mmgen/base_proto/ethereum/tx/new.py @@ -139,10 +139,10 @@ class New(Base,TxBase.New): ret.append(waddr) break else: - raise UserAddressNotInWallet(errmsg.format(addr)) + die( 'UserAddressNotInWallet', errmsg.format(addr) ) elif is_coin_addr(self.proto,addr): if not addr in data_root: - raise UserAddressNotInWallet(errmsg.format(addr)) + die( 'UserAddressNotInWallet', errmsg.format(addr) ) ret.append(addr) else: die(1,f'{addr!r}: not an MMGen ID or coin address') diff --git a/mmgen/baseconv.py b/mmgen/baseconv.py index 2681964b..ffdf5d75 100755 --- a/mmgen/baseconv.py +++ b/mmgen/baseconv.py @@ -22,7 +22,6 @@ baseconv.py: base conversion class for the MMGen suite from collections import namedtuple -from .exception import BaseConversionError,BaseConversionPadError,HexadecimalStringError,SeedLengthError from .util import die def is_b58_str(s): @@ -123,7 +122,7 @@ class baseconv(object): elif pad == 'seed': return seed_pad_func() else: - raise BaseConversionPadError(f"{pad!r}: illegal value for 'pad' (must be None,'seed' or int)") + die('BaseConversionPadError',f"{pad!r}: illegal value for 'pad' (must be None,'seed' or int)") def tohex(self,words_arg,pad=None): "convert string or list data of instance base to hex string" @@ -136,13 +135,13 @@ class baseconv(object): desc = self.desc.short if len(words) == 0: - raise BaseConversionError(f'empty {desc} data') + die('BaseConversionError',f'empty {desc} data') def get_seed_pad(): assert hasattr(self,'seedlen_map_rev'), f'seed padding not supported for base {self.wl_id!r}' d = self.seedlen_map_rev if not len(words) in d: - raise BaseConversionError( + die( 'BaseConversionError', f'{len(words)}: invalid length for seed-padded {desc} data in base conversion' ) return d[len(words)] @@ -151,7 +150,7 @@ class baseconv(object): base = len(wl) if not set(words) <= set(wl): - raise BaseConversionError( + die( 'BaseConversionError', ( 'seed data' if pad == 'seed' else f'{words_arg!r}:' ) + f' not in {desc} format' ) @@ -164,7 +163,7 @@ class baseconv(object): from .util import is_hex_str if not is_hex_str(hexstr): - raise HexadecimalStringError( + die( 'HexadecimalStringError', ( 'seed data' if pad == 'seed' else f'{hexstr!r}:' ) + ' not a hexadecimal string' ) @@ -174,13 +173,13 @@ class baseconv(object): "convert byte string to list or string data of instance base" if not bytestr: - raise BaseConversionError('empty data not allowed in base conversion') + die( 'BaseConversionError', 'empty data not allowed in base conversion' ) def get_seed_pad(): assert hasattr(self,'seedlen_map'), f'seed padding not supported for base {self.wl_id!r}' d = self.seedlen_map if not len(bytestr) in d: - raise SeedLengthError( + die( 'SeedLengthError', f'{len(bytestr)}: invalid byte length for seed data in seed-padded base conversion' ) return d[len(bytestr)] diff --git a/mmgen/bip39.py b/mmgen/bip39.py index 301247fd..984ec68b 100755 --- a/mmgen/bip39.py +++ b/mmgen/bip39.py @@ -22,9 +22,8 @@ bip39.py - Data and routines for BIP39 mnemonic seed phrases from hashlib import sha256 -from .exception import MnemonicError from .baseconv import baseconv -from .util import is_hex_str +from .util import is_hex_str,die def is_bip39_str(s): return bool( bip39().tohex(s.split()) ) @@ -59,7 +58,7 @@ class bip39(baseconv): for k,v in cls.constants.items(): if v.mn_len == nwords: return k//8 if in_bytes else k//4 if in_hex else k - raise MnemonicError(f'{nwords!r}: invalid word length for BIP39 mnemonic') + die( 'MnemonicError', f'{nwords!r}: invalid word length for BIP39 mnemonic' ) @classmethod def seedlen2nwords(cls,seed_len,in_bytes=False,in_hex=False): @@ -83,7 +82,7 @@ class bip39(baseconv): for n,w in enumerate(words): if w not in wl: - raise MnemonicError(f'word #{n+1} is not in the BIP39 word list') + die( 'MnemonicError', f'word #{n+1} is not in the BIP39 word list' ) res = ''.join(['{:011b}'.format(wl.index(w)) for w in words]) @@ -92,7 +91,7 @@ class bip39(baseconv): bitlen = k break else: - raise MnemonicError(f'{len(words)}: invalid BIP39 seed phrase length') + die( 'MnemonicError', f'{len(words)}: invalid BIP39 seed phrase length' ) seed_bin = res[:bitlen] chk_bin = res[bitlen:] @@ -105,7 +104,7 @@ class bip39(baseconv): chk_bin_chk = '{:0{w}b}'.format(int(chk_hex_chk,16),w=256)[:chk_len] if chk_bin != chk_bin_chk: - raise MnemonicError('invalid BIP39 seed phrase checksum') + die( 'MnemonicError', 'invalid BIP39 seed phrase checksum' ) return seed_hex diff --git a/mmgen/cfg.py b/mmgen/cfg.py index 80bf82d5..23e8c733 100755 --- a/mmgen/cfg.py +++ b/mmgen/cfg.py @@ -28,7 +28,6 @@ import sys,os,re from collections import namedtuple from .globalvars import * -from .exception import CfgFileParseError from .util import * def cfg_file(id_str): @@ -92,7 +91,7 @@ class CfgFile(object): if m: yield self.line_data(m[1],m[3],lineno,None) else: - raise CfgFileParseError(f'Parse error in file {self.fn!r}, line {lineno}') + die( 'CfgFileParseError', f'Parse error in file {self.fn!r}, line {lineno}' ) return gen_lines() @classmethod @@ -135,7 +134,7 @@ class CfgFileSample(CfgFile): if m: return self.line_data(m[2],m[4],lineno,chunk) else: - raise CfgFileParseError(f'Parse error in file {self.fn!r}, line {lineno}') + die( 'CfgFileParseError', f'Parse error in file {self.fn!r}, line {lineno}' ) def gen_chunks(lines): hdr = True @@ -163,7 +162,7 @@ class CfgFileSample(CfgFile): chunk.append(line) last_nonblank = lineno else: - raise CfgFileParseError(f'Parse error in file {self.fn!r}, line {lineno}') + die( 'CfgFileParseError', f'Parse error in file {self.fn!r}, line {lineno}' ) if chunk: yield process_chunk(chunk,last_nonblank) diff --git a/mmgen/daemon.py b/mmgen/daemon.py index 93afc7ed..4ce63d05 100755 --- a/mmgen/daemon.py +++ b/mmgen/daemon.py @@ -80,8 +80,7 @@ class Daemon(Lockable): try: cp = run(cmd,check=False,stdout=out,stderr=out) except Exception as e: - from .exception import MMGenCalledProcessError - raise MMGenCalledProcessError(f'Error starting executable: {type(e).__name__} [Errno {e.errno}]') + die( 'MMGenCalledProcessError', f'Error starting executable: {type(e).__name__} [Errno {e.errno}]' ) if self.debug: print(cp) return cp diff --git a/mmgen/filename.py b/mmgen/filename.py index d760b22a..3fcb3912 100755 --- a/mmgen/filename.py +++ b/mmgen/filename.py @@ -54,16 +54,14 @@ class Filename(MMGenObject): if base_class: subclass = base_class.ext_to_type(self.ext,proto) if not subclass: - from .exception import BadFileExtension - raise BadFileExtension(f'{self.ext!r}: not a recognized file extension for {base_class}') + die( 'BadFileExtension', f'{self.ext!r}: not a recognized file extension for {base_class}' ) self.subclass = subclass try: st = os.stat(fn) except: - from .exception import FileNotFound - raise FileNotFound(f'{fn!r}: file not found') + die( 'FileNotFound', f'{fn!r}: file not found' ) import stat if stat.S_ISBLK(st.st_mode): diff --git a/mmgen/fileutil.py b/mmgen/fileutil.py index 1bbde693..898f8d69 100755 --- a/mmgen/fileutil.py +++ b/mmgen/fileutil.py @@ -89,8 +89,7 @@ def _check_file_type_and_access(fname,ftype,blkdev_ok=False): try: mode = os.stat(fname).st_mode except: - from .exception import FileNotFound - raise FileNotFound(f'Requested {ftype} {fname!r} not found') + die( 'FileNotFound', f'Requested {ftype} {fname!r} not found' ) for t in ok_types: if t[0](mode): @@ -289,8 +288,8 @@ def get_data_from_file(infile,desc='data',dash=False,silent=False,binary=False,q data = data.decode() if len(data) == g.max_input_size + 1: - from .exception import MaxInputSizeExceeded - raise MaxInputSizeExceeded(f'Too much input data! Max input data size: {f.max_input_size} bytes') + die( 'MaxInputSizeExceeded', + f'Too much input data! Max input data size: {f.max_input_size} bytes' ) return data diff --git a/mmgen/flags.py b/mmgen/flags.py index b69f7f4d..a6f3c190 100755 --- a/mmgen/flags.py +++ b/mmgen/flags.py @@ -20,9 +20,8 @@ flags.py: Class flags and opts for the MMGen suite """ -from .exception import ClassFlagsError from .base_obj import AttrCtrl,Lockable -from .util import fmt_list +from .util import fmt_list,die class ClassFlags(AttrCtrl): _name = 'flags' @@ -35,10 +34,10 @@ class ClassFlags(AttrCtrl): for a in self._available: if a.startswith('_'): - raise ClassFlagsError(f'{a!r}: {self._desc} cannot begin with an underscore') + die( 'ClassFlagsError', f'{a!r}: {self._desc} cannot begin with an underscore' ) for b in self.reserved_attrs: if a == b: - raise ClassFlagsError(f'{a!r}: {b} is a reserved name for {self._desc}') + die( 'ClassFlagsError', f'{a!r}: {b} is a reserved name for {self._desc}' ) if arg: assert type(arg) in (list,tuple), f"{arg!r}: {self._name!r} must be list or tuple" @@ -69,14 +68,14 @@ class ClassFlags(AttrCtrl): assert type(val) is bool, f'{val!r} not boolean' old_val = getattr(self,name) if val and old_val: - raise ClassFlagsError(f'{self._desc} {name!r} already set') + die( 'ClassFlagsError', f'{self._desc} {name!r} already set' ) if not val and not old_val: - raise ClassFlagsError(f'{self._desc} {name!r} not set, so cannot be unset') + die( 'ClassFlagsError', f'{self._desc} {name!r} not set, so cannot be unset' ) super().__setattr__(name,val) def not_available_error(self,name): - raise ClassFlagsError('{!r}: unrecognized {} for {}: (available {}: {})'.format( + die( 'ClassFlagsError', '{!r}: unrecognized {} for {}: (available {}: {})'.format( name, self._desc, type(self._parent).__name__, diff --git a/mmgen/key.py b/mmgen/key.py index 68d02336..e5233570 100755 --- a/mmgen/key.py +++ b/mmgen/key.py @@ -83,9 +83,9 @@ class PrivKey(bytes,Hilite,InitErrors,MMGenObject): me.wif = str.__new__(WifKey,wif) # check has been done me.orig_bytes = None if k.sec != proto.preprocess_key(k.sec,k.pubkey_type): - from .exception import PrivateKeyError - raise PrivateKeyError( - f'{proto.cls_name} WIF key {me.wif!r} encodes private key with invalid value {me}') + from .util import die + die( 'PrivateKeyError', + f'{proto.cls_name} WIF key {me.wif!r} encodes private key with invalid value {me}' ) me.proto = proto return me except Exception as e: diff --git a/mmgen/keygen.py b/mmgen/keygen.py index f272995c..0796acca 100755 --- a/mmgen/keygen.py +++ b/mmgen/keygen.py @@ -64,8 +64,9 @@ class keygen_backend: try: from .secp256k1 import priv2pub if not priv2pub(bytes.fromhex('deadbeef'*8),1): - from .exception import ExtensionModuleError - raise ExtensionModuleError('Unable to execute priv2pub() from secp256k1 extension module') + from .util import die + die( 'ExtensionModuleError', + 'Unable to execute priv2pub() from secp256k1 extension module' ) return True except Exception as e: if not silent: diff --git a/mmgen/led.py b/mmgen/led.py index 94ee9dfa..c0a24bb1 100755 --- a/mmgen/led.py +++ b/mmgen/led.py @@ -69,8 +69,8 @@ class LEDControl: except: pass else: break else: - from mmgen.exception import NoLEDSupport - raise NoLEDSupport('Control files not found! LED control not supported on this system') + from .util import die + die( 'NoLEDSupport', 'Control files not found! LED control not supported on this system' ) msg(f'{board.name} board detected') @@ -89,6 +89,7 @@ class LEDControl: fp.write(f'{init_val}\n') return True except PermissionError: + from .util import die die(2,'\n'+fmt(f""" You do not have access to the {desc} file To allow access, run the following command: diff --git a/mmgen/main.py b/mmgen/main.py index a9addc9e..331cf787 100755 --- a/mmgen/main.py +++ b/mmgen/main.py @@ -57,6 +57,7 @@ def launch(mod): _o = namedtuple('exit_data',['color','exit_val','fs']) d = { + 0: _o(nocolor, 1, '{message}'), 1: _o(nocolor, 1, '{message}'), 2: _o(yellow, 2, '{message}'), 3: _o(yellow, 3, '\nMMGen Error ({name}): {message}'), diff --git a/mmgen/main_tool.py b/mmgen/main_tool.py index 44cb0b16..92fba360 100755 --- a/mmgen/main_tool.py +++ b/mmgen/main_tool.py @@ -215,7 +215,7 @@ def process_args(cmd,cmd_args,cls): # If we're reading from a pipe, replace '-' with output of previous command if flag == 'STDIN_OK' and u_args and u_args[0] == '-': if sys.stdin.isatty(): - raise BadFilename("Standard input is a TTY. Can't use '-' as a filename") + die( 'BadFilename', "Standard input is a TTY. Can't use '-' as a filename" ) else: max_dlen_spec = '10kB' # limit input to 10KB for now max_dlen = parse_bytespec(max_dlen_spec) diff --git a/mmgen/obj.py b/mmgen/obj.py index a7a5723b..37f03c79 100755 --- a/mmgen/obj.py +++ b/mmgen/obj.py @@ -23,7 +23,6 @@ obj.py: MMGen native classes import sys,os,re,unicodedata from .objmethods import * -from .exception import BadTwComment def get_obj(objname,*args,**kwargs): """ @@ -378,7 +377,7 @@ class MMGenWalletLabel(MMGenLabel): class TwComment(MMGenLabel): max_screen_width = 80 desc = 'tracking wallet comment' - exc = BadTwComment + exc = 'BadTwComment' class MMGenTxLabel(MMGenLabel): max_len = 72 diff --git a/mmgen/objmethods.py b/mmgen/objmethods.py index d1d27bcb..e028ac2c 100755 --- a/mmgen/objmethods.py +++ b/mmgen/objmethods.py @@ -115,13 +115,14 @@ class InitErrors: if m2: errmsg = repr(m2) + '\n' + errmsg - if hasattr(cls,'passthru_excs') and type(e) in cls.passthru_excs: + from .util import die + + if hasattr(cls,'passthru_excs') and type(e).__name__ in cls.passthru_excs: raise elif hasattr(cls,'exc'): - raise cls.exc(errmsg) + die( cls.exc, errmsg ) else: - from .exception import ObjectInitError - raise ObjectInitError(errmsg) + die( 'ObjectInitError', errmsg ) @classmethod def method_not_implemented(cls): diff --git a/mmgen/opts.py b/mmgen/opts.py index a17e667b..495b835d 100755 --- a/mmgen/opts.py +++ b/mmgen/opts.py @@ -21,7 +21,6 @@ opts.py: MMGen-specific options processing after generic processing by share.Op """ import sys,os,stat -from .exception import UserOptError,CfgFileParseError from .globalvars import g from .base_obj import Lockable @@ -163,11 +162,13 @@ def override_globals_from_cfg_file(ucfg,need_proto): refval = getattr(cls,attr) val = ucfg.parse_value(d.value,refval) if not val: - raise CfgFileParseError(f'Parse error in file {ucfg.fn!r}, line {d.lineno}') + from .util import die + die( 'CfgFileParseError', f'Parse error in file {ucfg.fn!r}, line {d.lineno}' ) val_conv = set_for_type(val,refval,attr,src=ucfg.fn) setattr(cls,attr,val_conv) else: - raise CfgFileParseError(f'{d.name!r}: unrecognized option in {ucfg.fn!r}, line {d.lineno}') + from .util import die + die( 'CfgFileParseError', f'{d.name!r}: unrecognized option in {ucfg.fn!r}, line {d.lineno}' ) def override_globals_and_set_opts_from_env(opt): for name in g.env_opts: @@ -426,39 +427,39 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails try: l = val.split(sep) except: - raise UserOptError(f'{val!r}: invalid {desc} (not {sepword}-separated list)') + die( 'UserOptError', f'{val!r}: invalid {desc} (not {sepword}-separated list)' ) if len(l) != n: - raise UserOptError(f'{val!r}: invalid {desc} ({n} {sepword}-separated items required)') + die( 'UserOptError', f'{val!r}: invalid {desc} ({n} {sepword}-separated items required)' ) def opt_compares(val,op_str,target,desc,desc2=''): import operator as o op_f = { '<':o.lt, '<=':o.le, '>':o.gt, '>=':o.ge, '=':o.eq }[op_str] if not op_f(val,target): d2 = desc2 + ' ' if desc2 else '' - raise UserOptError(f'{val}: invalid {desc} ({d2}not {op_str} {target})') + die( 'UserOptError', f'{val}: invalid {desc} ({d2}not {op_str} {target})' ) def opt_is_int(val,desc): if not is_int(val): - raise UserOptError(f'{val!r}: invalid {desc} (not an integer)') + die( 'UserOptError', f'{val!r}: invalid {desc} (not an integer)' ) def opt_is_float(val,desc): try: float(val) except: - raise UserOptError(f'{val!r}: invalid {desc} (not a floating-point number)') + die( 'UserOptError', f'{val!r}: invalid {desc} (not a floating-point number)' ) def opt_is_in_list(val,tlist,desc): if val not in tlist: q,sep = (('',','),("'","','"))[type(tlist[0]) == str] - raise UserOptError('{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}'.format( + die( 'UserOptError', '{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}'.format( v = val, w = desc, q = q, o = sep.join(map(str,sorted(tlist))) )) def opt_unrecognized(key,val,desc='value'): - raise UserOptError(f'{val!r}: unrecognized {desc} for option {fmt_opt(key)!r}') + die( 'UserOptError', f'{val!r}: unrecognized {desc} for option {fmt_opt(key)!r}' ) def opt_display(key,val='',beg='For selected',end=':\n'): from .util import msg_r @@ -475,15 +476,15 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails if key == 'out_fmt': p = 'hidden_incog_output_params' if sstype == IncogWalletHidden and not getattr(opt,p): - raise UserOptError( + die( 'UserOptError', 'Hidden incog format output requested. ' + f'You must supply a file and offset with the {fmt_opt(p)!r} option' ) if issubclass(sstype,IncogWallet) and opt.old_incog_fmt: opt_display(key,val,beg='Selected',end=' ') opt_display('old_incog_fmt',beg='conflicts with',end=':\n') - raise UserOptError('Export to old incog wallet format unsupported') + die( 'UserOptError', 'Export to old incog wallet format unsupported' ) elif issubclass(sstype,Brainwallet): - raise UserOptError('Output to brainwallet format unsupported') + die( 'UserOptError', 'Output to brainwallet format unsupported' ) chk_out_fmt = chk_in_fmt @@ -491,7 +492,7 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails a = val.rsplit(',',1) # permit comma in filename if len(a) != 2: opt_display(key,val) - raise UserOptError('Option requires two comma-separated arguments') + die( 'UserOptError', 'Option requires two comma-separated arguments' ) fn,offset = a opt_is_int(offset,desc) @@ -514,7 +515,7 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails val2 = getattr(opt,key2) from .wallet import IncogWalletHidden if val2 and val2 not in IncogWalletHidden.fmt_codes: - raise UserOptError(f'Option conflict:\n {fmt_opt(key)}, with\n {fmt_opt(key2)}={val2}') + die( 'UserOptError', f'Option conflict:\n {fmt_opt(key)}, with\n {fmt_opt(key2)}={val2}' ) chk_hidden_incog_output_params = chk_hidden_incog_input_params @@ -539,7 +540,7 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails a = val.split(',') if len(a) != 2: opt_display(key,val) - raise UserOptError('Option requires two comma-separated arguments') + die( 'UserOptError', 'Option requires two comma-separated arguments' ) opt_is_int(a[0],'seed length '+desc) opt_is_in_list(int(a[0]),Seed.lens,'seed length '+desc) opt_is_in_list(a[1],list(hash_presets.keys()),'hash preset '+desc) @@ -567,14 +568,14 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails # TODO: move this check elsewhere # def chk_rbf(key,val,desc): # if not proto.cap('rbf'): -# raise UserOptError(f'--rbf requested, but {proto.coin} does not support replace-by-fee transactions') +# die( 'UserOptError', f'--rbf requested, but {proto.coin} does not support replace-by-fee transactions' ) # def chk_bob(key,val,desc): # from .regtest import MMGenRegtest # try: # os.stat(os.path.join(MMGenRegtest(g.coin).d.datadir,'regtest','debug.log')) # except: -# raise UserOptError( +# die( 'UserOptError', # 'Regtest (Bob and Alice) mode not set up yet. ' + # f"Run '{g.proj_name.lower()}-regtest setup' to initialize." ) # @@ -587,13 +588,13 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails # TODO: move this check elsewhere # def chk_token(key,val,desc): # if not 'token' in proto.caps: -# raise UserOptError(f'Coin {tx.coin!r} does not support the --token option') +# die( 'UserOptError', f'Coin {tx.coin!r} does not support the --token option' ) # if len(val) == 40 and is_hex_str(val): # return # if len(val) > 20 or not all(s.isalnum() for s in val): -# raise UserOptError(f'{val!r}: invalid parameter for --token option') +# die( 'UserOptError', f'{val!r}: invalid parameter for --token option' ) - from .util import is_int + from .util import is_int,die cfuncs = { k:v for k,v in locals().items() if k.startswith('chk_') } @@ -642,8 +643,8 @@ def check_and_set_autoset_opts(): # Raises exception if any check fails else: ret = locals()[asd.type](key,val,asd) if type(ret) is str: - from .util import fmt_list - raise UserOptError( + from .util import fmt_list,die + die( 'UserOptError', '{!r}: invalid parameter for option --{} (not {}: {})'.format( val, key.replace('_','-'), diff --git a/mmgen/passwdlist.py b/mmgen/passwdlist.py index 669dd947..0aba2211 100755 --- a/mmgen/passwdlist.py +++ b/mmgen/passwdlist.py @@ -22,7 +22,7 @@ passwdlist.py: Password list class for the MMGen suite from collections import namedtuple -from .util import ymsg,is_int,keypress_confirm +from .util import ymsg,is_int,keypress_confirm,die from .obj import ImmutableAttr,ListItemAttr,MMGenPWIDString,TwComment from .key import PrivKey from .addr import MMGenPasswordType,AddrIdx,AddrListID @@ -112,8 +112,7 @@ class PasswordList(AddrList): self.pw_fmt = pw_fmt self.pw_fmt_disp = pw_fmt if self.pw_fmt not in self.pw_info: - from .exception import InvalidPasswdFormat - raise InvalidPasswdFormat( + die( 'InvalidPasswdFormat', '{!r}: invalid password format. Valid formats: {}'.format( self.pw_fmt, ', '.join(self.pw_info) )) diff --git a/mmgen/rpc.py b/mmgen/rpc.py index 6514930d..c2457aa8 100755 --- a/mmgen/rpc.py +++ b/mmgen/rpc.py @@ -190,7 +190,7 @@ class RPCBackends: headers = self.http_hdrs ) r = s.getresponse() # => http.client.HTTPResponse instance except Exception as e: - raise RPCFailure(str(e)) + die( 'RPCFailure', str(e) ) if timeout: ret = ( r.read(), r.status ) @@ -303,8 +303,7 @@ class RPCClient(MMGenObject): try: socket.create_connection((host,port),timeout=1).close() except: - from .exception import SocketError - raise SocketError(f'Unable to connect to {host}:{port}') + die( 'SocketError', f'Unable to connect to {host}:{port}' ) self.http_hdrs = { 'Content-Type': 'application/json' } self.url = f'{self.network_proto}://{host}:{port}{self.host_path}' @@ -435,7 +434,7 @@ class RPCClient(MMGenObject): except: try: m = t['error'] except: m = t - raise RPCFailure(m) + die( 'RPCFailure', m ) else: import http m,s = ( '', http.HTTPStatus(status) ) @@ -445,7 +444,7 @@ class RPCClient(MMGenObject): except: try: m = text.decode() except: m = text - raise RPCFailure(f'{s.value} {s.name}: {m}') + die( 'RPCFailure', f'{s.value} {s.name}: {m}' ) async def stop_daemon(self,quiet=False,silent=False): if self.daemon.state == 'ready': @@ -852,10 +851,10 @@ async def rpc_init(proto,backend=None,daemon=None,ignore_daemon_version=False): ignore_daemon_version or proto.ignore_daemon_version or g.ignore_daemon_version ) if rpc.chain not in proto.chain_names: - raise RPCChainMismatch('\n'+fmt(f""" + die( 'RPCChainMismatch', '\n' + fmt(f""" Protocol: {proto.cls_name} Valid chain names: {fmt_list(proto.chain_names,fmt='bare')} RPC client chain: {rpc.chain} - """,indent=' ').rstrip()) + """,indent=' ').rstrip() ) return rpc diff --git a/mmgen/seedsplit.py b/mmgen/seedsplit.py index bf64318b..f7061c17 100755 --- a/mmgen/seedsplit.py +++ b/mmgen/seedsplit.py @@ -80,8 +80,7 @@ class SeedShareList(SubSeedList): msg(f'master_share seed ID collision with parent seed, incrementing nonce to {nonce+1}') else: return ms - from .exception import SubSeedNonceRangeExceeded - raise SubSeedNonceRangeExceeded('nonce range exceeded') + die( 'SubSeedNonceRangeExceeded', 'nonce range exceeded' ) def last_share_debug(last_share): if not debug_last_share: @@ -109,8 +108,7 @@ class SeedShareList(SubSeedList): self.data['long'][ls.sid] = (count,nonce) break else: - from .exception import SubSeedNonceRangeExceeded - raise SubSeedNonceRangeExceeded('nonce range exceeded') + die( 'SubSeedNonceRangeExceeded', 'nonce range exceeded' ) if g.debug_subseed: A = parent_seed.data @@ -119,8 +117,7 @@ class SeedShareList(SubSeedList): def get_share_by_idx(self,idx,base_seed=False): if idx < 1 or idx > self.count: - from .exception import RangeError - raise RangeError(f'{idx}: share index out of range') + die( 'RangeError', f'{idx}: share index out of range' ) elif idx == self.count: return self.last_share elif self.master_share and idx == 1: diff --git a/mmgen/subseed.py b/mmgen/subseed.py index a04c24ed..24c1f410 100755 --- a/mmgen/subseed.py +++ b/mmgen/subseed.py @@ -21,7 +21,7 @@ subseed.py: Subseed classes and methods for the MMGen suite """ from .color import green -from .util import msg_r,msg,qmsg +from .util import msg_r,msg,qmsg,die from .obj import MMGenRange,IndexedDict from .seed import * from .crypto import scramble_seed @@ -191,8 +191,7 @@ class SubSeedList(MMGenObject): self.data[length][sid] = (idx,nonce) return last_sid == sid else: # must exit here, as this could leave self.data in inconsistent state - from .exception import SubSeedNonceRangeExceeded - raise SubSeedNonceRangeExceeded('add_subseed(): nonce range exceeded') + die( 'SubSeedNonceRangeExceeded', 'add_subseed(): nonce range exceeded' ) for idx in SubSeedIdxRange(first_idx,last_idx).iterate(): match1 = add_subseed(idx,'long') diff --git a/mmgen/tw.py b/mmgen/tw.py index 99eed047..ca5113f9 100755 --- a/mmgen/tw.py +++ b/mmgen/tw.py @@ -22,7 +22,6 @@ tw: Tracking wallet dependency classes for the MMGen suite import time -from .exception import BadTwLabel,BadTwComment from .objmethods import Hilite,InitErrors,MMGenObject from .obj import TwComment from .addr import MMGenID @@ -86,8 +85,8 @@ class TwMMGenID(str,Hilite,InitErrors,MMGenObject): # non-displaying container for TwMMGenID,TwComment class TwLabel(str,InitErrors,MMGenObject): - exc = BadTwLabel - passthru_excs = (BadTwComment,) + exc = 'BadTwLabel' + passthru_excs = ('BadTwComment',) def __new__(cls,proto,text): if type(text) == cls: return text @@ -109,8 +108,8 @@ def get_tw_label(proto,s): """ try: return TwLabel(proto,s) - except BadTwComment: - raise except Exception as e: -# print(e) - return None + if type(e).__name__ == 'BadTwComment': # do it this way to avoid importing .exception + raise + else: + return None diff --git a/mmgen/twaddrs.py b/mmgen/twaddrs.py index 7c3311af..37a59ea2 100755 --- a/mmgen/twaddrs.py +++ b/mmgen/twaddrs.py @@ -126,8 +126,7 @@ class TwAddrList(MMGenDict,TwCommon,metaclass=AsyncInit): if not self.has_age: show_age = False if age_fmt not in self.age_fmts: - from .exception import BadAgeFormat - raise BadAgeFormat(f'{age_fmt!r}: invalid age format (must be one of {self.age_fmts!r})') + die( 'BadAgeFormat', f'{age_fmt!r}: invalid age format (must be one of {self.age_fmts!r})' ) fs = '{mid}' + ('',' {addr}')[showbtcaddrs] + ' {cmt} {amt}' + ('',' {age}')[show_age] mmaddrs = [k for k in self.keys() if k.type == 'mmgen'] max_mmid_len = max(len(k) for k in mmaddrs) + 2 if mmaddrs else 10 diff --git a/mmgen/twctl.py b/mmgen/twctl.py index 9cf663a7..e111ca1b 100755 --- a/mmgen/twctl.py +++ b/mmgen/twctl.py @@ -21,7 +21,7 @@ twctl: Tracking wallet control class for the MMGen suite """ from .globalvars import g -from .util import msg,dmsg,write_mode,base_proto_subclass +from .util import msg,dmsg,write_mode,base_proto_subclass,die from .base_obj import AsyncInit from .objmethods import MMGenObject from .obj import TwComment,get_obj @@ -61,8 +61,7 @@ class TrackingWallet(MMGenObject,metaclass=AsyncInit): self.init_empty() if self.data['coin'] != self.proto.coin: # TODO remove? - from .exception import WalletFileError - raise WalletFileError( + die( 'WalletFileError', 'Tracking wallet coin ({}) does not match current coin ({})!'.format( self.data['coin'], self.proto.coin )) @@ -98,8 +97,7 @@ class TrackingWallet(MMGenObject,metaclass=AsyncInit): self.init_empty() self.force_write() else: - from .exception import WalletFileError - raise WalletFileError(f'File {self.tw_fn!r} exists but does not contain valid json data') + die( 'WalletFileError', f'File {self.tw_fn!r} exists but does not contain valid json data' ) else: self.upgrade_wallet_maybe() diff --git a/mmgen/twuo.py b/mmgen/twuo.py index e09bc55c..e40660c2 100755 --- a/mmgen/twuo.py +++ b/mmgen/twuo.py @@ -128,8 +128,7 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, add [l]abel: @age_fmt.setter def age_fmt(self,val): if val not in self.age_fmts: - from .exception import BadAgeFormat - raise BadAgeFormat(f'{val!r}: invalid age format (must be one of {self.age_fmts!r})') + die( 'BadAgeFormat', f'{val!r}: invalid age format (must be one of {self.age_fmts!r})' ) self._age_fmt = val def get_display_precision(self): diff --git a/mmgen/tx/base.py b/mmgen/tx/base.py index 6d308415..73efef73 100755 --- a/mmgen/tx/base.py +++ b/mmgen/tx/base.py @@ -16,7 +16,7 @@ from ..globalvars import * from ..objmethods import MMGenObject from ..obj import ImmutableAttr,ListItemAttr,MMGenListItem,MMGenTxLabel,TwComment,CoinTxID,HexStr from ..addr import MMGenID,CoinAddr -from ..util import msg,ymsg,fmt,remove_dups,keypress_confirm,make_timestamp,line_input +from ..util import msg,ymsg,fmt,remove_dups,keypress_confirm,make_timestamp,line_input,die from ..opts import opt class MMGenTxIO(MMGenListItem): @@ -118,8 +118,8 @@ class Base(MMGenObject): def check_correct_chain(self): if hasattr(self,'rpc'): if self.chain != self.rpc.chain: - raise TransactionChainMismatch( - f'Transaction is for {self.chain}, but coin daemon chain is {self.rpc.chain}!') + die( 'TransactionChainMismatch', + f'Transaction is for {self.chain}, but coin daemon chain is {self.rpc.chain}!' ) def sum_inputs(self): return sum(e.amt for e in self.inputs) @@ -177,7 +177,7 @@ class Base(MMGenObject): m = fs.format('\n '.join(non_mmaddrs)) if caller in ('txdo','txsign'): if not opt.keys_from_file: - raise UserOptError(f'\n{indent}ERROR: {m}\n') + die( 'UserOptError', f'\n{indent}ERROR: {m}\n' ) else: msg(f'\n{indent}WARNING: {m}\n') if not (opt.yes or keypress_confirm('Continue?',default_yes=True)): diff --git a/mmgen/txfile.py b/mmgen/txfile.py index 0d113bfc..0527bc78 100755 --- a/mmgen/txfile.py +++ b/mmgen/txfile.py @@ -60,8 +60,7 @@ class MMGenTxFile(MMGenObject): try: desc = 'data' if len(tx_data) > g.max_tx_file_size: - from .exception import MaxFileSizeExceeded - raise MaxFileSizeExceeded(f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)') + die( 'MaxFileSizeExceeded', f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)' ) tx_data = tx_data.splitlines() assert len(tx_data) >= 5,'number of lines less than 5' assert len(tx_data[0]) == 6,'invalid length of first line' @@ -187,8 +186,7 @@ class MMGenTxFile(MMGenObject): self.chksum = make_chksum_6(' '.join(lines)) fmt_data = '\n'.join([self.chksum] + lines) + '\n' if len(fmt_data) > g.max_tx_file_size: - from .exception import MaxFileSizeExceeded - raise MaxFileSizeExceeded(f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)') + die( 'MaxFileSizeExceeded', f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)' ) return fmt_data def write(self, diff --git a/mmgen/util.py b/mmgen/util.py index 9af2a404..54128215 100755 --- a/mmgen/util.py +++ b/mmgen/util.py @@ -121,12 +121,17 @@ def mdie(*args): sys.exit(0) def die(ev,s='',stdout=False): - assert isinstance(ev,int) - from .exception import MMGenSystemExit,MMGenError - if ev <= 2: - raise MMGenSystemExit(ev,s,stdout) + if isinstance(ev,int): + from .exception import MMGenSystemExit,MMGenError + if ev <= 2: + raise MMGenSystemExit(ev,s,stdout) + else: + raise MMGenError(ev,s,stdout) + elif isinstance(ev,str): + import mmgen.exception + raise getattr(mmgen.exception,ev)(s) else: - raise MMGenError(ev,s,stdout) + raise ValueError(f'{ev}: exit value must be string or int instance') def die_wait(delay,ev=0,s=''): assert isinstance(delay,int) @@ -460,8 +465,7 @@ def compare_or_die(val1, desc1, val2, desc2, e='Error'): def check_wallet_extension(fn): from .wallet import Wallet if not Wallet.ext_to_type(get_extension(fn)): - from .exception import BadFileExtension - raise BadFileExtension(f'{fn!r}: unrecognized seed source file extension') + die( 'BadFileExtension', f'{fn!r}: unrecognized seed source file extension' ) def make_full_path(outdir,outfile): return os.path.normpath(os.path.join(outdir, os.path.basename(outfile))) @@ -472,8 +476,7 @@ def confirm_or_raise(message,q,expect='YES',exit_msg='Exiting at user request'): a = f'{q} ' if q[0].isupper() else f'Are you sure you want to {q}?\n' b = f'Type uppercase {expect!r} to confirm: ' if line_input(a+b).strip() != expect: - from .exception import UserNonConfirmation - raise UserNonConfirmation(exit_msg) + die( 'UserNonConfirmation', exit_msg ) def get_words_from_user(prompt): words = line_input(prompt, echo=opt.echo_passphrase).split() diff --git a/mmgen/wallet.py b/mmgen/wallet.py index c254818e..a795fd29 100755 --- a/mmgen/wallet.py +++ b/mmgen/wallet.py @@ -521,7 +521,7 @@ class DieRollSeedFile(WalletUnenc): rmap = bc.seedlen_map_rev if not len(d) in rmap: - raise SeedLengthError('{!r}: invalid length for {} (must be one of {})'.format( + die( 'SeedLengthError', '{!r}: invalid length for {} (must be one of {})'.format( len(d), self.desc, list(rmap) )) diff --git a/mmgen/xmrseed.py b/mmgen/xmrseed.py index fe070c33..8e799663 100755 --- a/mmgen/xmrseed.py +++ b/mmgen/xmrseed.py @@ -54,17 +54,15 @@ class xmrseed(baseconv): wl = self.digits base = len(wl) - from .exception import MnemonicError - if not set(words) <= set(wl): - raise MnemonicError( f'{words!r}: not in {desc} format' ) + die( 'MnemonicError', f'{words!r}: not in {desc} format' ) if len(words) not in self.seedlen_map_rev: - raise MnemonicError( f'{len(words)}: invalid seed phrase length for {desc}' ) + die( 'MnemonicError', f'{len(words)}: invalid seed phrase length for {desc}' ) z = self.monero_mn_checksum(words[:-1]) if z != words[-1]: - raise MnemonicError(f'invalid {desc} checksum') + die( 'MnemonicError', f'invalid {desc} checksum' ) words = tuple(words[:-1]) @@ -84,8 +82,7 @@ class xmrseed(baseconv): base = len(wl) if len(bytestr) not in self.seedlen_map: - from .exception import SeedLengthError - raise SeedLengthError(f'{len(bytestr)}: invalid seed byte length for {desc}') + die( 'SeedLengthError', f'{len(bytestr)}: invalid seed byte length for {desc}' ) def num2base_monero(num): w1 = num % base diff --git a/mmgen/xmrwallet.py b/mmgen/xmrwallet.py index 5ab52700..cc066eb7 100755 --- a/mmgen/xmrwallet.py +++ b/mmgen/xmrwallet.py @@ -888,6 +888,6 @@ class MoneroWalletOps: ymsg('Transaction not relayed') return True else: - raise RPCFailure(repr(res)) + die( 'RPCFailure', repr(res) ) else: die(1,'Exiting at user request') diff --git a/test/include/common.py b/test/include/common.py index e3ece6cc..7416c4b7 100755 --- a/test/include/common.py +++ b/test/include/common.py @@ -112,7 +112,8 @@ def cleandir(d,do_msg=False): def mk_tmpdir(d): try: os.mkdir(d,0o755) except OSError as e: - if e.errno != 17: raise + if e.errno != 17: + raise else: vmsg(f'Created directory {d!r}') @@ -149,7 +150,7 @@ def ok(): def cmp_or_die(s,t,desc=None): if s != t: - raise TestSuiteFatalException( + die( 'TestSuiteFatalException', (f'For {desc}:\n' if desc else '') + f'ERROR: recoded data:\n{t!r}\ndiffers from original data:\n{s!r}' ) diff --git a/test/objattrtest.py b/test/objattrtest.py index 873193a1..12aa1e15 100755 --- a/test/objattrtest.py +++ b/test/objattrtest.py @@ -85,7 +85,7 @@ def test_attr_perm(obj,attrname,perm_name,perm_value,dobj,attrval_type): try: so = sample_objs[attrval_type.__name__] except: - raise SampleObjError(f'unable to find sample object of type {attrval_type.__name__!r}') + die( 'SampleObjError', f'unable to find sample object of type {attrval_type.__name__!r}' ) # ListItemAttr allows setting an attribute if its value is None if type(dobj) == ListItemAttr and getattr(obj,attrname) == None: setattr(obj,attrname,so) diff --git a/test/test.py b/test/test.py index 099c28c4..d45e50eb 100755 --- a/test/test.py +++ b/test/test.py @@ -460,7 +460,8 @@ def create_tmp_dirs(shm_dir): try: os.unlink(cfgs[cfg]['tmpdir']) except OSError as e: - if e.errno != 2: raise + if e.errno != 2: + raise finally: os.symlink(src,cfgs[cfg]['tmpdir']) diff --git a/test/test_py_d/ts_ethdev.py b/test/test_py_d/ts_ethdev.py index 678617ef..9fd970be 100755 --- a/test/test_py_d/ts_ethdev.py +++ b/test/test_py_d/ts_ethdev.py @@ -28,7 +28,6 @@ from subprocess import run,PIPE,DEVNULL from mmgen.globalvars import g from mmgen.opts import opt from mmgen.util import die -from mmgen.exception import * from mmgen.amt import ETHAmt from mmgen.protocol import CoinProtocol from ..include.common import * diff --git a/test/test_py_d/ts_main.py b/test/test_py_d/ts_main.py index a30bcb13..0a070148 100755 --- a/test/test_py_d/ts_main.py +++ b/test/test_py_d/ts_main.py @@ -46,7 +46,7 @@ def make_brainwallet_file(fn): def verify_checksum_or_exit(checksum,chk): chk = strip_ansi_escapes(chk) if checksum != chk: - raise TestSuiteFatalException(f'Checksum error: {chk}') + die( 'TestSuiteFatalException', f'Checksum error: {chk}' ) vmsg(green('Checksums match: ') + cyan(chk)) addrs_per_wallet = 8 @@ -403,7 +403,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared): ad.add(al) aix = AddrIdxList(fmt_str=self.cfgs[s]['addr_idx_list']) if len(aix) != addrs_per_wallet: - raise TestSuiteFatalException(f'Address index list length != {addrs_per_wallet}: {repr(aix)}') + die( 'TestSuiteFatalException', f'Address index list length != {addrs_per_wallet}: {repr(aix)}' ) tx_data[s] = { 'addrfile': afile, 'chk': al.chksum, @@ -497,7 +497,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared): ['-f',self.tx_fee,'-B'] + add_args + cmd_args + txdo_args) if t.expect([('Get','Unsigned transac')[cmdline_inputs],r'Unable to connect to \S+'],regex=True) == 1: - raise TestSuiteException('\n'+t.p.after) + die( 'TestSuiteException', '\n'+t.p.after ) if cmdline_inputs: t.written_to_file('tion') diff --git a/test/test_py_d/ts_misc.py b/test/test_py_d/ts_misc.py index 7219bfd9..94b3c5b4 100755 --- a/test/test_py_d/ts_misc.py +++ b/test/test_py_d/ts_misc.py @@ -58,8 +58,8 @@ class TestSuiteHelp(TestSuiteBase): def usage(self): t = self.spawn(f'mmgen-walletgen',['foo']) - t.expect('USAGE: mmgen-walletgen') t.expect('MMGenSystemExit(1)') + t.expect('USAGE: mmgen-walletgen') t.req_exit_val = 1 return t diff --git a/test/tooltest2.py b/test/tooltest2.py index b773fdb4..c15b83ad 100755 --- a/test/tooltest2.py +++ b/test/tooltest2.py @@ -778,7 +778,7 @@ def fork_cmd(cmd_name,args,out,opts,stdin_input): vmsg(cp.stderr.strip().decode()) if cp.returncode != 0: import re - m = re.match(b'tool command returned (None|False)'+NL.encode(),cp.stderr) + m = re.search(b'tool command returned (None|False)',cp.stdout) if m: return { b'None': None, b'False': False }[m.group(1)] else: diff --git a/test/unit_tests_d/ut_baseconv.py b/test/unit_tests_d/ut_baseconv.py index 2aa61fbd..a9c00713 100755 --- a/test/unit_tests_d/ut_baseconv.py +++ b/test/unit_tests_d/ut_baseconv.py @@ -4,7 +4,6 @@ test/unit_tests_d/ut_baseconv.py: Base conversion unit test for the MMGen suite """ from mmgen.common import * -from mmgen.exception import * class unit_test(object): diff --git a/test/unit_tests_d/ut_bip39.py b/test/unit_tests_d/ut_bip39.py index 9342092b..697ff9f4 100755 --- a/test/unit_tests_d/ut_bip39.py +++ b/test/unit_tests_d/ut_bip39.py @@ -4,7 +4,6 @@ test/unit_tests_d/ut_bip39: BIP39 unit test for the MMGen suite """ from mmgen.common import * -from mmgen.exception import * class unit_test(object): diff --git a/test/unit_tests_d/ut_daemon.py b/test/unit_tests_d/ut_daemon.py index 9b65e4f5..e277b990 100755 --- a/test/unit_tests_d/ut_daemon.py +++ b/test/unit_tests_d/ut_daemon.py @@ -5,7 +5,6 @@ test/unit_tests_d/ut_daemon.py: unit test for the MMGen suite's Daemon class from subprocess import run,DEVNULL from mmgen.common import * -from mmgen.exception import * from mmgen.daemon import * from mmgen.protocol import init_proto diff --git a/test/unit_tests_d/ut_flags.py b/test/unit_tests_d/ut_flags.py index 352fe320..227b61f0 100755 --- a/test/unit_tests_d/ut_flags.py +++ b/test/unit_tests_d/ut_flags.py @@ -4,7 +4,6 @@ test/unit_tests_d/ut_flags.py: unit test for the MMGen suite's ClassFlags class """ from mmgen.common import * -from mmgen.exception import * from mmgen.flags import * class unit_test(object): diff --git a/test/unit_tests_d/ut_lockable.py b/test/unit_tests_d/ut_lockable.py index 47b646c5..3cf45045 100755 --- a/test/unit_tests_d/ut_lockable.py +++ b/test/unit_tests_d/ut_lockable.py @@ -4,7 +4,6 @@ test/unit_tests_d/ut_lockable.py: unit test for the MMGen suite's Lockable class """ from mmgen.common import * -from mmgen.exception import * class unit_test(object): diff --git a/test/unit_tests_d/ut_rpc.py b/test/unit_tests_d/ut_rpc.py index cb36fb5b..3fe0fbd2 100755 --- a/test/unit_tests_d/ut_rpc.py +++ b/test/unit_tests_d/ut_rpc.py @@ -4,7 +4,6 @@ test.unit_tests_d.ut_rpc: RPC unit test for the MMGen suite """ from mmgen.common import * -from mmgen.exception import * from mmgen.protocol import init_proto from mmgen.rpc import rpc_init,MoneroWalletRPCClient diff --git a/test/unit_tests_d/ut_xmrseed.py b/test/unit_tests_d/ut_xmrseed.py index ff36f527..450b247e 100755 --- a/test/unit_tests_d/ut_xmrseed.py +++ b/test/unit_tests_d/ut_xmrseed.py @@ -4,7 +4,6 @@ test/unit_tests_d/ut_xmrseed: Monero mnemonic unit test for the MMGen suite """ from mmgen.common import * -from mmgen.exception import * class unit_test(object):