string formatting, whitespace, minor fixes throughout
This commit is contained in:
parent
1f7cfafd96
commit
5e745f2a08
7 changed files with 155 additions and 113 deletions
67
mmgen/obj.py
67
mmgen/obj.py
|
|
@ -108,13 +108,15 @@ class InitErrors(object):
|
|||
e2_fmt = '({}) '.format(e2.args[0]) if e2 else ''
|
||||
errmsg = fs.format(m,objname or cls.__name__,e2_fmt,e.args[0])
|
||||
|
||||
if m2: errmsg = '{!r}\n{}'.format(m2,errmsg)
|
||||
if m2:
|
||||
errmsg = '{!r}\n{}'.format(m2,errmsg)
|
||||
|
||||
from .util import die,msg
|
||||
if cls.on_fail == 'silent':
|
||||
return None # TODO: return False instead?
|
||||
elif cls.on_fail == 'return':
|
||||
if errmsg: msg(errmsg)
|
||||
if errmsg:
|
||||
msg(errmsg)
|
||||
return None # TODO: return False instead?
|
||||
elif g.traceback or cls.on_fail == 'raise':
|
||||
if hasattr(cls,'exc'):
|
||||
|
|
@ -127,8 +129,9 @@ class InitErrors(object):
|
|||
@classmethod
|
||||
def method_not_implemented(cls):
|
||||
import traceback
|
||||
raise NotImplementedError('method {!r} not implemented for class {!r}'.format(
|
||||
traceback.extract_stack()[-2].name, cls.__name__))
|
||||
raise NotImplementedError(
|
||||
'method {!r} not implemented for class {!r}'.format(
|
||||
traceback.extract_stack()[-2].name, cls.__name__) )
|
||||
|
||||
class Hilite(object):
|
||||
|
||||
|
|
@ -231,8 +234,10 @@ class ImmutableAttr: # Descriptor
|
|||
|
||||
def __init__(self,dtype,typeconv=True,set_none_ok=False,include_proto=False):
|
||||
assert isinstance(dtype,self.ok_dtypes), 'ImmutableAttr_check1'
|
||||
if include_proto: assert typeconv and type(dtype) == str, 'ImmutableAttr_check2'
|
||||
if set_none_ok: assert typeconv and type(dtype) != str, 'ImmutableAttr_check3'
|
||||
if include_proto:
|
||||
assert typeconv and type(dtype) == str, 'ImmutableAttr_check2'
|
||||
if set_none_ok:
|
||||
assert typeconv and type(dtype) != str, 'ImmutableAttr_check3'
|
||||
|
||||
if dtype is None:
|
||||
'use instance-defined conversion function for this attribute'
|
||||
|
|
@ -365,14 +370,16 @@ class AddrIdxList(list,InitErrors,MMGenObject):
|
|||
j = i.split('-')
|
||||
if len(j) == 1:
|
||||
idx = AddrIdx(i,on_fail='raise')
|
||||
if not idx: break
|
||||
if not idx:
|
||||
break
|
||||
ret.append(idx)
|
||||
elif len(j) == 2:
|
||||
beg = AddrIdx(j[0],on_fail='raise')
|
||||
if not beg: break
|
||||
if not beg:
|
||||
break
|
||||
end = AddrIdx(j[1],on_fail='raise')
|
||||
if not beg: break
|
||||
if end < beg: break
|
||||
if not beg or (end < beg):
|
||||
break
|
||||
ret.extend([AddrIdx(x,on_fail='raise') for x in range(beg,end+1)])
|
||||
else: break
|
||||
else:
|
||||
|
|
@ -391,7 +398,8 @@ class MMGenRange(tuple,InitErrors,MMGenObject):
|
|||
try:
|
||||
if len(args) == 1:
|
||||
s = args[0]
|
||||
if type(s) == cls: return s
|
||||
if type(s) == cls:
|
||||
return s
|
||||
assert isinstance(s,str),'not a string or string subclass'
|
||||
ss = s.split('-',1)
|
||||
first = int(ss[0])
|
||||
|
|
@ -442,7 +450,8 @@ class BTCAmt(Decimal,Hilite,InitErrors):
|
|||
|
||||
# NB: 'from_decimal' rounds down to precision of 'min_coin_unit'
|
||||
def __new__(cls,num,from_unit=None,from_decimal=False,on_fail='die'):
|
||||
if type(num) == cls: return num
|
||||
if type(num) == cls:
|
||||
return num
|
||||
cls.arg_chk(on_fail)
|
||||
try:
|
||||
if from_unit:
|
||||
|
|
@ -480,7 +489,8 @@ class BTCAmt(Decimal,Hilite,InitErrors):
|
|||
cls.method_not_implemented()
|
||||
|
||||
def fmt(self,fs=None,color=False,suf='',prec=1000):
|
||||
if fs == None: fs = self.amt_fs
|
||||
if fs == None:
|
||||
fs = self.amt_fs
|
||||
s = str(int(self)) if int(self) == self else self.normalize().__format__('f')
|
||||
if '.' in fs:
|
||||
p1,p2 = list(map(int,fs.split('.',1)))
|
||||
|
|
@ -576,7 +586,8 @@ class SeedID(str,Hilite,InitErrors):
|
|||
width = 8
|
||||
trunc_ok = False
|
||||
def __new__(cls,seed=None,sid=None,on_fail='die'):
|
||||
if type(sid) == cls: return sid
|
||||
if type(sid) == cls:
|
||||
return sid
|
||||
cls.arg_chk(on_fail)
|
||||
try:
|
||||
if seed:
|
||||
|
|
@ -586,7 +597,7 @@ class SeedID(str,Hilite,InitErrors):
|
|||
return str.__new__(cls,make_chksum_8(seed.data))
|
||||
elif sid:
|
||||
assert set(sid) <= set(hexdigits.upper()),'not uppercase hex digits'
|
||||
assert len(sid) == cls.width,'not {} characters wide'.format(cls.width)
|
||||
assert len(sid) == cls.width, f'not {cls.width} characters wide'
|
||||
return str.__new__(cls,sid)
|
||||
raise ValueError('no arguments provided')
|
||||
except Exception as e:
|
||||
|
|
@ -596,7 +607,8 @@ class SubSeedIdx(str,Hilite,InitErrors):
|
|||
color = 'red'
|
||||
trunc_ok = False
|
||||
def __new__(cls,s,on_fail='die'):
|
||||
if type(s) == cls: return s
|
||||
if type(s) == cls:
|
||||
return s
|
||||
cls.arg_chk(on_fail)
|
||||
try:
|
||||
assert isinstance(s,str),'not a string or string subclass'
|
||||
|
|
@ -676,7 +688,7 @@ class TwLabel(str,InitErrors,MMGenObject):
|
|||
ts = text.split(None,1)
|
||||
mmid = TwMMGenID(proto,ts[0],on_fail='raise')
|
||||
comment = TwComment(ts[1] if len(ts) == 2 else '',on_fail='raise')
|
||||
me = str.__new__(cls,'{}{}'.format(mmid,' {}'.format(comment) if comment else ''))
|
||||
me = str.__new__( cls, mmid + (' ' + comment if comment else '') )
|
||||
me.mmid = mmid
|
||||
me.comment = comment
|
||||
me.proto = proto
|
||||
|
|
@ -690,16 +702,18 @@ class HexStr(str,Hilite,InitErrors):
|
|||
hexcase = 'lower'
|
||||
trunc_ok = False
|
||||
def __new__(cls,s,on_fail='die',case=None):
|
||||
if type(s) == cls: return s
|
||||
if type(s) == cls:
|
||||
return s
|
||||
cls.arg_chk(on_fail)
|
||||
if case == None: case = cls.hexcase
|
||||
if case == None:
|
||||
case = cls.hexcase
|
||||
try:
|
||||
assert isinstance(s,str),'not a string or string subclass'
|
||||
assert case in ('upper','lower'),"'{}' incorrect case specifier".format(case)
|
||||
assert set(s) <= set(getattr(hexdigits,case)()),'not {}case hexadecimal symbols'.format(case)
|
||||
assert case in ('upper','lower'), f'{case!r} incorrect case specifier'
|
||||
assert set(s) <= set(getattr(hexdigits,case)()), f'not {case}case hexadecimal symbols'
|
||||
assert not len(s) % 2,'odd-length string'
|
||||
if cls.width:
|
||||
assert len(s) == cls.width,'Value is not {} characters wide'.format(cls.width)
|
||||
assert len(s) == cls.width, f'Value is not {cls.width} characters wide'
|
||||
return str.__new__(cls,s)
|
||||
except Exception as e:
|
||||
return cls.init_fail(e,s)
|
||||
|
|
@ -755,7 +769,8 @@ class PrivKey(str,Hilite,InitErrors,MMGenObject):
|
|||
# initialize with (priv_bin,compressed), WIF or self
|
||||
def __new__(cls,proto,s=None,compressed=None,wif=None,pubkey_type=None,on_fail='die'):
|
||||
|
||||
if type(s) == cls: return s
|
||||
if type(s) == cls:
|
||||
return s
|
||||
cls.arg_chk(on_fail)
|
||||
|
||||
if wif:
|
||||
|
|
@ -821,7 +836,8 @@ class MMGenLabel(str,Hilite,InitErrors):
|
|||
max_screen_width = 0 # if != 0, overrides max_len
|
||||
desc = 'label'
|
||||
def __new__(cls,s,on_fail='die',msg=None):
|
||||
if type(s) == cls: return s
|
||||
if type(s) == cls:
|
||||
return s
|
||||
cls.arg_chk(on_fail)
|
||||
for k in cls.forbidden,cls.allowed:
|
||||
assert type(k) == list
|
||||
|
|
@ -874,7 +890,8 @@ class MMGenPWIDString(MMGenLabel):
|
|||
class SeedSplitSpecifier(str,Hilite,InitErrors,MMGenObject):
|
||||
color = 'red'
|
||||
def __new__(cls,s,on_fail='raise'):
|
||||
if type(s) == cls: return s
|
||||
if type(s) == cls:
|
||||
return s
|
||||
cls.arg_chk(on_fail)
|
||||
try:
|
||||
arr = s.split(':')
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ class CoinProtocol(MMGenObject):
|
|||
return False
|
||||
|
||||
def coin_addr(self,addr):
|
||||
return CoinAddr(proto=self,addr=addr)
|
||||
return CoinAddr( proto=self, addr=addr )
|
||||
|
||||
def addr_type(self,id_str,on_fail='die'):
|
||||
return MMGenAddrType(proto=self,id_str=id_str,on_fail=on_fail)
|
||||
|
|
|
|||
167
mmgen/tw.py
167
mmgen/tw.py
|
|
@ -32,9 +32,12 @@ CUR_HOME,ERASE_ALL = '\033[H','\033[0J'
|
|||
def CUR_RIGHT(n): return '\033[{}C'.format(n)
|
||||
|
||||
def get_tw_label(proto,s):
|
||||
try: return TwLabel(proto,s,on_fail='raise')
|
||||
except BadTwComment: raise
|
||||
except: return None
|
||||
try:
|
||||
return TwLabel(proto,s,on_fail='raise')
|
||||
except BadTwComment:
|
||||
raise
|
||||
except:
|
||||
return None
|
||||
|
||||
_date_formatter = {
|
||||
'days': lambda rpc,secs: (rpc.cur_date - secs) // 86400,
|
||||
|
|
@ -113,13 +116,6 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, add [l]abel:
|
|||
def amt2(self,value):
|
||||
return self.proto.coin_amt(value)
|
||||
|
||||
wmsg = {
|
||||
'no_spendable_outputs': """
|
||||
No spendable outputs found! Import addresses with balances into your
|
||||
watch-only wallet using '{}-addrimport' and then re-run this program.
|
||||
""".strip().format(g.proj_name.lower())
|
||||
}
|
||||
|
||||
async def __ainit__(self,proto,minconf=1,addrs=[]):
|
||||
self.proto = proto
|
||||
self.unspent = self.MMGenTwOutputList()
|
||||
|
|
@ -146,7 +142,7 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
@age_fmt.setter
|
||||
def age_fmt(self,val):
|
||||
if val not in self.age_fmts:
|
||||
raise BadAgeFormat("'{}': invalid age format (must be one of {!r})".format(val,self.age_fmts))
|
||||
raise BadAgeFormat(f'{val!r}: invalid age format (must be one of {self.age_fmts!r})')
|
||||
self._age_fmt = val
|
||||
|
||||
def get_display_precision(self):
|
||||
|
|
@ -176,7 +172,10 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
us_raw = await self.get_unspent_rpc()
|
||||
|
||||
if not us_raw:
|
||||
die(0,self.wmsg['no_spendable_outputs'])
|
||||
die(0,fmt(f"""
|
||||
No spendable outputs found! Import addresses with balances into your
|
||||
watch-only wallet using '{g.proj_name.lower()}-addrimport' and then re-run this program.
|
||||
""").strip())
|
||||
|
||||
lbl_id = ('account','label')['label_api' in self.rpc.caps]
|
||||
|
||||
|
|
@ -214,7 +213,7 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
}
|
||||
key = key or self.sort_key
|
||||
if key not in sort_funcs:
|
||||
die(1,"'{}': invalid sort key. Valid options: {}".format(key,' '.join(sort_funcs.keys())))
|
||||
die(1,f'{key!r}: invalid sort key. Valid options: {" ".join(sort_funcs.keys())}')
|
||||
self.sort_key = key
|
||||
assert type(reverse) == bool
|
||||
self.unspent.sort(key=sort_funcs[key],reverse=reverse or self.reverse)
|
||||
|
|
@ -230,10 +229,11 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
from .term import get_terminal_size
|
||||
while True:
|
||||
self.cols = g.terminal_width or get_terminal_size().width
|
||||
if self.cols >= g.min_screen_width: break
|
||||
m1 = 'Screen too narrow to display the tracking wallet\n'
|
||||
m2 = 'Please resize your screen to at least {} characters and hit ENTER '
|
||||
my_raw_input((m1+m2).format(g.min_screen_width))
|
||||
if self.cols >= g.min_screen_width:
|
||||
break
|
||||
my_raw_input(
|
||||
'Screen too narrow to display the tracking wallet\n'
|
||||
+ f'Please resize your screen to at least {g.min_screen_width} characters and hit ENTER ' )
|
||||
|
||||
def get_display_constants(self):
|
||||
unsp = self.unspent
|
||||
|
|
@ -360,20 +360,29 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
max_lbl_len = max([len(i.label) for i in self.unspent if i.label] or [2])
|
||||
for n,i in enumerate(self.unspent):
|
||||
yield fs.format(
|
||||
n = str(n+1)+')',
|
||||
t = '{},{}'.format('|'+'.'*63 if i.skip == 'txid' and self.group else i.txid,i.vout),
|
||||
n = str(n+1) + ')',
|
||||
t = '{},{}'.format(
|
||||
('|'+'.'*63 if i.skip == 'txid' and self.group else i.txid),
|
||||
i.vout ),
|
||||
a = (
|
||||
'|'+'.' * addr_w if i.skip == 'addr' and self.group else
|
||||
i.addr.fmt(color=color,width=addr_w) ),
|
||||
m = MMGenID.fmtc(i.twmmid if i.twmmid.type=='mmgen' else
|
||||
'Non-{}'.format(g.proj_name),width = mmid_w,color=color),
|
||||
m = MMGenID.fmtc(
|
||||
(i.twmmid if i.twmmid.type == 'mmgen' else f'Non-{g.proj_name}'),
|
||||
width = mmid_w,
|
||||
color = color ),
|
||||
A = i.amt.fmt(color=color),
|
||||
A2 = ( i.amt2.fmt(color=color) if i.amt2 is not None else '' ),
|
||||
c = i.confs,
|
||||
b = self.rpc.blockcount - (i.confs - 1),
|
||||
D = self.age_disp(i,'date_time'),
|
||||
l = i.label.hl(color=color) if i.label else
|
||||
TwComment.fmtc('',color = color,nullrepl='-',width=max_lbl_len) ).rstrip()
|
||||
TwComment.fmtc(
|
||||
s = '',
|
||||
color = color,
|
||||
nullrepl = '-',
|
||||
width = max_lbl_len )
|
||||
).rstrip()
|
||||
|
||||
fs2 = '{} (block #{}, {} UTC)\n{}Sort order: {}\n{}\n\nTotal {}: {}\n'
|
||||
self.fmt_print = fs2.format(
|
||||
|
|
@ -399,11 +408,11 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
def get_idx_from_user(self,action):
|
||||
msg('')
|
||||
while True:
|
||||
ret = my_raw_input('Enter {} number (or RETURN to return to main menu): '.format(self.item_desc))
|
||||
ret = my_raw_input(f'Enter {self.item_desc} number (or RETURN to return to main menu): ')
|
||||
if ret == '': return (None,None) if action == 'a_lbl_add' else None
|
||||
n = AddrIdx(ret,on_fail='silent')
|
||||
if not n or n < 1 or n > len(self.unspent):
|
||||
msg('Choice must be a single number between 1 and {}'.format(len(self.unspent)))
|
||||
msg(f'Choice must be a single number between 1 and {len(self.unspent)}')
|
||||
else:
|
||||
if action == 'a_lbl_add':
|
||||
while True:
|
||||
|
|
@ -411,17 +420,17 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
if s == 'q':
|
||||
return None,None
|
||||
elif s == '':
|
||||
fs = "Removing label for {} #{}. Is this what you want?"
|
||||
if keypress_confirm(fs.format(self.item_desc,n)):
|
||||
if keypress_confirm(
|
||||
f'Removing label for {self.item_desc} #{n}. Is this what you want?'):
|
||||
return n,s
|
||||
elif s:
|
||||
if TwComment(s,on_fail='return'):
|
||||
return n,s
|
||||
else:
|
||||
if action == 'a_addr_delete':
|
||||
fs = "Removing {} #{} from tracking wallet. Is this what you want?"
|
||||
fs = 'Removing {} #{} from tracking wallet. Is this what you want?'
|
||||
elif action == 'a_balance_refresh':
|
||||
fs = "Refreshing tracking wallet {} #{}. Is this what you want?"
|
||||
fs = 'Refreshing tracking wallet {} #{}. Is this what you want?'
|
||||
if keypress_confirm(fs.format(self.item_desc,n)):
|
||||
return n
|
||||
|
||||
|
|
@ -468,7 +477,7 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
e = self.unspent[idx-1]
|
||||
bal = await self.wallet.get_balance(e.addr,force_rpc=True)
|
||||
await self.get_unspent_data()
|
||||
oneshot_msg = yellow('{} balance for account #{} refreshed\n\n'.format(self.proto.dcoin,idx))
|
||||
oneshot_msg = yellow(f'{self.proto.dcoin} balance for account #{idx} refreshed\n\n')
|
||||
self.display_constants = self.get_display_constants()
|
||||
elif action == 'a_lbl_add':
|
||||
idx,lbl = self.get_idx_from_user(action)
|
||||
|
|
@ -476,8 +485,10 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
e = self.unspent[idx-1]
|
||||
if await self.wallet.add_label(e.twmmid,lbl,addr=e.addr):
|
||||
await self.get_unspent_data()
|
||||
a = 'added to' if lbl else 'removed from'
|
||||
oneshot_msg = yellow("Label {} {} #{}\n\n".format(a,self.item_desc,idx))
|
||||
oneshot_msg = yellow('Label {} {} #{}\n\n'.format(
|
||||
('added to' if lbl else 'removed from'),
|
||||
self.item_desc,
|
||||
idx ))
|
||||
else:
|
||||
oneshot_msg = red('Label could not be added\n\n')
|
||||
self.display_constants = self.get_display_constants()
|
||||
|
|
@ -487,22 +498,29 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
|
|||
e = self.unspent[idx-1]
|
||||
if await self.wallet.remove_address(e.addr):
|
||||
await self.get_unspent_data()
|
||||
oneshot_msg = yellow("{} #{} removed\n\n".format(capfirst(self.item_desc),idx))
|
||||
oneshot_msg = yellow(f'{capfirst(self.item_desc)} #{idx} removed\n\n')
|
||||
else:
|
||||
oneshot_msg = red('Address could not be removed\n\n')
|
||||
self.display_constants = self.get_display_constants()
|
||||
elif action == 'a_print':
|
||||
of = '{}-{}[{}].out'.format(self.dump_fn_pfx,self.proto.dcoin,
|
||||
','.join(self.sort_info(include_group=False)).lower())
|
||||
of = '{}-{}[{}].out'.format(
|
||||
self.dump_fn_pfx,
|
||||
self.proto.dcoin,
|
||||
','.join(self.sort_info(include_group=False)).lower() )
|
||||
msg('')
|
||||
try:
|
||||
write_data_to_file(of,await self.format_for_printing(),desc='{} listing'.format(self.desc))
|
||||
write_data_to_file(
|
||||
of,
|
||||
await self.format_for_printing(),
|
||||
desc = f'{self.desc} listing' )
|
||||
except UserNonConfirmation as e:
|
||||
oneshot_msg = red("File '{}' not overwritten by user request\n\n".format(of))
|
||||
oneshot_msg = red(f'File {of!r} not overwritten by user request\n\n')
|
||||
else:
|
||||
oneshot_msg = yellow("Data written to '{}'\n\n".format(of))
|
||||
oneshot_msg = yellow(f'Data written to {of!r}\n\n')
|
||||
elif action in ('a_view','a_view_wide'):
|
||||
do_pager(self.fmt_display if action == 'a_view' else await self.format_for_printing(color=True))
|
||||
do_pager(
|
||||
self.fmt_display if action == 'a_view' else
|
||||
await self.format_for_printing(color=True) )
|
||||
if g.platform == 'linux' and oneshot_msg == None:
|
||||
msg_r(CUR_RIGHT(len(prompt.split('\n')[-1])-2))
|
||||
no_output = True
|
||||
|
|
@ -533,7 +551,7 @@ class TwAddrList(MMGenDict,metaclass=aInitMeta):
|
|||
for mmid in sorted(a.mmid for a in acct_labels if a):
|
||||
if mmid == mmid_prev:
|
||||
err = True
|
||||
msg('Duplicate MMGen ID ({}) discovered in tracking wallet!\n'.format(mmid))
|
||||
msg(f'Duplicate MMGen ID ({mmid}) discovered in tracking wallet!\n')
|
||||
mmid_prev = mmid
|
||||
if err: rdie(3,'Tracking wallet is corrupted!')
|
||||
|
||||
|
|
@ -567,14 +585,15 @@ class TwAddrList(MMGenDict,metaclass=aInitMeta):
|
|||
die(2,'duplicate {} address ({}) for this MMGen address! ({})'.format(
|
||||
proto.coin,
|
||||
d['address'],
|
||||
self[lm]['addr']) )
|
||||
self[lm]['addr'] ))
|
||||
else:
|
||||
lm.confs = d['confirmations']
|
||||
lm.txid = d['txid']
|
||||
lm.date = None
|
||||
self[lm] = {'amt': proto.coin_amt('0'),
|
||||
'lbl': label,
|
||||
'addr': CoinAddr(proto,d['address'])}
|
||||
self[lm] = {
|
||||
'amt': proto.coin_amt('0'),
|
||||
'lbl': label,
|
||||
'addr': CoinAddr(proto,d['address']) }
|
||||
self[lm]['amt'] += d['amount']
|
||||
self.total += d['amount']
|
||||
|
||||
|
|
@ -614,7 +633,7 @@ class TwAddrList(MMGenDict,metaclass=aInitMeta):
|
|||
if not self.has_age:
|
||||
show_age = False
|
||||
if age_fmt not in self.age_fmts:
|
||||
raise BadAgeFormat("'{}': invalid age format (must be one of {!r})".format(age_fmt,self.age_fmts))
|
||||
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]
|
||||
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
|
||||
|
|
@ -671,7 +690,9 @@ class TwAddrList(MMGenDict,metaclass=aInitMeta):
|
|||
age=self.age_disp(mmid,age_fmt) if show_age and hasattr(mmid,'confs') else '-'
|
||||
).rstrip()
|
||||
|
||||
yield '\nTOTAL: {} {}'.format(self.total.hl(color=True),self.proto.dcoin)
|
||||
yield '\nTOTAL: {} {}'.format(
|
||||
self.total.hl(color=True),
|
||||
self.proto.dcoin )
|
||||
|
||||
return '\n'.join(gen_output())
|
||||
|
||||
|
|
@ -694,7 +715,7 @@ class TrackingWallet(MMGenObject,metaclass=aInitMeta):
|
|||
mode = 'w'
|
||||
|
||||
if g.debug:
|
||||
print_stack_trace('TW INIT {!r} {!r}'.format(mode,self))
|
||||
print_stack_trace(f'TW INIT {mode!r} {self!r}')
|
||||
|
||||
self.rpc = await rpc_init(proto) # TODO: create on demand - only certain ops require RPC
|
||||
self.proto = proto
|
||||
|
|
@ -707,8 +728,10 @@ class TrackingWallet(MMGenObject,metaclass=aInitMeta):
|
|||
self.init_empty()
|
||||
|
||||
if self.data['coin'] != self.proto.coin: # TODO remove?
|
||||
m = 'Tracking wallet coin ({}) does not match current coin ({})!'
|
||||
raise WalletFileError(m.format(self.data['coin'],self.proto.coin))
|
||||
raise WalletFileError(
|
||||
'Tracking wallet coin ({}) does not match current coin ({})!'.format(
|
||||
self.data['coin'],
|
||||
self.proto.coin ))
|
||||
|
||||
self.conv_types(self.data[self.data_key])
|
||||
self.cur_balances = {} # cache balances to prevent repeated lookups per program invocation
|
||||
|
|
@ -739,8 +762,7 @@ class TrackingWallet(MMGenObject,metaclass=aInitMeta):
|
|||
self.init_empty()
|
||||
self.force_write()
|
||||
else:
|
||||
m = "File '{}' exists but does not contain valid json data"
|
||||
raise WalletFileError(m.format(self.tw_fn))
|
||||
raise WalletFileError(f'File {self.tw_fn!r} exists but does not contain valid json data')
|
||||
else:
|
||||
self.upgrade_wallet_maybe()
|
||||
|
||||
|
|
@ -748,7 +770,7 @@ class TrackingWallet(MMGenObject,metaclass=aInitMeta):
|
|||
if self.mode == 'w':
|
||||
import atexit
|
||||
def del_tw(tw):
|
||||
dmsg('Running exit handler del_tw() for {!r}'.format(tw))
|
||||
dmsg(f'Running exit handler del_tw() for {tw!r}')
|
||||
del tw
|
||||
atexit.register(del_tw,self)
|
||||
|
||||
|
|
@ -766,7 +788,7 @@ class TrackingWallet(MMGenObject,metaclass=aInitMeta):
|
|||
Since no exceptions are raised, errors will not be caught by the test suite.
|
||||
"""
|
||||
if g.debug:
|
||||
print_stack_trace('TW DEL {!r}'.format(self))
|
||||
print_stack_trace(f'TW DEL {self!r}')
|
||||
|
||||
if self.mode == 'w':
|
||||
self.write()
|
||||
|
|
@ -846,17 +868,22 @@ class TrackingWallet(MMGenObject,metaclass=aInitMeta):
|
|||
@write_mode
|
||||
def write_changed(self,data):
|
||||
write_data_to_file(
|
||||
self.tw_fn,data,
|
||||
desc='{} data'.format(self.base_desc),
|
||||
ask_overwrite=False,ignore_opt_outdir=True,quiet=True,
|
||||
check_data=True,cmp_data=self.orig_data)
|
||||
self.tw_fn,
|
||||
data,
|
||||
desc = f'{self.base_desc} data',
|
||||
ask_overwrite = False,
|
||||
ignore_opt_outdir = True,
|
||||
quiet = True,
|
||||
check_data = True,
|
||||
cmp_data = self.orig_data )
|
||||
|
||||
self.orig_data = data
|
||||
|
||||
def write(self): # use 'check_data' to check wallet hasn't been altered by another program
|
||||
if not self.use_tw_file:
|
||||
dmsg("'use_tw_file' is False, doing nothing")
|
||||
return
|
||||
dmsg('write(): checking if {} data has changed'.format(self.desc))
|
||||
dmsg(f'write(): checking if {self.desc} data has changed')
|
||||
wdata = json.dumps(self.data)
|
||||
|
||||
if self.orig_data != wdata:
|
||||
|
|
@ -903,11 +930,11 @@ class TrackingWallet(MMGenObject,metaclass=aInitMeta):
|
|||
|
||||
try:
|
||||
if not is_mmgen_id(self.proto,arg1):
|
||||
assert coinaddr,"Invalid coin address for this chain: {}".format(arg1)
|
||||
assert coinaddr,"{pn} address '{ma}' not found in tracking wallet"
|
||||
assert await self.is_in_wallet(coinaddr),"Address '{ca}' not found in tracking wallet"
|
||||
assert coinaddr, f'Invalid coin address for this chain: {arg1}'
|
||||
assert coinaddr, f'{g.proj_name} address {mmaddr!r} not found in tracking wallet'
|
||||
assert await self.is_in_wallet(coinaddr), f'Address {coinaddr!r} not found in tracking wallet'
|
||||
except Exception as e:
|
||||
msg(e.args[0].format(pn=g.proj_name,ma=mmaddr,ca=coinaddr))
|
||||
msg(str(e))
|
||||
return False
|
||||
|
||||
# Allow for the possibility that BTC addr of MMGen addr was entered.
|
||||
|
|
@ -917,7 +944,7 @@ class TrackingWallet(MMGenObject,metaclass=aInitMeta):
|
|||
mmaddr = (await TwAddrData(proto=self.proto)).coinaddr2mmaddr(coinaddr)
|
||||
|
||||
if not mmaddr:
|
||||
mmaddr = '{}:{}'.format(self.proto.base_coin.lower(),coinaddr)
|
||||
mmaddr = f'{self.proto.base_coin.lower()}:{coinaddr}'
|
||||
|
||||
mmaddr = TwMMGenID(self.proto,mmaddr)
|
||||
|
||||
|
|
@ -929,14 +956,16 @@ class TrackingWallet(MMGenObject,metaclass=aInitMeta):
|
|||
|
||||
if await self.set_label(coinaddr,lbl) == False:
|
||||
if not silent:
|
||||
msg('Label could not be {}'.format(('removed','added')[bool(label)]))
|
||||
msg( 'Label could not be {}'.format('added' if label else 'removed') )
|
||||
return False
|
||||
else:
|
||||
m = mmaddr.type.replace('mmg','MMG')
|
||||
a = mmaddr.replace(self.proto.base_coin.lower()+':','')
|
||||
s = '{} address {} in tracking wallet'.format(m,a)
|
||||
if label: msg("Added label '{}' to {}".format(label,s))
|
||||
else: msg('Removed label from {}'.format(s))
|
||||
desc = '{} address {} in tracking wallet'.format(
|
||||
mmaddr.type.replace('mmg','MMG'),
|
||||
mmaddr.replace(self.proto.base_coin.lower()+':','') )
|
||||
if label:
|
||||
msg(f'Added label {label!r} to {desc}')
|
||||
else:
|
||||
msg(f'Removed label from {desc}')
|
||||
return True
|
||||
|
||||
@write_mode
|
||||
|
|
@ -945,7 +974,7 @@ class TrackingWallet(MMGenObject,metaclass=aInitMeta):
|
|||
|
||||
@write_mode
|
||||
async def remove_address(self,addr):
|
||||
raise NotImplementedError('address removal not implemented for coin {}'.format(self.proto.coin))
|
||||
raise NotImplementedError(f'address removal not implemented for coin {self.proto.coin}')
|
||||
|
||||
class TwGetBalance(MMGenObject,metaclass=aInitMeta):
|
||||
|
||||
|
|
|
|||
|
|
@ -737,7 +737,7 @@ class MMGenTX:
|
|||
if selected:
|
||||
if selected[-1] <= len(unspent):
|
||||
return selected
|
||||
msg('Unspent output number must be <= {}'.format(len(unspent)))
|
||||
msg(f'Unspent output number must be <= {len(unspent)}')
|
||||
|
||||
def select_unspent_cmdline(self,unspent):
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ def run_test(test,arg,input_data):
|
|||
raise UserWarning("Non-'None' return value {} with bad input data".format(repr(ret)))
|
||||
if opt.silent and input_data=='good' and ret==bad_ret:
|
||||
raise UserWarning("'None' returned with good input data")
|
||||
|
||||
if input_data=='good':
|
||||
if ret_idx:
|
||||
ret_chk = arg[list(arg.keys())[ret_idx]].encode()
|
||||
|
|
@ -108,7 +109,8 @@ def run_test(test,arg,input_data):
|
|||
if not opt.super_silent:
|
||||
try: ret_disp = ret.decode()
|
||||
except: ret_disp = ret
|
||||
msg('==> {!r}'.format(ret_disp))
|
||||
msg(f'==> {ret_disp!r}')
|
||||
|
||||
if opt.verbose and issubclass(cls,MMGenObject):
|
||||
ret.pmsg() if hasattr(ret,'pmsg') else pmsg(ret)
|
||||
except Exception as e:
|
||||
|
|
@ -121,10 +123,10 @@ def run_test(test,arg,input_data):
|
|||
if input_data == 'good':
|
||||
raise ValueError('Error on good input data')
|
||||
if opt.verbose:
|
||||
msg('exitval: {}'.format(e.code))
|
||||
msg(f'exitval: {e.code}')
|
||||
except UserWarning as e:
|
||||
msg('==> {!r}'.format(ret))
|
||||
die(2,red('{}'.format(e.args[0])))
|
||||
msg(f'==> {ret!r}')
|
||||
die(2,red(str(e)))
|
||||
|
||||
def do_loop():
|
||||
import importlib
|
||||
|
|
@ -143,7 +145,11 @@ def do_loop():
|
|||
if not opt.silent:
|
||||
msg(purple(capfirst(k)+' input:'))
|
||||
for arg in test_data[test][k]:
|
||||
run_test(test,arg,input_data=k)
|
||||
run_test(
|
||||
test,
|
||||
arg,
|
||||
input_data = k,
|
||||
)
|
||||
|
||||
from mmgen.protocol import init_proto_from_opts
|
||||
proto = init_proto_from_opts()
|
||||
|
|
|
|||
|
|
@ -149,18 +149,6 @@ tests = {
|
|||
{'id_str':'F00BAA12:S:9999999', 'proto':proto},
|
||||
),
|
||||
},
|
||||
'TwLabel': {
|
||||
'bad': ('x x','x я','я:я',1,'f00f00f','a:b','x:L:3','F00BAA12:0 x',
|
||||
'F00BAA12:Z:99',tw_pfx+' x',tw_pfx+'я x',
|
||||
'F00BAA12:S:1 '+ utf8_ctrl[:40],
|
||||
{'s':'F00BAA12:S:1 '+ utf8_ctrl[:40],'on_fail':'raise','ExcType':'BadTwComment'},
|
||||
),
|
||||
'good': (
|
||||
('F00BAA12:99 a comment','F00BAA12:L:99 a comment'),
|
||||
'F00BAA12:L:99 comment (UTF-8) α',
|
||||
'F00BAA12:S:9999999 comment',
|
||||
tw_pfx+'x comment')
|
||||
},
|
||||
'TwLabel': {
|
||||
'bad': (
|
||||
{'text':'x x', 'proto':proto},
|
||||
|
|
|
|||
|
|
@ -167,6 +167,8 @@ def add_cmdline_opts():
|
|||
|
||||
# add_cmdline_opts()
|
||||
|
||||
opts.UserOpts._reset_ok += ('skip_deps',)
|
||||
|
||||
# step 2: opts.init will create new data_dir in ./test (if not 'resume' or 'skip_deps'):
|
||||
usr_args = opts.init(opts_data)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue