Browse Source

Minor fixes and improvements
- mmgen-tool listaddresses: add 'show_age','show_days' options
- init_fail(): make 'silent' override 'MMGEN_TRACEBACK', fixing regression
introduced by 3909339
- test/test.py: improve formatting of --list output
- test/{test,objtest,scrambletest}.py, mmgen/tool.py: indentation (whitespace) fixes

MMGen 7 years ago
parent
commit
f7e54cc
8 changed files with 66 additions and 61 deletions
  1. 3 5
      mmgen/main_tool.py
  2. 13 17
      mmgen/obj.py
  3. 25 12
      mmgen/tool.py
  4. 3 3
      mmgen/util.py
  5. 5 3
      scripts/traceback.py
  6. 7 7
      test/objtest.py
  7. 1 1
      test/scrambletest.py
  8. 9 13
      test/test.py

+ 3 - 5
mmgen/main_tool.py

@@ -150,9 +150,7 @@ if Command not in tool.cmd_data:
 	die(1,"'%s': no such command" % Command.lower())
 
 args,kwargs = tool.process_args(Command,cmd_args)
-try:
-	ret = tool.__dict__[Command](*args,**kwargs)
-except Exception as e:
-	die(1,'{}'.format(e))
 
-sys.exit(0 if ret in (None,True) else 1) # some commands die, some return False on failure
+ret = tool.__dict__[Command](*args,**kwargs)
+
+sys.exit((1,0)[ret in (None,True)]) # some commands die, some return False on failure

+ 13 - 17
mmgen/obj.py

@@ -110,17 +110,15 @@ class InitErrors(object):
 		assert on_fail in ('die','return','silent','raise'),'arg_chk in class {}'.format(cls.__name__)
 
 	@staticmethod
-	def init_fail(m,on_fail,silent=False):
+	def init_fail(m,on_fail):
+		if os.getenv('MMGEN_TRACEBACK'): on_fail == 'raise'
 		from mmgen.util import die,msg
-		if silent: m = ''
-		if os.getenv('MMGEN_TRACEBACK'):
-			raise ValueError,m
-		elif on_fail == 'die': die(1,m)
+		if   on_fail == 'silent': return None # TODO: return False instead?
+		elif on_fail == 'raise':  raise ValueError,m
+		elif on_fail == 'die':    die(1,m)
 		elif on_fail == 'return':
 			if m: msg(m)
-			return None # TODO: change to False
-		elif on_fail == 'silent': return None # same here
-		elif on_fail == 'raise':  raise ValueError,m
+			return None                       # TODO: here too?
 
 class Hilite(object):
 
@@ -134,11 +132,11 @@ class Hilite(object):
 				center=False,nullrepl='',app='',appcolor=False):
 		if width == None: width = cls.width
 		if trunc_ok == None: trunc_ok = cls.trunc_ok
-		assert width > 0
+		assert width > 0,'Width must be > 0'
 		if s == '' and nullrepl:
 			s,center = nullrepl,True
 		if center: s = s.center(width)
-		assert type(encl) is str and len(encl) in (0,2)
+		assert type(encl) is str and len(encl) in (0,2),'type(encl) must be str and len(encl) be in (0,2)'
 		a,b = list(encl) if encl else ('','')
 		if trunc_ok and len(s) > width: s = s[:width]
 		if app:
@@ -310,9 +308,9 @@ class BTCAmt(Decimal,Hilite,InitErrors):
 		raise NotImplementedError
 
 	def fmt(self,fs='3.8',color=False,suf=''):
-		s = self.__str__(color=False)
+		s = str(int(self)) if int(self) == self else self.normalize().__format__('f')
 		if '.' in fs:
-			p1,p2 = [int(i) for i in fs.split('.',1)]
+			p1,p2 = map(int,fs.split('.',1))
 			ss = s.split('.',1)
 			if len(ss) == 2:
 				a,b = ss
