Browse Source

Small changes in opts handling code

philemon 10 years ago
parent
commit
4c4377d618

+ 0 - 1
mmgen/addr.py

@@ -90,7 +90,6 @@ def generate_addrs(seed, addrnums):
 		seed = sha512(seed).digest()
 		num += 1 # round
 
-		if opt.debug: print "Seed round %s: %s" % (num, hexlify(seed))
 		if num != addrnums[pos]: continue
 
 		pos += 1

+ 4 - 4
mmgen/bitcoin.py

@@ -79,10 +79,10 @@ def verify_addr(addr,verbose=False,return_hex=False):
 		if step2[:8] == addr_hex[42:]:
 			return addr_hex[2:42] if return_hex else True
 		else:
-			if verbose: print "Invalid checksum in address '%s'" % addr
+			if verbose: Msg("Invalid checksum in address '%s'" % addr)
 			break
 
-	if verbose: print "Invalid address '%s'" % addr
+	if verbose: Msg("Invalid address '%s'" % addr)
 	return False
 
 
@@ -134,8 +134,8 @@ def _b58_pad(s,a,b,pad,f,w):
 	try:
 		outlen = b[a.index(len(s))]
 	except:
-		print "_b58_pad() accepts only %s %s bytes long "\
-			"(input was %s bytes)" % (w,",".join([str(i) for i in a]),len(s))
+		Msg("_b58_pad() accepts only %s %s bytes long "\
+			"(input was %s bytes)" % (w,",".join([str(i) for i in a]),len(s)))
 		return False
 
 	out = f(s)

+ 3 - 3
mmgen/config.py

@@ -51,6 +51,9 @@ email     = "<mmgen-py@yandex.com>"
 Cdates    = '2013-2015'
 version   = '0.7.9'
 
+required_opts = [ # list must contain "usr_randchars"
+	"quiet","verbose","debug","outdir","echo_passphrase","passwd_file","usr_randchars"
+]
 min_screen_width = 80
 max_tx_comment_len = 72
 
@@ -74,9 +77,6 @@ mmenc_ext           = "mmenc"
 default_wl    = "electrum"
 #default_wl    = "tirosh"
 
-# If user opt is set, different global opt is set to 'True'
-usr_set_vars = { "usr_randchars": "use_urandchars" }
-
 # Global value sets user opt
 dfl_vars = "seed_len","hash_preset","usr_randchars","debug"
 

+ 7 - 8
mmgen/crypto.py

@@ -90,7 +90,7 @@ def decrypt_seed(enc_seed, key, seed_id, key_id):
 #	else:
 #		qmsg("Generated IDs (Seed/Key): %s/%s" % (chk2,chk1))
 
-	if opt.debug: print "Decrypted seed: %s" % hexlify(dec_seed)
+	if opt.debug: Msg("Decrypted seed: %s" % hexlify(dec_seed))
 
 	vmsg("OK")
 	return dec_seed
