Browse Source

import cleanups throughout

The MMGen Project 3 years ago
parent
commit
ad569cbeb7

+ 0 - 2
mmgen/amt.py

@@ -23,8 +23,6 @@ amt.py: MMGen CoinAmt and related classes
 from decimal import Decimal
 from decimal import Decimal
 from .objmethods import Hilite,InitErrors
 from .objmethods import Hilite,InitErrors
 
 
-class UnknownCoinAmt(Decimal): pass
-
 class DecimalNegateResult(Decimal): pass
 class DecimalNegateResult(Decimal): pass
 
 
 class CoinAmt(Decimal,Hilite,InitErrors): # abstract class
 class CoinAmt(Decimal,Hilite,InitErrors): # abstract class

+ 3 - 2
mmgen/baseconv.py

@@ -21,10 +21,11 @@ baseconv.py:  base conversion class for the MMGen suite
 """
 """
 
 
 from hashlib import sha256
 from hashlib import sha256
-from .exception import *
-from .util import die
 from collections import namedtuple
 from collections import namedtuple
 
 
+from .exception import BaseConversionError,BaseConversionPadError,HexadecimalStringError,SeedLengthError
+from .util import die
+
 def is_b58_str(s):
 def is_b58_str(s):
 	return set(list(s)) <= set(baseconv('b58').digits)
 	return set(list(s)) <= set(baseconv('b58').digits)
 
 

+ 1 - 1
mmgen/bip39.py

@@ -22,7 +22,7 @@ bip39.py - Data and routines for BIP39 mnemonic seed phrases
 
 
 from hashlib import sha256
 from hashlib import sha256
 
 
-from .exception import *
+from .exception import MnemonicError
 from .baseconv import baseconv
 from .baseconv import baseconv
 from .util import is_hex_str
 from .util import is_hex_str
 
 

+ 6 - 3
mmgen/daemon.py

@@ -20,11 +20,13 @@
 daemon.py:  Daemon control interface for the MMGen suite
 daemon.py:  Daemon control interface for the MMGen suite
 """
 """
 
 
-import shutil
+import os,shutil,time
 from subprocess import run,PIPE,CompletedProcess
 from subprocess import run,PIPE,CompletedProcess
 from collections import namedtuple
 from collections import namedtuple
-from .exception import *
-from .common import *
+
+from .globalvars import g
+from .opts import opt
+from .util import msg,die,list_gen,get_subclasses
 from .flags import *
 from .flags import *
 
 
 _dd = namedtuple('daemon_data',['coind_name','coind_version','coind_version_str']) # latest tested version
 _dd = namedtuple('daemon_data',['coind_name','coind_version','coind_version_str']) # latest tested version
@@ -78,6 +80,7 @@ class Daemon(Lockable):
 		try:
 		try:
 			cp = run(cmd,check=False,stdout=out,stderr=out)
 			cp = run(cmd,check=False,stdout=out,stderr=out)
 		except Exception as e:
 		except Exception as e:
+			from .exception import MMGenCalledProcessError
 			raise MMGenCalledProcessError(f'Error starting executable: {type(e).__name__} [Errno {e.errno}]')
 			raise MMGenCalledProcessError(f'Error starting executable: {type(e).__name__} [Errno {e.errno}]')
 		if self.debug:
 		if self.debug:
 			print(cp)
 			print(cp)

+ 2 - 1
mmgen/fileutil.py

@@ -23,7 +23,6 @@ fileutil.py: Routines that read, write, execute or stat files
 import sys,os
 import sys,os
 
 
 from .globalvars import g
 from .globalvars import g