@@ -327,11 +325,9 @@ class BTCAmt(Decimal,Hilite,InitErrors):
 		return self.__str__(color=color)
 
 	def __str__(self,color=False): # format simply, no exponential notation
-		if int(self) == self:
-			ret = str(int(self))
-		else:
-			ret = self.normalize().__format__('f')
-		return self.colorize(ret,color=color)
+		return self.colorize(
+			str(int(self)) if int(self) == self else self.normalize().__format__('f'),
+			color=color)
 
 	def __repr__(self):
 		return "{}('{}')".format(type(self).__name__,self.__str__())

+ 25 - 12
mmgen/tool.py

@@ -77,8 +77,8 @@ cmd_data = OrderedDict([
 	('Mn_stats',     ["wordlist [str='electrum']"]),
 	('Mn_printlist', ["wordlist [str='electrum']"]),
 
-	('Listaddress',['<{} address> [str]'.format(pnm),'minconf [int=1]','pager [bool=False]','showempty [bool=True]''showbtcaddr [bool=True]']),
-	('Listaddresses',["addrs [str='']",'minconf [int=1]','showempty [bool=False]','pager [bool=False]','showbtcaddrs [bool=True]','all_labels [bool=False]',"sort [str=''] (options: reverse, age)"]),
+	('Listaddress',['<{} address> [str]'.format(pnm),'minconf [int=1]','pager [bool=False]','showempty [bool=True]','showbtcaddr [bool=True]','show_age [bool=False]','show_days [bool=True]']),
+	('Listaddresses',["addrs [str='']",'minconf [int=1]','showempty [bool=False]','pager [bool=False]','showbtcaddrs [bool=True]','all_labels [bool=False]',"sort [str=''] (options: reverse, age)",'show_age [bool=False]','show_days [bool=True]']),
 	('Getbalance',   ['minconf [int=1]','quiet [bool=False]']),
 	('Txview',       ['<{} TX file(s)> [str]'.format(pnm),'pager [bool=False]','terse [bool=False]',"sort [str='mtime'] (options: ctime, atime)",'MARGS']),
 	('Twview',       ["sort [str='age']",'reverse [bool=False]','show_days [bool=True]','show_mmid [bool=True]','minconf [int=1]','wide [bool=False]','pager [bool=False]']),
@@ -625,11 +625,16 @@ def monero_wallet_ops(infile,op,blockheight=None,addrs=None):
 
 # ================ RPC commands ================== #
 
-def Listaddress(addr,minconf=1,pager=False,showempty=True,showbtcaddr=True):
-	return Listaddresses(addrs=addr,minconf=minconf,pager=pager,showempty=showempty,showbtcaddrs=showbtcaddr)
+def Listaddress(addr,minconf=1,pager=False,showempty=True,showbtcaddr=True,show_age=False,show_days=None):
+	return Listaddresses(addrs=addr,minconf=minconf,pager=pager,
+			showempty=showempty,showbtcaddrs=showbtcaddr,show_age=show_age,show_days=show_days)
 
 # List MMGen addresses and their balances.  TODO: move this code to AddrList
-def Listaddresses(addrs='',minconf=1,showempty=False,pager=False,showbtcaddrs=True,all_labels=False,sort=None):
+def Listaddresses(addrs='',minconf=1,
+	showempty=False,pager=False,showbtcaddrs=True,all_labels=False,sort=None,show_age=False,show_days=None):
+
+	if show_days == None: show_days = False # user-set show_days triggers show_age
+	else: show_age = True
 
 	if sort:
 		sort = set(sort.split(','))
@@ -716,15 +721,19 @@ def Listaddresses(addrs='',minconf=1,showempty=False,pager=False,showbtcaddrs=Tr
 
 	out = ([],[green('Chain: {}'.format(g.chain.upper()))])[g.chain in ('testnet','regtest')]
 
-	fs = ('{mid} {cmt} {amt}','{mid} {addr} {cmt} {amt}')[showbtcaddrs]
+	fs = '{{mid}}{} {{cmt}} {{amt}}{}'.format(('',' {addr}')[showbtcaddrs],('',' {age}')[show_age])
 	mmaddrs = [k for k in addrs.keys() if k.type == 'mmgen']
 	max_mmid_len = max(len(k) for k in mmaddrs) + 2 if mmaddrs else 10
-	max_cmt_len =  max(max(len(addrs[k]['lbl'].comment) for k in addrs),7)
+	max_cmt_len  = max(max(len(v['lbl'].comment) for v in addrs.values()),7)
+#	pmsg([a.split('.')[1] for a in [str(v['amt']) for v in addrs.values()] if '.' in a])
+	# fp: fractional part
+	max_fp_len = max([len(a.split('.')[1]) for a in [str(v['amt']) for v in addrs.values()] if '.' in a] or [1])
 	out += [fs.format(
 			mid=MMGenID.fmtc('MMGenID',width=max_mmid_len),
 			addr=CoinAddr.fmtc('ADDRESS'),
 			cmt=TwComment.fmtc('COMMENT',width=max_cmt_len),
-			amt='BALANCE'
+			amt='{:{w}}'.format('BALANCE',w=max_fp_len+4),
+			age=('CONFS','AGE')[show_days],
 			)]
 
 	def sort_algo(j):
@@ -737,6 +746,7 @@ def Listaddresses(addrs='',minconf=1,showempty=False,pager=False,showbtcaddrs=Tr
 			return j.sort_key
 
 	al_id_save = None
+	confs_per_day = 60*60*24 / g.proto.secs_per_block
 	for mmid in sorted(addrs,key=sort_algo,reverse=bool(sort and 'reverse' in sort)):
 		if mmid.type == 'mmgen':
 			if al_id_save and al_id_save != mmid.obj.al_id:
@@ -748,11 +758,14 @@ def Listaddresses(addrs='',minconf=1,showempty=False,pager=False,showbtcaddrs=Tr
 				out.append('')
 				al_id_save = None
 			mmid_disp = 'Non-MMGen'
+		e = addrs[mmid]
 		out.append(fs.format(
-			mid = MMGenID.fmtc(mmid_disp,width=max_mmid_len,color=True),
-			addr=(addrs[mmid]['addr'].fmt(color=True) if showbtcaddrs else None),
-			cmt=addrs[mmid]['lbl'].comment.fmt(width=max_cmt_len,color=True,nullrepl='-'),
-			amt=addrs[mmid]['amt'].fmt('3.0',color=True)))
+			mid=MMGenID.fmtc(mmid_disp,width=max_mmid_len,color=True),
+			addr=(e['addr'].fmt(color=True) if showbtcaddrs else None),
+			cmt=e['lbl'].comment.fmt(width=max_cmt_len,color=True,nullrepl='-'),
+			amt=e['amt'].fmt('3.{}'.format(max_fp_len),color=True),
+			age=mmid.confs / (1,confs_per_day)[show_days] if hasattr(mmid,'confs') else '-'
+			))
 	out.append('\nTOTAL: {} {}'.format(total.hl(color=True),g.coin))
 	o = '\n'.join(out)
 	return do_pager(o) if pager else Msg(o)

+ 3 - 3
mmgen/util.py

@@ -860,13 +860,13 @@ def rpc_init(reinit=False):
 	g.rpch = conn
 	return conn
 
-def format_text(s,indent=0,width=80):
+def format_par(s,indent=0,width=80,as_list=False):
 	words,lines = s.split(),[]
 	assert width >= indent + 4,'width must be >= indent + 4'
 	while words:
 		line = ''
 		while len(line) <= (width-indent) and words:
-			if len(line) + len(words[0]) + 1 > width-indent: break
+			if line and len(line) + len(words[0]) + 1 > width-indent: break
 			line += ('',' ')[bool(line)] + words.pop(0)
 		lines.append(' '*indent + line)
-	return '\n'.join(lines) + '\n'
+	return lines if as_list else '\n'.join(lines) + '\n'

+ 5 - 3
scripts/traceback.py

@@ -5,12 +5,14 @@ sys.path.insert(0,'.')
 if 'TMUX' in os.environ: del os.environ['TMUX']
 os.environ['MMGEN_TRACEBACK'] = '1'
 
-f = open('my.err','w')
+tb_source = open(sys.argv[1])
+tb_file = open('my.err','w')
 
 try:
 	sys.argv.pop(0)
-	execfile(sys.argv[0])
+	exec tb_source
 except SystemExit:
+#	pass
 	e = sys.exc_info()
 	sys.exit(int(str(e[1])))
 except:
@@ -19,5 +21,5 @@ except:
 	def red(s):    return '{e}[31;1m{}{e}[0m'.format(s,e='\033')
 	def yellow(s): return '{e}[33;1m{}{e}[0m'.format(s,e='\033')
 	sys.stdout.write('{}{}'.format(yellow(''.join(l)),red(exc)))
-	traceback.print_exc(file=f)
+	traceback.print_exc(file=tb_file)
 	sys.exit(1)

+ 7 - 7
test/objtest.py

@@ -193,19 +193,19 @@ tests = OrderedDict([
 		'bad':  ({'wif':1},),
 		'good': ({
 			'btc': (({'wif':'5KXEpVzjWreTcQoG5hX357s1969MUKNLuSfcszF6yu84kpsNZKb',
-					 'ret':'e0aef965b905a2fedf907151df8e0a6bac832aa697801c51f58bd2ecb4fd381c'},
+					'ret':'e0aef965b905a2fedf907151df8e0a6bac832aa697801c51f58bd2ecb4fd381c'},
 					{'wif':'KwWr9rDh8KK5TtDa3HLChEvQXNYcUXpwhRFUPc5uSNnMtqNKLFhk',
-					 'ret':'08d0ed83b64b68d56fa064be48e2385060ed205be2b1e63cd56d218038c3a05f'}),
+					'ret':'08d0ed83b64b68d56fa064be48e2385060ed205be2b1e63cd56d218038c3a05f'}),
 					({'wif':'93HsQEpH75ibaUJYi3QwwiQxnkW4dUuYFPXZxcbcKds7XrqHkY6',
-					 'ret':'e0aef965b905a2fedf907151df8e0a6bac832aa697801c51f58bd2ecb4fd381c'},
+					'ret':'e0aef965b905a2fedf907151df8e0a6bac832aa697801c51f58bd2ecb4fd381c'},
 					{'wif':'cMsqcmDYZP1LdKgqRh9L4ZRU9br28yvdmTPwW2YQwVSN9aQiMAoR',
 					'ret':'08d0ed83b64b68d56fa064be48e2385060ed205be2b1e63cd56d218038c3a05f'})),
 			'ltc': (({'wif':'6ufJhtQQiRYA3w2QvDuXNXuLgPFp15i3HR1Wp8An2mx1JnhhJAh',
-					 'ret':'470a974ffca9fca1299b706b09142077bea3acbab6d6480b87dbba79d5fd279b'},
+					'ret':'470a974ffca9fca1299b706b09142077bea3acbab6d6480b87dbba79d5fd279b'},
 					{'wif':'T41Fm7J3mtZLKYPMCLVSFARz4QF8nvSDhLAfW97Ds56Zm9hRJgn8',
-					 'ret':'1c6feab55a4c3b4ad1823d4ecacd1565c64228c01828cf44fb4db1e2d82c3d56'}),
+					'ret':'1c6feab55a4c3b4ad1823d4ecacd1565c64228c01828cf44fb4db1e2d82c3d56'}),
 					({'wif':'92iqzh6NqiKawyB1ronw66YtEHrU4rxRJ5T4aHniZqvuSVZS21f',
-					 'ret':'95b2aa7912550eacdd3844dcc14bee08ce7bc2434ad4858beb136021e945afeb'},
+					'ret':'95b2aa7912550eacdd3844dcc14bee08ce7bc2434ad4858beb136021e945afeb'},
 					{'wif':'cSaJAXBAm9ooHpVJgoxqjDG3AcareFy29Cz8mhnNTRijjv2HLgta',
 					'ret':'94fa8b90c11fea8fb907c9376b919534b0a75b9a9621edf71a78753544b4101c'})),
 				}[g.coin.lower()][bool(g.testnet)],