@@ -155,11 +155,10 @@ def make_key(passwd,salt,hash_preset,
 
 	if from_what: what += " from "
 	if opt.verbose or verbose:
-		msg_r("Generating %s%s.\nPlease wait..." % (what,from_what))
+		msg_r("Generating %s%s..." % (what,from_what))
 	key = scrypt_hash_passphrase(passwd, salt, hash_preset)
-	if opt.verbose or verbose:
-		msg("done")
-	if opt.debug: print "Key: %s" % hexlify(key)
+	if opt.verbose or verbose: msg("done")
+	if opt.debug: Msg("Key: %s" % hexlify(key))
 	return key
 
 
@@ -399,7 +398,7 @@ def _get_seed(infile,silent=False,seed_id=""):
 		msg("Invalid %s file '%s'" % (source,infile))
 		sys.exit(2)
 
-	if opt.debug: print "Seed: %s" % hexlify(seed)
+	if opt.debug: Msg("Seed: %s" % hexlify(seed))
 
 	return seed
 
@@ -415,9 +414,9 @@ def get_seed_retry(infile,seed_id=""):
 
 def _get_seed_from_brain_passphrase(words):
 	bp = " ".join(words)
-	if opt.debug: print "Sanitized brain passphrase: %s" % bp
+	if opt.debug: Msg("Sanitized brain passphrase: %s" % bp)
 	seed_len,hash_preset = get_from_brain_opt_params()
-	if opt.debug: print "Brainwallet l = %s, p = %s" % (seed_len,hash_preset)
+	if opt.debug: Msg("Brainwallet l = %s, p = %s" % (seed_len,hash_preset))
 	vmsg_r("Hashing brainwallet data.  Please wait...")
 	# Use buflen arg of scrypt.hash() to get seed of desired length
 	seed = scrypt_hash_passphrase(bp, "", hash_preset, buflen=seed_len/8)

+ 1 - 3
mmgen/main_addrgen.py

@@ -118,8 +118,6 @@ cmd_args = opt.opts.init(opts_data,add_opts=["b16"])
 if opt.show_hash_presets: show_hash_presets()
 if opt.from_incog_hex or opt.from_incog_hidden: opt.from_incog = True
 
-if opt.debug: opt.opts.show_opts_and_cmd_args(cmd_args)
-
 if len(cmd_args) == 1 and (
 			opt.from_mnemonic
 			or opt.from_brain
@@ -130,7 +128,7 @@ if len(cmd_args) == 1 and (
 elif len(cmd_args) == 2:
 	infile,addr_idx_arg = cmd_args
 	check_infile(infile)
-else: opt.opts.usage(opts_data)
+else: opt.opts.usage()
 
 addr_idxs = parse_addr_idxs(addr_idx_arg)
 

+ 1 - 1
mmgen/main_tool.py

@@ -48,7 +48,7 @@ command
 cmd_args = opt.opts.init(opts_data)
 
 if len(cmd_args) < 1:
-	opt.opts.usage(opts_data)
+	opt.opts.usage()
 	sys.exit(1)
 
 command = cmd_args.pop(0)

+ 2 - 6
mmgen/main_txcreate.py

@@ -334,8 +334,6 @@ def mmaddr2btcaddr(c,mmaddr,acct_data,ail):
 
 cmd_args = opt.opts.init(opts_data)
 
-if opt.debug: show_opts_and_cmd_args(cmd_args)
-
 if opt.comment_file:
 	comment = get_tx_comment_from_file(opt.comment_file)
 
@@ -394,8 +392,6 @@ if not opt.info:
 		msg("Transaction fee too large: %s > %s" % (tx_fee,g.max_tx_fee))
 		sys.exit(2)
 
-if opt.debug: show_opts_and_cmd_args(cmd_args)
-
 if g.bogus_wallet_data:  # for debugging purposes only
 	import mmgen.rpc.data
 	us = eval(get_data_from_file(g.bogus_wallet_data))
@@ -459,8 +455,8 @@ if change > 0: tx_out[change_addr] = float(change)
 tx_in = [{"txid":i.txid, "vout":i.vout} for i in sel_unspent]
 
 if opt.debug:
-	print "tx_in:", repr(tx_in)
-	print "tx_out:", repr(tx_out)
+	Msg("tx_in:  " + repr(tx_in))
+	Msg("tx_out: " + repr(tx_out))
 
 if opt.comment_file:
 	if keypress_confirm("Edit comment?",False):

+ 1 - 1
mmgen/main_txsend.py

@@ -42,7 +42,7 @@ cmd_args = opt.opts.init(opts_data)
 
 if len(cmd_args) == 1:
 	infile = cmd_args[0]; check_infile(infile)
-else: opt.opts.usage(opts_data)
+else: opt.opts.usage()
 
 # Begin execution
 

+ 4 - 4
mmgen/main_txsign.py

@@ -147,7 +147,7 @@ def sign_transaction(c,tx_hex,tx_num_str,sig_data,keys=None):
 
 	if keys:
 		qmsg("Passing %s key%s to bitcoind" % (len(keys),suf(keys,"k")))
-		if opt.debug: print "Keys:\n  %s" % "\n  ".join(keys)
+		if opt.debug: Msg("Keys:\n  %s" % "\n  ".join(keys))
 
 	msg_r("Signing transaction{}...".format(tx_num_str))
 	from mmgen.rpc import exceptions
@@ -207,10 +207,10 @@ def check_maps_from_seeds(maplist,label,infiles,saved_seeds,return_keys=False):
 		return ret
 
 def missing_keys_errormsg(addrs):
-	print """
+	Msg("""
 A key file must be supplied (or use the '--use-wallet-dat' option)
 for the following non-{} address{}:\n    {}""".format(
-	g.proj_name,suf(addrs,"a"),"\n    ".join(addrs)).strip()
+	g.proj_name,suf(addrs,"a"),"\n    ".join(addrs)).strip())
 
 
 def parse_mmgen_keyaddr_file():
@@ -287,7 +287,7 @@ for l in (
 
 if opt.from_incog_hex or opt.from_incog_hidden: opt.from_incog = True
 
-if not infiles: opt.opts.usage(opts_data)
+if not infiles: opt.opts.usage()
 for i in infiles: check_infile(i)
 
 c = connect_to_bitcoind()

+ 3 - 1
mmgen/main_walletchk.py

@@ -95,6 +95,8 @@ def export_to_hidden_incog(incog_enc):
 	outfile,offset = opt.export_incog_hidden.split(",") #Already sanity-checked
 	if opt.outdir: outfile = make_full_path(opt.outdir,outfile)
 
+	if opt.debug:
+		Msg("Incog data len %s, offset %s" % (len(incog_enc),offset))
 	check_data_fits_file_at_offset(outfile,int(offset),len(incog_enc),"write")
 
 	if not opt.quiet: confirm_or_exit("","alter file '%s'" % outfile)
@@ -112,7 +114,7 @@ cmd_args = opt.opts.init(opts_data)
 if opt.export_incog_hidden or opt.export_incog_hex:
 	opt.export_incog = True
 
-if len(cmd_args) != 1: opt.opts.usage(opts_data)
+if len(cmd_args) != 1: opt.opts.usage()
 
 check_infile(cmd_args[0])
 

+ 1 - 3
mmgen/main_walletgen.py

@@ -125,8 +125,6 @@ cmd_args = opt.opts.init(opts_data)
 
 if opt.show_hash_presets: show_hash_presets()
 
-if opt.debug: opt.opts.show_opts_and_cmd_args(cmd_args)
-
 if len(cmd_args) == 1:
 	infile = cmd_args[0]
 	check_infile(infile)
@@ -140,7 +138,7 @@ if len(cmd_args) == 1:
 		sys.exit(1)
 elif len(cmd_args) == 0:
 	infile = ""
-else: opt.opts.usage(opts_data)
+else: opt.opts.usage()
 
 g.use_urandchars = True
 

+ 9 - 9
mmgen/mnemonic.py

@@ -22,7 +22,7 @@ mnemonic.py:  Mnemonic routines for the MMGen suite
 
 import sys
 from binascii import hexlify
-from mmgen.util import msg,msg_r,make_chksum_8,Vmsg
+from mmgen.util import msg,msg_r,make_chksum_8,Vmsg,Msg
 from mmgen.crypto import get_random
 import mmgen.config as g
 import mmgen.opt as opt
@@ -107,24 +107,24 @@ def get_mnemonic_from_seed(seed, wl, label="", verbose=False):
 
 def check_wordlist(wl,label):
 
-	print "Wordlist: %s" % label.capitalize()
+	Msg("Wordlist: %s" % label.capitalize())
 
 	from hashlib import sha256
 
-	print "Length:   %i words" % len(wl)
+	Msg("Length:   %i words" % len(wl))
 	new_chksum = sha256(" ".join(wl)).hexdigest()[:8]
 
 	if new_chksum != wl_checksums[label]:
-		print "ERROR: Checksum mismatch.  Computed: %s, Saved: %s" % \
-			(new_chksum,wl_checksums[label])
+		Msg("ERROR: Checksum mismatch.  Computed: %s, Saved: %s" % \
+			(new_chksum,wl_checksums[label]))
 		sys.exit(3)
 
-	print "Checksum: %s (matches)" % new_chksum
+	Msg("Checksum: %s (matches)" % new_chksum)
 
 	if (sorted(wl) == wl):
-		print "List is sorted"
+		Msg("List is sorted")
 	else:
-		print "ERROR: List is not sorted!"
+		Msg("ERROR: List is not sorted!")
 		sys.exit(3)
 
 from mmgen.mn_electrum  import electrum_words as el
@@ -146,4 +146,4 @@ def do_random_mn(nbytes,wordlist):
 		wl = get_wordlist(wlname)
 		mn = get_mnemonic_from_seed(r,wl,wordlist)
 		Vmsg("%s wordlist mnemonic:" % (wlname.capitalize()))
-		print " ".join(mn)
+		Msg(" ".join(mn))

+ 1 - 1
mmgen/opt.py

@@ -17,6 +17,6 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 """
-opt.py: an empty namespace for the global opt variables
+opt.py: a namespace for the global opt variables
 """
 import opts

+ 77 - 64
mmgen/opts.py

@@ -17,24 +17,25 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 """
-opts.py:  Further options processing after mmgen.share.Opts
+opts.py:  MMGen-specific options processing after general processing by share.Opts
 """
 import sys
 
 import mmgen.config as g
 import mmgen.share.Opts
 import opt
-from mmgen.util import msg,msgrepr_exit,msgrepr
+from mmgen.util import msg,msgrepr_exit,msgrepr,Msg
 
-def usage(opts_data):
-	print "USAGE: %s %s" % (opts_data['prog_name'], opts_data['usage'])
+def usage():
+	Msg("USAGE: %s %s" % (g.prog_name, usage_txt))
 	sys.exit(2)
 
 def print_version_info():
-	print """
-'{g.prog_name}' version {g.version}.  Part of the {g.proj_name} suite.
-Copyright (C) {g.Cdates} by {g.author} {g.email}.
-""".format(g=g).strip()
+	Msg("""
+{pnu} version {g.version}.  Part of the {g.proj_name} suite, a Bitcoin
+cold-storage solution for the command line.  Copyright (C) {g.Cdates}
+by {g.author} {g.email}
+""".format(g=g,pnu=g.prog_name.upper()).strip())
 
 def warn_incompatible_opts(incompat_list):
 	bad = [k for k in opt.__dict__ if opt.__dict__[k] and k in incompat_list]
@@ -43,13 +44,15 @@ def warn_incompatible_opts(incompat_list):
 					["--"+b.replace("_","-") for b in bad]))
 		sys.exit(1)
 
-def typeconvert_from_dfl(opts,opt):
+def typeconvert_from_dfl(key):
 
-	vtype = type(g.__dict__[opt])
-	if g.debug: print "Override opt: %-15s [%s]" % (opt,vtype)
+	vtype = type(g.__dict__[key])
+	if g.debug: Msg("Override opt: %-15s [%s]" % (key,vtype))
+
+	global opt
 
 	try:
-		opts[opt] = vtype(opts[opt])
+		opt.__dict__[key] = vtype(opt.__dict__[key])
 	except:
 		d = {
 			'int':   'an integer',
@@ -57,9 +60,10 @@ def typeconvert_from_dfl(opts,opt):
 			'float': 'a float',
 			'bool':  'a boolean value',
 		}
-		m = [d[k] for k in d if __builtins__[k] == vtype][0]
-		msg("'%s': invalid parameter for '--%s' option (not %s)" %
-				(opts[opt],opt.replace("_","-"),m))
+		m = [d[k] for k in d if __builtins__[k] == vtype]
+		msgrepr_exit(key,vtype)
+		fs = "'%s': invalid parameter for '--%s' option (not %s)"
+		msg(fs % (opt.__dict__[key],opt.replace("_","-"),m))
 		sys.exit(1)
 
 def init(opts_data,add_opts=[]):
@@ -67,39 +71,55 @@ def init(opts_data,add_opts=[]):
 	if len(sys.argv) == 2 and sys.argv[1] == '--version':
 		print_version_info(); sys.exit()
 
-	opts,args,short_opts,long_opts = mmgen.share.Opts.parse_opts(sys.argv,opts_data)
+	uopts,args,short_opts,long_opts = \
+		mmgen.share.Opts.parse_opts(sys.argv,opts_data)
 
 	if g.debug:
-		print "short opts: %s" % repr(short_opts)
-		print "long opts:  %s" % repr(long_opts)
-		print "user-selected opts: %s" % repr(opts)
-		print "cmd args:           %s" % repr(args)
+		d = (
+			("short opts",         short_opts),
+			("long opts",          long_opts),
+			("user-selected opts", uopts),
+			("cmd args",           args),
+		)
+		for e in d: Msg("{:<20}: {}".format(*e))
+
+	# Save this for usage()
+	global usage_txt
+	usage_txt = opts_data['usage']
+
+	# We don't need this data anymore
+	del mmgen.share.Opts
+	for k in 'prog_name','desc','usage','options','notes':
+		if k in opts_data: del opts_data[k]
+
+	# Remove all unneeded attributes from opt, our special global namespace
+	for k in dir(opt):
+		if k[:2] == "__": del opt.__dict__[k]
 
-	# check opts without modifying them
-	if not check_opts(opts,long_opts): sys.exit(1)
+	# Transfer uopts into opt, setting required opts to None if not set by user
+	for o in [s.rstrip("=") for s in long_opts] + g.required_opts + add_opts:
+		opt.__dict__[o] = uopts[o] if o in uopts else None
 
-	# If user opt is set, an opt in mmgen.config is set to 'True'
-	for v in g.usr_set_vars:
-		if v in opts:
-			g.__dict__[g.usr_set_vars[v]] = True
+	# check user-set opts without modifying them
+	if not check_opts(uopts): sys.exit(1)
+
+	# A special case - do this here, before opt gets set from g.dfl_vars
+	if opt.usr_randchars: g.use_urandchars = True
 
 	# If user opt is unset, set it to default value in mmgen.config (g):
 	# If set, convert its type based on value in mmgen.config
-	for v in g.dfl_vars:
-		if v in opts: typeconvert_from_dfl(opts,v)
-		else: opts[v] = g.__dict__[v]
-
-	if g.debug: print "opts after typeconvert: %s" % opts
+	for k in g.dfl_vars:
+		if k in opt.__dict__ and opt.__dict__[k] != None:
+			typeconvert_from_dfl(k)
+		else: opt.__dict__[k] = g.__dict__[k]
 
-	# A hack, but harmless
-	extra_opts = [
-		"quiet","verbose","debug",
-		"outdir","echo_passphrase","passwd_file"
-	] + add_opts
+	if opt.debug: opt.verbose = True
 
-	# Transfer opts into our custom namespace
-	for o in [s.rstrip("=") for s in long_opts] + extra_opts:
-		opt.__dict__[o] = opts[o] if o in opts else None
+	if g.debug:
+		Msg("opts after typeconvert:")
+		for k in opt.__dict__:
+			if opt.__dict__[k] != None and k != "opts":
+ 				msg("    %-18s: %s" % (k,opt.__dict__[k]))
 
 	for l in (
 	('from_incog_hidden','from_incog','from_seed','from_mnemonic','from_brain'),
@@ -108,25 +128,17 @@ def init(opts_data,add_opts=[]):
 	('quiet','verbose')
 	): warn_incompatible_opts(l)
 
-	del mmgen.share.Opts
 	return args
 
-def show_opts_and_cmd_args(cmd_args):
-	print "Processed options:"
-	d = opt.__dict__
-	for k in d:
-		if k[:2] != "__" and k != "opts" and d[k] != None:
-			msg("%-20s: %s" % (k, d[k]))
-	print "Cmd args: %s" % repr(cmd_args)
-
+# save for debugging
 def show_all_opts():
 	msg("Processed options:")
 	d = opt.__dict__
-	for k in d:
-		if k[:2] != "__" and k != "opts":
-			msg("%-20s: %s" % (k, d[k]))
+	for k in [o for o in d if o != "opts"]:
+		tstr = type(d[k]) if d[k] not in (None,False,True) else ""
+		msg("%-20s: %-8s %s" % (k, d[k], tstr))
 
-def check_opts(opts,long_opts):       # Returns false if any check fails
+def check_opts(usr_opts):       # Returns false if any check fails
 
 	def opt_splits(val,sep,n,what):
 		sepword = "comma" if sep == "," else (
@@ -163,21 +175,22 @@ def check_opts(opts,long_opts):       # Returns false if any check fails
 			return False
 		return True
 
-	for opt,val in opts.items():
+	global opt
+	for key,val in [(k,getattr(opt,k)) for k in usr_opts]:
 
-		what = "parameter for '--%s' option" % opt.replace("_","-")
+		what = "parameter for '--%s' option" % key.replace("_","-")
 
 		# Check for file existence and readability
-		if opt in ('keys_from_file','mmgen_keys_from_file',
+		if key in ('keys_from_file','mmgen_keys_from_file',
 				'passwd_file','keysforaddrs','comment_file'):
 			from mmgen.util import check_infile
 			check_infile(val)  # exits on error
 			continue
 
-		if opt == 'outdir':
+		if key == 'outdir':
 			from mmgen.util import check_outdir
 			check_outdir(val)  # exits on error
-		elif opt == 'label':
+		elif key == 'label':
 			if not opt_compares(len(val),"<=",g.max_wallet_label_len,"label length"):
 				return False
 			try: val.decode("ascii")
@@ -187,8 +200,8 @@ def check_opts(opts,long_opts):       # Returns false if any check fails
 			w = "character in label"
 			for ch in list(val):
 				if not opt_is_in_list(ch,g.wallet_label_symbols,w): return False
-		elif opt == 'export_incog_hidden' or opt == 'from_incog_hidden':
-			if opt == 'from_incog_hidden':
+		elif key == 'export_incog_hidden' or key == 'from_incog_hidden':
+			if key == 'from_incog_hidden':
 				if not opt_splits(val,",",3,what): return False
 				infile,offset,seed_len = val.split(",")
 				from mmgen.util import check_infile
@@ -204,7 +217,7 @@ def check_opts(opts,long_opts):       # Returns false if any check fails
 			w = "offset " + what
 			if not opt_is_int(offset,w): return False
 			if not opt_compares(offset,">=",0,what): return False
-		elif opt == 'from_brain':
+		elif key == 'from_brain':
 			if not opt_splits(val,",",2,what): return False
 			l,p = val.split(",")
 			w = "seed length " + what
@@ -212,16 +225,16 @@ def check_opts(opts,long_opts):       # Returns false if any check fails
 			if not opt_is_in_list(int(l),g.seed_lens,w): return False
 			w = "hash preset " + what
 			if not opt_is_in_list(p,g.hash_presets.keys(),w): return False
-		elif opt == 'seed_len':
+		elif key == 'seed_len':
 			if not opt_is_int(val,what): return False
 			if not opt_is_in_list(int(val),g.seed_lens,what): return False
-		elif opt == 'hash_preset':
+		elif key == 'hash_preset':
 			if not opt_is_in_list(val,g.hash_presets.keys(),what): return False
-		elif opt == 'usr_randchars':
+		elif key == 'usr_randchars':
 			if not opt_is_int(val,what): return False
 			if not opt_compares(val,">=",g.min_urandchars,what): return False
 			if not opt_compares(val,"<=",g.max_urandchars,what): return False
 		else:
-			if 'debug' in opts: print "check_opts(): No test for opt '%s'" % opt
+			if g.debug: Msg("check_opts(): No test for opt '%s'" % key)
 
 	return True

+ 1 - 1
mmgen/term.py

@@ -242,4 +242,4 @@ def do_pager(text):
 			p.communicate(text+end+"\n")
 			msg_r("\r")
 			break
-	else: print text+end
+	else: Msg(text+end)

+ 31 - 31
mmgen/tool.py

@@ -153,8 +153,8 @@ cmd_help = """
 """.format(pnm=g.proj_name)
 
 def tool_usage(prog_name, command):
-	print "USAGE: '%s %s%s'" % (prog_name, command,
-		(" "+" ".join(cmd_data[command]) if cmd_data[command] else ""))
+	Msg("USAGE: '%s %s%s'" % (prog_name, command,
+		(" "+" ".join(cmd_data[command]) if cmd_data[command] else "")))
 
 def process_args(prog_name, command, cmd_args):
 	c_args = [[i.split(" [")[0],i.split(" [")[1][:-1]]
@@ -182,15 +182,15 @@ def process_args(prog_name, command, cmd_args):
 #	print c_args; print c_kwargs; print u_args; print u_kwargs; sys.exit()
 
 	if set(u_kwargs) > set(c_kwargs):
-		print "Invalid named argument"
+		Msg("Invalid named argument")
 		sys.exit(1)
 
 	def convert_type(arg,arg_name,arg_type):
 		try:
 			return __builtins__[arg_type](arg)
 		except:
-			print "'%s': Invalid argument for argument %s ('%s' required)" % \
-				(arg, arg_name, arg_type)
+			Msg("'%s': Invalid argument for argument %s ('%s' required)" % \
+				(arg, arg_name, arg_type))
 			sys.exit(1)
 
 	def convert_to_bool_maybe(arg, arg_type):
@@ -244,8 +244,8 @@ def usage(cmd):
 	tool_usage(g.prog_name, cmd)
 
 def hexdump(infile, cols=8, line_nums=True):
-	print pretty_hexdump(get_data_from_file(infile,dash=True,silent=True),
-			cols=cols, line_nums=line_nums)
+	Msg(pretty_hexdump(get_data_from_file(infile,dash=True,silent=True),
+			cols=cols, line_nums=line_nums))
 
 def unhexdump(infile):
 	sys.stdout.write(decode_pretty_hexdump(
@@ -281,7 +281,7 @@ def b58randenc():
 	print_convert_results(r,enc,dec,"str")
 
 def randhex(nbytes='32'):
-	print ba.hexlify(get_random(int(nbytes)))
+	Msg(ba.hexlify(get_random(int(nbytes))))
 
 def randwif(compressed=False):
 	r_hex = ba.hexlify(get_random(32))
@@ -314,22 +314,22 @@ def mn_rand256(wordlist="electrum"): do_random_mn(32,wordlist)
 def hex2mn(s,wordlist="electrum"):
 	import mmgen.mnemonic
 	wl = get_wordlist(wordlist)
-	print " ".join(get_mnemonic_from_seed(ba.unhexlify(s), wl, wordlist))
+	Msg(" ".join(get_mnemonic_from_seed(ba.unhexlify(s), wl, wordlist)))
 
 def mn2hex(s,wordlist="electrum"):
 	import mmgen.mnemonic
 	wl = get_wordlist(wordlist)
-	print ba.hexlify(get_seed_from_mnemonic(s.split(),wl,True))
+	Msg(ba.hexlify(get_seed_from_mnemonic(s.split(),wl,True)))
 
 def b32tohex(s):
 	b32a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
 	import mmgen.mnemonic
-	print baseNtohex(32,s,b32a)
+	Msg(baseNtohex(32,s,b32a))
 
 def hextob32(s):
 	b32a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
 	import mmgen.mnemonic
-	print "".join(hextobaseN(32,s,b32a))
+	Msg("".join(hextobaseN(32,s,b32a)))
 
 def mn_stats(wordlist="electrum"):
 	l = get_wordlist(wordlist)
@@ -337,11 +337,11 @@ def mn_stats(wordlist="electrum"):
 
 def mn_printlist(wordlist="electrum"):
 	wl = get_wordlist(wordlist)
-	print "\n".join(wl)
+	Msg("\n".join(wl))
 
-def id8(infile): print make_chksum_8(get_data_from_file(infile,dash=True,silent=True))
-def id6(infile): print make_chksum_6(get_data_from_file(infile,dash=True,silent=True))
-def str2id6(s):  print make_chksum_6("".join(s.split()))
+def id8(infile): Msg(make_chksum_8(get_data_from_file(infile,dash=True,silent=True)))
+def id6(infile): Msg(make_chksum_6(get_data_from_file(infile,dash=True,silent=True)))
+def str2id6(s):  Msg(make_chksum_6("".join(s.split())))
 
 # List MMGen addresses and their balances:
 def listaddresses(minconf=1,showempty=False,pager=False):
@@ -391,7 +391,7 @@ def listaddresses(minconf=1,showempty=False,pager=False):
 
 	o = "\n".join(out)
 	if pager: do_pager(o)
-	else: print o
+	else: Msg(o)
 
 
 def getbalance(minconf=1):
@@ -413,10 +413,10 @@ def getbalance(minconf=1):
 
 	fs = "{:12}  {:<%s} {:<%s} {:<}" % (16,16)
 	mc,lbl = str(minconf),"confirms"
-	print fs.format("Wallet","Unconfirmed",
-			"<%s %s"%(mc,lbl),">=%s %s"%(mc,lbl))
+	Msg(fs.format("Wallet","Unconfirmed","<%s %s"%(mc,lbl),">=%s %s"%(mc,lbl)))
 	for key in sorted(accts.keys()):
-		print fs.format(key+":", *[str(trim_exponent(a))+" BTC" for a in accts[key]])
+		Msg(fs.format(key+":", *[str(trim_exponent(a))+" BTC"
+				for a in accts[key]]))
 
 def txview(infile,pager=False,terse=False):
 	c = connect_to_bitcoind()
@@ -434,38 +434,38 @@ def keyaddrfile_chksum(infile):
 	AddrInfo(infile,has_keys=True)
 
 def hexreverse(hex_str):
-	print ba.hexlify(decode_pretty_hexdump(hex_str)[::-1])
+	Msg(ba.hexlify(decode_pretty_hexdump(hex_str)[::-1]))
 
 def hexlify(s):
-	print ba.hexlify(s)
+	Msg(ba.hexlify(s))
 
 def sha256x2(s, file_input=False, hex_input=False):
 	from hashlib import sha256
 	if file_input:  b = get_data_from_file(s)
 	elif hex_input: b = decode_pretty_hexdump(s)
 	else:           b = s
-	print sha256(sha256(b).digest()).hexdigest()
+	Msg(sha256(sha256(b).digest()).hexdigest())
 
 def hexaddr2addr(hexaddr):
-	print bitcoin.hexaddr2addr(hexaddr)
+	Msg(bitcoin.hexaddr2addr(hexaddr))
 
 def addr2hexaddr(addr):
-	print bitcoin.verify_addr(addr,return_hex=True)
+	Msg(bitcoin.verify_addr(addr,return_hex=True))
 
 def pubkey2hexaddr(pubkeyhex):
-	print bitcoin.pubhex2hexaddr(pubkeyhex)
+	Msg(bitcoin.pubhex2hexaddr(pubkeyhex))
 
 def pubkey2addr(pubkeyhex):
-	print bitcoin.hexaddr2addr(bitcoin.pubhex2hexaddr(pubkeyhex))
+	Msg(bitcoin.hexaddr2addr(bitcoin.pubhex2hexaddr(pubkeyhex)))
 
 def privhex2addr(privkeyhex,compressed=False):
-	print bitcoin.privnum2addr(int(privkeyhex,16),compressed)
+	Msg(bitcoin.privnum2addr(int(privkeyhex,16),compressed))
 
 def wif2hex(wif,compressed=False):
-	print bitcoin.wiftohex(wif,compressed)
+	Msg(bitcoin.wiftohex(wif,compressed))
 
 def hex2wif(hexpriv,compressed=False):
-	print bitcoin.hextowif(hexpriv,compressed)
+	Msg(bitcoin.hextowif(hexpriv,compressed))
 
 
 def encrypt(infile,outfile="",hash_preset=""):
@@ -603,4 +603,4 @@ def rand2file(outfile, nbytes, threads=4, silent=False):
 	q2.join()
 	f.close()
 
-def bytespec(s): print parse_nbytes(s)
+def bytespec(s): Msg(parse_nbytes(s))

+ 1 - 1
mmgen/tx.py

@@ -47,7 +47,7 @@ def normalize_btc_amt(amt):
 		return False
 
 	if opt.debug:
-		print "Decimal(amt): %s\nAs tuple: %s" % (amt,repr(ret.as_tuple()))
+		Msg("Decimal(amt): %s\nAs tuple: %s" % (amt,repr(ret.as_tuple())))
 
 	if ret.as_tuple()[-1] < -8:
 		msg("%s: Too many decimal places in amount" % amt)

+ 10 - 10
mmgen/util.py

@@ -178,9 +178,9 @@ def compare_checksums(chksum1, desc1, chksum2, desc2):
 		return True
 	else:
 		if opt.debug:
-			print \
-	"ERROR!\nComputed checksum %s (%s) doesn't match checksum %s (%s)" \
-			% (desc1,chksum1,desc2,chksum2)
+			Msg(
+	"ERROR: Computed checksum %s (%s) doesn't match checksum %s (%s)"
+			% (desc1,chksum1,desc2,chksum2))
 		return False
 
 def get_default_wordlist():
@@ -289,7 +289,7 @@ def get_new_passphrase(what,  passchg=False):
 		for i in range(g.passwd_max_tries):
 			pw = " ".join(_get_words_from_user("Enter {}: ".format(w)))
 			pw2 = " ".join(_get_words_from_user("Repeat passphrase: "))
-			if opt.debug: print "Passphrases: [%s] [%s]" % (pw,pw2)
+			if opt.debug: Msg("Passphrases: [%s] [%s]" % (pw,pw2))
 			if pw == pw2:
 				vmsg("Passphrases match"); break
 			else: msg("Passphrases do not match.  Try again.")
@@ -378,7 +378,7 @@ def write_to_file_or_stdout(outfile, data,  what="data"):
 from mmgen.bitcoin import b58decode_pad,b58encode_pad
 
 def display_control_data(label,metadata,hash_preset,salt,enc_seed):
-	print "WALLET DATA"
+	Msg("WALLET DATA")
 	fs = "  {:18} {}"
 	pw_empty = "yes" if metadata[3] == "E" else "no"
 	for i in (
@@ -391,7 +391,7 @@ def display_control_data(label,metadata,hash_preset,salt,enc_seed):
 				" ".join([str(i) for i in get_hash_params(hash_preset)]))),
 		("Passphrase empty?", pw_empty.capitalize()),
 		("Timestamp:",           "%s UTC" % metadata[4]),
-	): print fs.format(*i)
+	): Msg(fs.format(*i))
 
 	fs = "  {:6} {}"
 	for i in (
@@ -401,7 +401,7 @@ def display_control_data(label,metadata,hash_preset,salt,enc_seed):
 		("Encrypted seed:", ""),
 		("  b58:",      b58encode_pad(enc_seed)),
 		("  hex:",      hexlify(enc_seed))
-	): print fs.format(*i)
+	): Msg(fs.format(*i))
 
 
 def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed):
@@ -480,7 +480,7 @@ def _check_chksum_6(chk,val,desc,infile):
 		msg("Checksum: %s. Computed value: %s" % (chk,comp_chk))
 		sys.exit(2)
 	elif opt.debug:
-		print "%s checksum passed: %s" % (desc.capitalize(),chk)
+		Msg("%s checksum passed: %s" % (desc.capitalize(),chk))
 
 
 def get_data_from_wallet(infile,silent=False):
@@ -530,7 +530,7 @@ def get_data_from_wallet(infile,silent=False):
 def _get_words_from_user(prompt):
 	# split() also strips
 	words = my_raw_input(prompt, echo=opt.echo_passphrase).split()
-	if opt.debug: print "Sanitized input: [%s]" % " ".join(words)
+	if opt.debug: Msg("Sanitized input: [%s]" % " ".join(words))
 	return words
 
 
@@ -540,7 +540,7 @@ def _get_words_from_file(infile,what):
 	# split() also strips
 	words = f.read().split()
 	f.close()
-	if opt.debug: print "Sanitized input: [%s]" % " ".join(words)
+	if opt.debug: Msg("Sanitized input: [%s]" % " ".join(words))
 	return words
 
 

+ 22 - 18
test/test.py

@@ -155,8 +155,8 @@ cmd_data = OrderedDict([
 	['keyaddrgen',    (1,'key-address file generation', [[["mmdat"],1]])],
 	['txsign_keyaddr',(1,'transaction signing with key-address file', [[["akeys.mmenc","raw"],1]])],
 
-	['walletgen2',(2,'wallet generation (2)',     [])],
-#	['walletgen2',(2,'wallet generation (2), 128-bit seed (WIP)',     [])],
+#	['walletgen2',(2,'wallet generation (2)',     [])],
+	['walletgen2',(2,'wallet generation (2), 128-bit seed',     [])],
 	['addrgen2',  (2,'address generation (2)',    [[["mmdat"],2]])],
 	['txcreate2', (2,'transaction creation (2)',  [[["addrs"],2]])],
 	['txsign2',   (2,'transaction signing, two transactions',[[["mmdat","raw"],1],[["mmdat","raw"],2]])],
@@ -215,18 +215,18 @@ opts_data = {
 	'desc': "Test suite for the MMGen suite",
 	'usage':"[options] [command or metacommand]",
 	'options': """
--h, --help         Print this help message
--b, --buf-keypress Use buffered keypresses as with real human input
--d, --debug        Produce debugging output
--D, --direct-exec  Bypass pexpect and execute a command directly (for
-                   debugging only)
--e, --exact-output Show the exact output of the MMGen script(s) being run
--l, --list-cmds    List and describe the tests and commands in the test suite
--p, --pause        Pause between tests, resuming on keypress
--q, --quiet        Produce minimal output.  Suppress dependency info
--s, --system       Test scripts and modules installed on system rather than
-                   those in the repo root
--v, --verbose      Produce more verbose output
+-h, --help          Print this help message
+-b, --buf-keypress  Use buffered keypresses as with real human input
+-d, --debug-scripts Turn on debugging output in executed scripts
+-D, --direct-exec   Bypass pexpect and execute a command directly (for
+                    debugging only)
+-e, --exact-output  Show the exact output of the MMGen script(s) being run
+-l, --list-cmds     List and describe the tests and commands in the test suite
+-p, --pause         Pause between tests, resuming on keypress
+-q, --quiet         Produce minimal output.  Suppress dependency info
+-s, --system        Test scripts and modules installed on system rather than
+                    those in the repo root
+-v, --verbose       Produce more verbose output
 """,
 	'notes': """
 
@@ -238,6 +238,8 @@ cmd_args = opt.opts.init(opts_data)
 
 if opt.system: sys.path.pop(0)
 
+if opt.debug_scripts: os.environ["MMGEN_DEBUG"] = "1"
+
 if opt.buf_keypress:
 	send_delay = 0.3
 else:
@@ -651,9 +653,10 @@ class MMGenTestSuite(object):
 	def generate_cmd_deps(self,fdeps):
 		return [cfgs[str(n)]['dep_generators'][ext] for n,ext in fdeps]
 
-	def walletgen(self,name,brain=False):
+	def walletgen(self,name,brain=False,seed_len=None):
 
 		args = ["-d",cfg['tmpdir'],"-p1","-r10"]
+		if seed_len: args += ["-l",str(seed_len)]
 #        if 'seed_len' in cfg: args += ["-l",cfg['seed_len']]
 		if brain:
 			bwf = os.path.join(cfg['tmpdir'],cfg['bw_filename'])
@@ -951,7 +954,7 @@ class MMGenTestSuite(object):
 		ok()
 
 	def walletgen2(self,name):
-		self.walletgen(name)
+		self.walletgen(name,seed_len=128)
 
 	def addrgen2(self,name,walletfile):
 		self.addrgen(name,walletfile)
@@ -1111,5 +1114,6 @@ except:
 	raise
 
 t = int(time.time()) - start_time
-msg(green(
-	"All requested tests finished OK, elapsed time: %02i:%02i" % (t/60,t%60)))
+sys.stderr.write(green(
+	"All requested tests finished OK, elapsed time: %02i:%02i\n"
+	% (t/60,t%60)))

+ 7 - 7
test/tooltest.py

@@ -78,12 +78,12 @@ opts_data = {
 	'desc': "Test suite for the 'mmgen-tool' utility",
 	'usage':"[options] [command]",
 	'options': """
--h, --help         Print this help message
--d, --debug        Produce debugging output
--l, --list-cmds    List and describe the tests and commands in the test suite
--s, --system       Test scripts and modules installed on system rather than
-                   those in the repo root
--v, --verbose      Produce more verbose output
+-h, --help          Print this help message
+-d, --debug-scripts Turn on debugging output in executed scripts
+-l, --list-cmds     List and describe the tests and commands in the test suite
+-s, --system        Test scripts and modules installed on system rather than
+                    those in the repo root
+-v, --verbose       Produce more verbose output
 """,
 	'notes': """
 
@@ -95,7 +95,7 @@ cmd_args = opt.opts.init(opts_data,add_opts=["exact_output"])
 
 if opt.system: sys.path.pop(0)
 
-env = os.environ
+if opt.debug_scripts: os.environ["MMGEN_DEBUG"] = "1"
 
 if opt.debug: opt.verbose = True