-from .exception import FileNotFound,MaxInputSizeExceeded
 from .util import (
 from .util import (
 	msg,
 	msg,
 	qmsg,
 	qmsg,
@@ -90,6 +89,7 @@ def _check_file_type_and_access(fname,ftype,blkdev_ok=False):
 	try:
 	try:
 		mode = os.stat(fname).st_mode
 		mode = os.stat(fname).st_mode
 	except:
 	except:
+		from .exception import FileNotFound
 		raise FileNotFound(f'Requested {ftype} {fname!r} not found')
 		raise FileNotFound(f'Requested {ftype} {fname!r} not found')
 
 
 	for t in ok_types:
 	for t in ok_types:
@@ -289,6 +289,7 @@ def get_data_from_file(infile,desc='data',dash=False,silent=False,binary=False,q
 		data = data.decode()
 		data = data.decode()
 
 
 	if len(data) == g.max_input_size + 1:
 	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')
 		raise MaxInputSizeExceeded(f'Too much input data!  Max input data size: {f.max_input_size} bytes')
 
 
 	return data
 	return data

+ 4 - 8
mmgen/main_autosign.py

@@ -24,6 +24,8 @@ import sys,os,time,signal,shutil
 from subprocess import run,PIPE,DEVNULL
 from subprocess import run,PIPE,DEVNULL
 from stat import *
 from stat import *
 
 
+from .common import *
+
 mountpoint   = '/mnt/tx'
 mountpoint   = '/mnt/tx'
 tx_dir       = '/mnt/tx/tx'
 tx_dir       = '/mnt/tx/tx'
 part_label   = 'MMGEN_TX'
 part_label   = 'MMGEN_TX'
@@ -35,10 +37,8 @@ mn_fmts      = {
 }
 }
 mn_fmt_dfl   = 'mmgen'
 mn_fmt_dfl   = 'mmgen'
 
 
-from .common import *
 opts.UserOpts._set_ok += ('outdir','passwd_file')
 opts.UserOpts._set_ok += ('outdir','passwd_file')
 
 
-prog_name = os.path.basename(sys.argv[0])
 opts_data = {
 opts_data = {
 	'sets': [('stealth_led', True, 'led', True)],
 	'sets': [('stealth_led', True, 'led', True)],
 	'text': {
 	'text': {
@@ -118,7 +118,7 @@ This command is currently available only on Linux-based platforms.
 
 
 cmd_args = opts.init(
 cmd_args = opts.init(
 	opts_data,
 	opts_data,
-	add_opts = ['outdir','passwd_file'], # required, because in _set_ok
+	add_opts = ['outdir','passwd_file'], # in _set_ok, so must be set
 	init_opts = {
 	init_opts = {
 		'quiet': True,
 		'quiet': True,
 		'out_fmt': 'wallet',
 		'out_fmt': 'wallet',
@@ -135,15 +135,12 @@ if opt.mnemonic_fmt:
 			opt.mnemonic_fmt,
 			opt.mnemonic_fmt,
 			fmt_list(mn_fmts,fmt='no_spc') ))
 			fmt_list(mn_fmts,fmt='no_spc') ))
 
 
-import mmgen.tx
 from .wallet import Wallet
 from .wallet import Wallet
+from .tx import MMGenTX
 from .txsign import txsign
 from .txsign import txsign
 from .protocol import init_proto
 from .protocol import init_proto
 from .rpc import rpc_init
 from .rpc import rpc_init
 
 
-if g.test_suite:
-	from .daemon import CoinDaemon
-
 if opt.mountpoint:
 if opt.mountpoint:
 	mountpoint = opt.mountpoint
 	mountpoint = opt.mountpoint
 
 
@@ -198,7 +195,6 @@ def do_umount():
 		run(['umount',mountpoint],check=True)
 		run(['umount',mountpoint],check=True)
 
 
 async def sign_tx_file(txfile):
 async def sign_tx_file(txfile):
-	from .tx import MMGenTX
 	try:
 	try:
 		tx1 = MMGenTX.Unsigned(filename=txfile)
 		tx1 = MMGenTX.Unsigned(filename=txfile)
 		if tx1.proto.sign_mode == 'daemon':
 		if tx1.proto.sign_mode == 'daemon':

+ 1 - 1
mmgen/passwdlist.py

@@ -22,7 +22,6 @@ passwdlist.py: Password list class for the MMGen suite
 
 
 from collections import namedtuple
 from collections import namedtuple
 
 
-from .exception import InvalidPasswdFormat
 from .util import ymsg,is_hex_str,is_int,keypress_confirm
 from .util import ymsg,is_hex_str,is_int,keypress_confirm
 from .obj import ImmutableAttr,ListItemAttr,MMGenPWIDString
 from .obj import ImmutableAttr,ListItemAttr,MMGenPWIDString
 from .baseconv import baseconv,is_b32_str,is_b58_str
 from .baseconv import baseconv,is_b32_str,is_b58_str
@@ -115,6 +114,7 @@ class PasswordList(AddrList):
 			self.pw_fmt = pw_fmt
 			self.pw_fmt = pw_fmt
 			self.pw_fmt_disp = pw_fmt
 			self.pw_fmt_disp = pw_fmt
 		if self.pw_fmt not in self.pw_info:
 		if self.pw_fmt not in self.pw_info:
+			from .exception import InvalidPasswdFormat
 			raise InvalidPasswdFormat(
 			raise InvalidPasswdFormat(
 				'{!r}: invalid password format.  Valid formats: {}'.format(
 				'{!r}: invalid password format.  Valid formats: {}'.format(
 					self.pw_fmt,
 					self.pw_fmt,

+ 3 - 1
mmgen/seedsplit.py

@@ -22,7 +22,6 @@ seedsplit.py: Seed split classes and methods for the MMGen suite
 
 
 from .globalvars import g
 from .globalvars import g
 from .color import yellow
 from .color import yellow
-from .exception import RangeError
 from .obj import MMGenPWIDString,MMGenIdx
 from .obj import MMGenPWIDString,MMGenIdx
 from .subseed import *
 from .subseed import *
 
 
@@ -81,6 +80,7 @@ class SeedShareList(SubSeedList):
 						msg(f'master_share seed ID collision with parent seed, incrementing nonce to {nonce+1}')
 						msg(f'master_share seed ID collision with parent seed, incrementing nonce to {nonce+1}')
 				else:
 				else:
 					return ms
 					return ms
+			from .exception import SubSeedNonceRangeExceeded
 			raise SubSeedNonceRangeExceeded('nonce range exceeded')
 			raise SubSeedNonceRangeExceeded('nonce range exceeded')
 
 
 		def last_share_debug(last_share):
 		def last_share_debug(last_share):
@@ -109,6 +109,7 @@ class SeedShareList(SubSeedList):
 				self.data['long'][ls.sid] = (count,nonce)
 				self.data['long'][ls.sid] = (count,nonce)
 				break
 				break
 		else:
 		else:
+			from .exception import SubSeedNonceRangeExceeded
 			raise SubSeedNonceRangeExceeded('nonce range exceeded')
 			raise SubSeedNonceRangeExceeded('nonce range exceeded')
 
 
 		if g.debug_subseed:
 		if g.debug_subseed:
@@ -118,6 +119,7 @@ class SeedShareList(SubSeedList):
 
 
 	def get_share_by_idx(self,idx,base_seed=False):
 	def get_share_by_idx(self,idx,base_seed=False):
 		if idx < 1 or idx > self.count:
 		if idx < 1 or idx > self.count:
+			from .exception import RangeError
 			raise RangeError(f'{idx}: share index out of range')
 			raise RangeError(f'{idx}: share index out of range')
 		elif idx == self.count:
 		elif idx == self.count:
 			return self.last_share
 			return self.last_share

+ 1 - 1
mmgen/subseed.py

@@ -22,7 +22,6 @@ subseed.py:  Subseed classes and methods for the MMGen suite
 
 
 from .color import green
 from .color import green
 from .util import msg_r,msg,qmsg
 from .util import msg_r,msg,qmsg
-from .exception import SubSeedNonceRangeExceeded
 from .obj import MMGenRange,IndexedDict
 from .obj import MMGenRange,IndexedDict
 from .seed import *
 from .seed import *
 from .crypto import scramble_seed
 from .crypto import scramble_seed
@@ -192,6 +191,7 @@ class SubSeedList(MMGenObject):
 					self.data[length][sid] = (idx,nonce)
 					self.data[length][sid] = (idx,nonce)
 					return last_sid == sid
 					return last_sid == sid
 			else: # must exit here, as this could leave self.data in inconsistent state
 			else: # must exit here, as this could leave self.data in inconsistent state
+				from .exception import SubSeedNonceRangeExceeded
 				raise SubSeedNonceRangeExceeded('add_subseed(): nonce range exceeded')
 				raise SubSeedNonceRangeExceeded('add_subseed(): nonce range exceeded')
 
 
 		for idx in SubSeedIdxRange(first_idx,last_idx).iterate():
 		for idx in SubSeedIdxRange(first_idx,last_idx).iterate():

+ 4 - 9
mmgen/tool.py

@@ -20,19 +20,20 @@
 tool.py:  Routines for the 'mmgen-tool' utility
 tool.py:  Routines for the 'mmgen-tool' utility
 """
 """
 
 
-from .protocol import hash160
 from .common import *
 from .common import *
+from .protocol import hash160
+from .fileutil import get_seed_file,get_data_from_file,write_data_to_file
 from .crypto import get_random
 from .crypto import get_random
 from .key import PrivKey
 from .key import PrivKey
 from .subseed import SubSeedList
 from .subseed import SubSeedList
 from .seedsplit import MasterShareIdx
 from .seedsplit import MasterShareIdx
 from .addr import *
 from .addr import *
-from .addrlist import AddrList,KeyAddrList
+from .addrlist import AddrList,KeyAddrList,AddrIdxList
 from .passwdlist import PasswordList
 from .passwdlist import PasswordList
 from .baseconv import baseconv
 from .baseconv import baseconv
 from .xmrseed import xmrseed
 from .xmrseed import xmrseed
 from .bip39 import bip39
 from .bip39 import bip39
-from .fileutil import get_seed_file,get_data_from_file,write_data_to_file
+from .tw import TwCommon
 
 
 NL = ('\n','\r\n')[g.platform=='win']
 NL = ('\n','\r\n')[g.platform=='win']
 
 
@@ -234,8 +235,6 @@ def _process_result(ret,pager=False,print_result=False):
 	else:
 	else:
 		ydie(1,f'tool.py: can’t handle return value of type {type(ret).__name__!r}')
 		ydie(1,f'tool.py: can’t handle return value of type {type(ret).__name__!r}')
 
 
-from .addr import MMGenAddrType
-
 dfl_mnemonic_fmt = 'mmgen'
 dfl_mnemonic_fmt = 'mmgen'
 mft = namedtuple('mnemonic_format',['fmt','pad','conv_cls'])
 mft = namedtuple('mnemonic_format',['fmt','pad','conv_cls'])
 mnemonic_fmts = {
 mnemonic_fmts = {
@@ -895,7 +894,6 @@ class MMGenToolCmdWallet(MMGenToolCmds):
 		ss = Wallet(sf)
 		ss = Wallet(sf)
 		if ss.seed.sid != addr.sid:
 		if ss.seed.sid != addr.sid:
 			die(1,f'Seed ID of requested address ({addr.sid}) does not match wallet ({ss.seed.sid})')
 			die(1,f'Seed ID of requested address ({addr.sid}) does not match wallet ({ss.seed.sid})')
-		from .addrlist import AddrList,AddrIdxList
 		al = AddrList(
 		al = AddrList(
 			proto     = self.proto,
 			proto     = self.proto,
 			seed      = ss.seed,
 			seed      = ss.seed,
@@ -905,8 +903,6 @@ class MMGenToolCmdWallet(MMGenToolCmds):
 		ret = d.sec.wif if target=='wif' else d.addr
 		ret = d.sec.wif if target=='wif' else d.addr
 		return ret
 		return ret
 
 
-from .tw import TwCommon
-
 class MMGenToolCmdRPC(MMGenToolCmds):
 class MMGenToolCmdRPC(MMGenToolCmds):
 	"tracking wallet commands using the JSON-RPC interface"
 	"tracking wallet commands using the JSON-RPC interface"
 
 
@@ -964,7 +960,6 @@ class MMGenToolCmdRPC(MMGenToolCmds):
 				die(1,
 				die(1,
 					f'{mmgen_addrs}: invalid address list argument ' +
 					f'{mmgen_addrs}: invalid address list argument ' +
 					'(must be in form <seed ID>:[<type>:]<idx list>)' )
 					'(must be in form <seed ID>:[<type>:]<idx list>)' )
-			from .addrlist import AddrIdxList
 			usr_addr_list = [MMGenID(self.proto,f'{a[0]}:{i}') for i in AddrIdxList(a[1])]
 			usr_addr_list = [MMGenID(self.proto,f'{a[0]}:{i}') for i in AddrIdxList(a[1])]
 
 
 		from .twaddrs import TwAddrList
 		from .twaddrs import TwAddrList

+ 1 - 1
mmgen/twaddrs.py

@@ -21,7 +21,6 @@ twaddrs: Tracking wallet listaddresses class for the MMGen suite
 """
 """
 
 
 from .color import green
 from .color import green
-from .exception import BadAgeFormat
 from .util import msg,die,altcoin_subclass
 from .util import msg,die,altcoin_subclass
 from .base_obj import AsyncInit
 from .base_obj import AsyncInit
 from .obj import MMGenList,MMGenDict,TwComment
 from .obj import MMGenList,MMGenDict,TwComment
@@ -125,6 +124,7 @@ class TwAddrList(MMGenDict,TwCommon,metaclass=AsyncInit):
 		if not self.has_age:
 		if not self.has_age:
 			show_age = False
 			show_age = False
 		if age_fmt not in self.age_fmts:
 		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})')
 			raise 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]
 		fs = '{mid}' + ('',' {addr}')[showbtcaddrs] + ' {cmt} {amt}' + ('',' {age}')[show_age]
 		mmaddrs = [k for k in self.keys() if k.type == 'mmgen']
 		mmaddrs = [k for k in self.keys() if k.type == 'mmgen']

+ 2 - 1
mmgen/twctl.py

@@ -21,7 +21,6 @@ twctl: Tracking wallet control class for the MMGen suite
 """
 """
 
 
 from .globalvars import g
 from .globalvars import g
-from .exception import WalletFileError
 from .util import msg,dmsg,write_mode,altcoin_subclass
 from .util import msg,dmsg,write_mode,altcoin_subclass
 from .base_obj import AsyncInit
 from .base_obj import AsyncInit
 from .objmethods import MMGenObject
 from .objmethods import MMGenObject
@@ -62,6 +61,7 @@ class TrackingWallet(MMGenObject,metaclass=AsyncInit):
 			self.init_empty()
 			self.init_empty()
 
 
 		if self.data['coin'] != self.proto.coin: # TODO remove?
 		if self.data['coin'] != self.proto.coin: # TODO remove?
+			from .exception import WalletFileError
 			raise WalletFileError(
 			raise WalletFileError(
 				'Tracking wallet coin ({}) does not match current coin ({})!'.format(
 				'Tracking wallet coin ({}) does not match current coin ({})!'.format(
 					self.data['coin'],
 					self.data['coin'],
@@ -98,6 +98,7 @@ class TrackingWallet(MMGenObject,metaclass=AsyncInit):
 				self.init_empty()
 				self.init_empty()
 				self.force_write()
 				self.force_write()
 			else:
 			else:
+				from .exception import WalletFileError
 				raise WalletFileError(f'File {self.tw_fn!r} exists but does not contain valid json data')
 				raise WalletFileError(f'File {self.tw_fn!r} exists but does not contain valid json data')
 		else:
 		else:
 			self.upgrade_wallet_maybe()
 			self.upgrade_wallet_maybe()

+ 1 - 1
mmgen/twuo.py

@@ -25,7 +25,6 @@ from collections import namedtuple
 
 
 from .globalvars import g
 from .globalvars import g
 from .color import red,yellow,green
 from .color import red,yellow,green
-from .exception import BadAgeFormat
 from .util import (
 from .util import (
 	msg,
 	msg,
 	msg_r,
 	msg_r,
@@ -129,6 +128,7 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, add [l]abel:
 	@age_fmt.setter
 	@age_fmt.setter
 	def age_fmt(self,val):
 	def age_fmt(self,val):
 		if val not in self.age_fmts:
 		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})')
 			raise BadAgeFormat(f'{val!r}: invalid age format (must be one of {self.age_fmts!r})')
 		self._age_fmt = val
 		self._age_fmt = val
 
 

+ 41 - 4
mmgen/tx.py

@@ -20,10 +20,45 @@
 tx.py:  Transaction routines for the MMGen suite
 tx.py:  Transaction routines for the MMGen suite
 """
 """
 
 
-import sys,os,json
-from stat import *
-from .common import *
-from .obj import *
+import sys,time
+from .globalvars import g
+from .opts import opt
+from .color import *
+from .util import (
+	msg,
+	ymsg,
+	dmsg,
+	vmsg,
+	qmsg,
+	msg_r,
+	die,
+	is_int,
+	fmt,
+	suf,
+	altcoin_subclass,
+	confirm_or_raise,
+	remove_dups,
+	get_extension,
+	keypress_confirm,
+	do_license_msg,
+	line_input,
+	make_chksum_6,
+	make_timestamp,
+	secs_to_dhms,
+)
+from .objmethods import MMGenObject
+from .obj import (
+	ImmutableAttr,
+	ListItemAttr,
+	MMGenList,
+	MMGenListItem,
+	MMGenTxLabel,
+	HexStr,
+	MMGenTxID,
+	MMGenDict,
+	CoinTxID,
+	get_obj,
+)
 from .addr import MMGenID,CoinAddr,is_mmgen_id,is_coin_addr
 from .addr import MMGenID,CoinAddr,is_mmgen_id,is_coin_addr
 
 
 wmsg = lambda k: {
 wmsg = lambda k: {
@@ -148,6 +183,7 @@ class DeserializedTX(dict,MMGenObject):
 				return int(vbytes[::-1].hex(),16)
 				return int(vbytes[::-1].hex(),16)
 
 
 		def make_txid(tx_bytes):
 		def make_txid(tx_bytes):
+			from hashlib import sha256
 			return sha256(sha256(tx_bytes).digest()).digest()[::-1].hex()
 			return sha256(sha256(tx_bytes).digest()).digest()[::-1].hex()
 
 
 		self.idx = 0
 		self.idx = 0
@@ -1356,6 +1392,7 @@ class MMGenTX:
 			vmsg(f'\nVsize: {vsize} (true) {est_vsize} (estimated)')
 			vmsg(f'\nVsize: {vsize} (true) {est_vsize} (estimated)')
 			ratio = float(est_vsize) / vsize
 			ratio = float(est_vsize) / vsize
 			if not (0.95 < ratio < 1.05): # allow for 5% error
 			if not (0.95 < ratio < 1.05): # allow for 5% error
+				from .exception import BadTxSizeEstimate
 				raise BadTxSizeEstimate(fmt(f"""
 				raise BadTxSizeEstimate(fmt(f"""
 					Estimated transaction vsize is {ratio:1.2f} times the true vsize
 					Estimated transaction vsize is {ratio:1.2f} times the true vsize
 					Your transaction fee estimates will be inaccurate
 					Your transaction fee estimates will be inaccurate

+ 2 - 2
mmgen/txfile.py

@@ -23,8 +23,6 @@ txfile.py:  Transaction file operations for the MMGen suite
 from .common import *
 from .common import *
 from .obj import HexStr,MMGenTxID,CoinTxID,MMGenTxLabel
 from .obj import HexStr,MMGenTxID,CoinTxID,MMGenTxLabel
 from .tx import MMGenTxOutput,MMGenTxOutputList,MMGenTxInput,MMGenTxInputList
 from .tx import MMGenTxOutput,MMGenTxOutputList,MMGenTxInput,MMGenTxInputList
-from .amt import UnknownCoinAmt
-from .exception import MaxFileSizeExceeded
 
 
 class MMGenTxFile:
 class MMGenTxFile:
 
 
@@ -63,6 +61,7 @@ class MMGenTxFile:
 		try:
 		try:
 			desc = 'data'
 			desc = 'data'
 			if len(tx_data) > g.max_tx_file_size:
 			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)')
 				raise MaxFileSizeExceeded(f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)')
 			tx_data = tx_data.splitlines()
 			tx_data = tx_data.splitlines()
 			assert len(tx_data) >= 5,'number of lines less than 5'
 			assert len(tx_data) >= 5,'number of lines less than 5'
@@ -188,6 +187,7 @@ class MMGenTxFile:
 		self.chksum = make_chksum_6(' '.join(lines))
 		self.chksum = make_chksum_6(' '.join(lines))
 		fmt_data = '\n'.join([self.chksum] + lines) + '\n'
 		fmt_data = '\n'.join([self.chksum] + lines) + '\n'
 		if len(fmt_data) > g.max_tx_file_size:
 		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)')
 			raise MaxFileSizeExceeded(f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)')
 		return fmt_data
 		return fmt_data
 
 

+ 21 - 22
mmgen/util.py

@@ -25,8 +25,8 @@ from hashlib import sha256
 from string import hexdigits,digits
 from string import hexdigits,digits
 
 
 from .color import *
 from .color import *
-from .exception import BadFileExtension,UserNonConfirmation
 from .globalvars import g
 from .globalvars import g
+from .opts import opt
 
 
 CUR_HIDE = '\033[?25l'
 CUR_HIDE = '\033[?25l'
 CUR_SHOW = '\033[?25h'
 CUR_SHOW = '\033[?25h'
@@ -65,6 +65,24 @@ def gmsg(s):   msg(green(s))
 def gmsg_r(s): msg_r(green(s))
 def gmsg_r(s): msg_r(green(s))
 def bmsg(s):   msg(blue(s))
 def bmsg(s):   msg(blue(s))
 def bmsg_r(s): msg_r(blue(s))
 def bmsg_r(s): msg_r(blue(s))
+def qmsg(s,alt=None):
+	if opt.quiet:
+		if alt != None: msg(alt)
+	else: msg(s)
+def qmsg_r(s,alt=None):
+	if opt.quiet:
+		if alt != None: msg_r(alt)
+	else: msg_r(s)
+def vmsg(s,force=False):
+	if opt.verbose or force: msg(s)
+def vmsg_r(s,force=False):
+	if opt.verbose or force: msg_r(s)
+def Vmsg(s,force=False):
+	if opt.verbose or force: Msg(s)
+def Vmsg_r(s,force=False):
+	if opt.verbose or force: Msg_r(s)
+def dmsg(s):
+	if opt.debug: msg(s)
 
 
 def mmsg(*args):
 def mmsg(*args):
 	for d in args: Msg(repr(d))
 	for d in args: Msg(repr(d))
@@ -239,27 +257,6 @@ def parse_bytespec(nbytes):
 
 
 	die(1,f'{nbytes!r}: invalid byte specifier')
 	die(1,f'{nbytes!r}: invalid byte specifier')
 
 
-from .opts import opt
-
-def qmsg(s,alt=None):
-	if opt.quiet:
-		if alt != None: msg(alt)
-	else: msg(s)
-def qmsg_r(s,alt=None):
-	if opt.quiet:
-		if alt != None: msg_r(alt)
-	else: msg_r(s)
-def vmsg(s,force=False):
-	if opt.verbose or force: msg(s)
-def vmsg_r(s,force=False):
-	if opt.verbose or force: msg_r(s)
-def Vmsg(s,force=False):
-	if opt.verbose or force: Msg(s)
-def Vmsg_r(s,force=False):
-	if opt.verbose or force: Msg_r(s)
-def dmsg(s):
-	if opt.debug: msg(s)
-
 def suf(arg,suf_type='s',verb='none'):
 def suf(arg,suf_type='s',verb='none'):
 	suf_types = {
 	suf_types = {
 		'none': {
 		'none': {
@@ -449,6 +446,7 @@ def compare_or_die(val1, desc1, val2, desc2, e='Error'):
 def check_wallet_extension(fn):
 def check_wallet_extension(fn):
 	from .wallet import Wallet
 	from .wallet import Wallet
 	if not Wallet.ext_to_type(get_extension(fn)):
 	if not Wallet.ext_to_type(get_extension(fn)):
+		from .exception import BadFileExtension
 		raise BadFileExtension(f'{fn!r}: unrecognized seed source file extension')
 		raise BadFileExtension(f'{fn!r}: unrecognized seed source file extension')
 
 
 def make_full_path(outdir,outfile):
 def make_full_path(outdir,outfile):
@@ -460,6 +458,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'
 	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: '
 	b = f'Type uppercase {expect!r} to confirm: '
 	if line_input(a+b).strip() != expect:
 	if line_input(a+b).strip() != expect:
+		from .exception import UserNonConfirmation
 		raise UserNonConfirmation(exit_msg)
 		raise UserNonConfirmation(exit_msg)
 
 
 def get_words_from_user(prompt):
 def get_words_from_user(prompt):

+ 4 - 1
mmgen/xmrseed.py

@@ -20,7 +20,6 @@
 xmrseed.py: Monero mnemonic conversion class for the MMGen suite
 xmrseed.py: Monero mnemonic conversion class for the MMGen suite
 """
 """
 
 
-from .exception import *
 from .baseconv import baseconv
 from .baseconv import baseconv
 from .util import die
 from .util import die
 
 
@@ -55,6 +54,8 @@ class xmrseed(baseconv):
 		wl = self.digits
 		wl = self.digits
 		base = len(wl)
 		base = len(wl)
 
 
+		from .exception import MnemonicError
+
 		if not set(words) <= set(wl):
 		if not set(words) <= set(wl):
 			raise MnemonicError( f'{words!r}: not in {desc} format' )
 			raise MnemonicError( f'{words!r}: not in {desc} format' )
 
 
@@ -64,6 +65,7 @@ class xmrseed(baseconv):
 		z = self.monero_mn_checksum(words[:-1])
 		z = self.monero_mn_checksum(words[:-1])
 		if z != words[-1]:
 		if z != words[-1]:
 			raise MnemonicError(f'invalid {desc} checksum')
 			raise MnemonicError(f'invalid {desc} checksum')
+
 		words = tuple(words[:-1])
 		words = tuple(words[:-1])
 
 
 		def gen():
 		def gen():
@@ -82,6 +84,7 @@ class xmrseed(baseconv):
 		base = len(wl)
 		base = len(wl)
 
 
 		if len(bytestr) not in self.seedlen_map:
 		if len(bytestr) not in self.seedlen_map:
+			from .exception import SeedLengthError
 			raise SeedLengthError(f'{len(bytestr)}: invalid seed byte length for {desc}')
 			raise SeedLengthError(f'{len(bytestr)}: invalid seed byte length for {desc}')
 
 
 		def num2base_monero(num):
 		def num2base_monero(num):

+ 1 - 0
test/objattrtest.py

@@ -31,6 +31,7 @@ os.environ['MMGEN_TEST_SUITE'] = '1'
 
 
 # Import these _after_ local path's been added to sys.path
 # Import these _after_ local path's been added to sys.path
 from test.objattrtest_py_d.oat_common import *
 from test.objattrtest_py_d.oat_common import *
+from mmgen.common import *
 from mmgen.addrlist import *
 from mmgen.addrlist import *
 from mmgen.passwdlist import *
 from mmgen.passwdlist import *