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
This commit is contained in:
The MMGen Project 2018-02-17 12:34:15 +03:00
commit f7e54cce93
Signed by: mmgen
GPG key ID: 62DBE9E5212F05BE
8 changed files with 66 additions and 61 deletions

View file

@ -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

View file

@ -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__())

View file

@ -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)

View file

@ -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'

View file

@ -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)

View file

@ -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@яяя',)
}),

View file

@ -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)))

View file

@ -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)]