@@ -234,7 +234,7 @@ tests = OrderedDict([
 		'bad': ('This text is too long for a transaction comment. '*2,),
 		'good':  (u'UTF-8 is OK: я','a good comment',)
 	}),
-	('MMGenPWIDString', { #	forbidden = list(u' :/\\')
+	('MMGenPWIDString', { # forbidden = list(u' :/\\')
 		'bad': ('foo/','foo:','foo:\\'),
 		'good':  (u'qwerty@яяя',)
 	}),

+ 1 - 1
test/scrambletest.py

@@ -106,5 +106,5 @@ start_time = int(time.time())
 run_tests()
 
 t = int(time.time()) - start_time
-m =	'\nAll requested tests finished OK, elapsed time: {:02}:{:02}'
+m = '\nAll requested tests finished OK, elapsed time: {:02}:{:02}'
 msg(green(m.format(t/60,t%60)))

+ 9 - 13
test/test.py

@@ -907,6 +907,7 @@ if opt.list_cmds:
 	from mmgen.term import get_terminal_size
 	tw = get_terminal_size()[0]
 	fs = '  {:<{w}} - {}'
+
 	Msg(green('AVAILABLE COMMANDS:'))
 	w = max([len(i) for i in cmd_data])
 	for cmd in cmd_data:
@@ -916,24 +917,19 @@ if opt.list_cmds:
 			continue
 		Msg('  '+fs.format(cmd,cmd_data[cmd][1],w=w))
 
-	w = max([len(i) for i in meta_cmds])
-	Msg('\n'+green('AVAILABLE METACOMMANDS:'))
-	for cmd in meta_cmds:
-		ft = format_text(' '.join(meta_cmds[cmd]),width=tw,indent=4).lstrip()
-		sep = '\n' if not ft else ' ' if len(ft.splitlines()[0]) + len(cmd) < tw - 4 else '\n    '
-		Msg_r('  {}{}{}'.format(yellow(cmd+':'),sep,ft))
-
-	w = max([len(i) for i in cmd_list])
-	Msg('\n'+green('AVAILABLE COMMAND GROUPS:'))
-	for cmd in cmd_list:
-		ft = format_text(' '.join(cmd_list[cmd]),width=tw,indent=4).lstrip()
-		sep = '\n' if not ft else ' ' if len(ft.splitlines()[0]) + len(cmd) < tw - 4 else '\n    '
-		Msg_r('  {}{}{}'.format(yellow(cmd+':'),sep,ft))
+	for cl,lbl in ((meta_cmds,'METACOMMANDS'),(cmd_list,'COMMAND GROUPS')):
+		w = max([len(i) for i in cl])
+		Msg('\n'+green('AVAILABLE {}:'.format(lbl)))
+		for cmd in cl:
+			ft = format_par(' '.join(cl[cmd]),width=tw,indent=4,as_list=True)
+			sep = '' if not ft else ' ' if len(ft[0]) + len(cmd) < tw - 4 else '\n    '
+			Msg('  {}{}{}'.format(yellow(cmd+':'),sep,'\n'.join(ft).lstrip()))
 
 	Msg('\n'+green('AVAILABLE UTILITIES:'))
 	w = max([len(i) for i in utils])
 	for cmd in sorted(utils):
 		Msg(fs.format(cmd,utils[cmd],w=w))
+
 	sys.exit(0)
 
 NL = ('\r\n','\n')[g.platform=='linux' and bool(opt.popen_spawn)]