From 9c07442191c658aeca351ffec2ac61b7a91803e2 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sun, 13 Nov 2022 15:36:35 +0000 Subject: [PATCH] CoinAmt: improve columnar formatting --- mmgen/amt.py | 27 ++++++++++----------------- mmgen/data/version | 2 +- mmgen/proto/eth/tw/addresses.py | 2 +- mmgen/proto/eth/tw/unspent.py | 4 ++-- mmgen/tw/addresses.py | 6 +++--- mmgen/tw/bal.py | 2 +- mmgen/tw/txhistory.py | 10 ++++++++-- mmgen/tw/unspent.py | 12 ++++++------ mmgen/tw/view.py | 10 ++++++++++ mmgen/xmrwallet.py | 2 +- 10 files changed, 43 insertions(+), 34 deletions(-) diff --git a/mmgen/amt.py b/mmgen/amt.py index da7e12e5..a83bcea5 100755 --- a/mmgen/amt.py +++ b/mmgen/amt.py @@ -38,7 +38,6 @@ class CoinAmt(Decimal,Hilite,InitErrors): # abstract class max_prec = 0 # number of decimal places for this coin max_amt = None # coin supply if known, otherwise None units = () # defined unit names, e.g. ('satoshi',...) - amt_fs = '0.0' # format string for the fmt() method def __new__(cls,num,from_unit=None,from_decimal=False): if type(num) == cls: @@ -73,21 +72,18 @@ class CoinAmt(Decimal,Hilite,InitErrors): # abstract class def fmtc(cls): cls.method_not_implemented() - def fmt(self,fs=None,color=False,suf='',prec=1000): - if fs == None: - fs = self.amt_fs + def fmt(self,color=False,iwidth=1,prec=None): # iwidth: width of the integer part s = self.__str__() - if '.' in fs: - p1,p2 = list(map(int,fs.split('.',1))) - ss = s.split('.',1) - if len(ss) == 2: - a,b = ss - ret = a.rjust(p1) + '.' + ((b+suf).ljust(p2+len(suf)))[:prec] - else: - ret = s.rjust(p1) + suf + (' ' * (p2+1))[:prec+1-len(suf)] + prec = prec or self.max_prec + if '.' in s: + a,b = s.split('.',1) + return self.colorize( + a.rjust(iwidth) + '.' + b.ljust(prec)[:prec], # truncation, not rounding! + color = color ) else: - ret = s.ljust(int(fs)) - return self.colorize(ret,color=color) + return self.colorize( + s.rjust(iwidth).ljust(iwidth+prec+1), + color = color ) def hl(self,color=True): return self.colorize(self.__str__(),color=color) @@ -165,7 +161,6 @@ class BTCAmt(CoinAmt): max_amt = 21000000 satoshi = Decimal('0.00000001') units = ('satoshi',) - amt_fs = '4.8' class BCHAmt(BTCAmt): pass @@ -177,7 +172,6 @@ class XMRAmt(CoinAmt): max_prec = 12 atomic = Decimal('0.000000000001') units = ('atomic',) - amt_fs = '4.12' # Kwei (babbage) 3, Mwei (lovelace) 6, Gwei (shannon) 9, µETH (szabo) 12, mETH (finney) 15, ETH 18 class ETHAmt(CoinAmt): @@ -189,7 +183,6 @@ class ETHAmt(CoinAmt): szabo = Decimal('0.000001') finney = Decimal('0.001') units = ('wei','Kwei','Mwei','Gwei','szabo','finney') - amt_fs = '4.18' def toWei(self): return int(Decimal(self) // self.wei) diff --git a/mmgen/data/version b/mmgen/data/version index 321f28f9..d60f339b 100644 --- a/mmgen/data/version +++ b/mmgen/data/version @@ -1 +1 @@ -13.3.dev19 +13.3.dev20 diff --git a/mmgen/proto/eth/tw/addresses.py b/mmgen/proto/eth/tw/addresses.py index 6302d4b9..a03e13d8 100755 --- a/mmgen/proto/eth/tw/addresses.py +++ b/mmgen/proto/eth/tw/addresses.py @@ -48,7 +48,7 @@ Actions: [q]uit, r[e]draw, [D]elete address, add [l]abel: 'num': max(2,len(str(len(data)))+1), 'mmid': max(len(d.twmmid.disp) for d in data), 'used': 0, - 'amt': self.disp_prec + 5, + 'amt': self.amt_widths['amt'], 'date': 0, 'block': 0, 'date_time': 0, diff --git a/mmgen/proto/eth/tw/unspent.py b/mmgen/proto/eth/tw/unspent.py index 2969aee7..81f7607d 100755 --- a/mmgen/proto/eth/tw/unspent.py +++ b/mmgen/proto/eth/tw/unspent.py @@ -75,8 +75,8 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, widths = { # fixed cols 'num': max(2,len(str(len(data)))+1), 'mmid': max(len(d.twmmid.disp) for d in data) if self.show_mmid else 0, - 'amt': self.disp_prec + 5, - 'amt2': self.disp_prec + 5 if self.has_amt2 else 0, + 'amt': self.amt_widths['amt'], + 'amt2': self.amt_widths.get('amt2',0), 'spc': (5 if self.show_mmid else 3) + self.has_amt2, # 5(3) spaces in fs 'txid': 0, 'vout': 0, diff --git a/mmgen/tw/addresses.py b/mmgen/tw/addresses.py index 672e63f7..a1515ca3 100755 --- a/mmgen/tw/addresses.py +++ b/mmgen/tw/addresses.py @@ -131,7 +131,7 @@ class TwAddresses(TwView): 'num': max(2,len(str(len(data)))+1), 'mmid': max(len(d.twmmid.disp) for d in data), 'used': 4, - 'amt': self.disp_prec + 5, + 'amt': self.amt_widths['amt'], 'date': self.age_w if self.has_age else 0, 'block': self.age_col_params['block'][0] if wide and self.has_age else 0, 'date_time': self.age_col_params['date_time'][0] if wide and self.has_age else 0, @@ -179,7 +179,7 @@ class TwAddresses(TwView): u = yes if d.recvd else no, a = d.addr.fmt( color=color, width=cw.addr ), c = d.comment.fmt( width=cw.comment, color=color, nullrepl='-' ), - A = d.amt.fmt( color=color, prec=self.disp_prec ), + A = d.amt.fmt( color=color, iwidth=cw.iwidth, prec=self.disp_prec ), d = self.age_disp( d, self.age_fmt ) ) @@ -208,7 +208,7 @@ class TwAddresses(TwView): u = yes if d.recvd else no, a = d.addr.fmt( color=color, width=cw.addr ), c = d.comment.fmt( width=cw.comment, color=color, nullrepl='-' ), - A = d.amt.fmt( color=color, prec=self.disp_prec ), + A = d.amt.fmt( color=color, iwidth=cw.iwidth, prec=self.disp_prec ), b = self.age_disp( d, 'block' ), D = self.age_disp( d, 'date_time' ), ).rstrip() diff --git a/mmgen/tw/bal.py b/mmgen/tw/bal.py index 80ef32e8..aa5cd437 100755 --- a/mmgen/tw/bal.py +++ b/mmgen/tw/bal.py @@ -69,7 +69,7 @@ class TwGetBalance(MMGenObject,metaclass=AsyncInit): return len(str(int(max(v[colname] for v in self.data.values())))) + iwidth_adj def make_col(label,col): - return(self.data[label][col].fmt(fs=f'{iwidths[col]}.{add_w-1}',color=color)) + return(self.data[label][col].fmt(iwidth=iwidths[col],color=color)) if color: from ..color import red,green,yellow diff --git a/mmgen/tw/txhistory.py b/mmgen/tw/txhistory.py index 96361e77..a21ee0d5 100755 --- a/mmgen/tw/txhistory.py +++ b/mmgen/tw/txhistory.py @@ -12,6 +12,8 @@ tw.txhistory: Tracking wallet transaction history class for the MMGen suite """ +from collections import namedtuple + from ..util import fmt from ..objmethods import MMGenObject from ..obj import NonNegativeInt @@ -49,6 +51,10 @@ class TwTxHistory(TwView): def filter_data(self): return (d for d in self.data if d.confirmations > 0 or self.show_unconfirmed) + def set_amt_widths(self,data): + amts_tuple = namedtuple('amts_data',['amt']) + return super().set_amt_widths([amts_tuple(d.amt_disp(self.show_total_amt)) for d in data]) + def get_column_widths(self,data,wide=False): # var cols: inputs outputs comment [txid] @@ -77,7 +83,7 @@ class TwTxHistory(TwView): widths = { # fixed cols 'num': max(2,len(str(len(data)))+1), 'date': self.age_w, - 'amt': self.disp_prec + 5, + 'amt': self.amt_widths['amt'], 'spc': 6 + self.show_txid, # 5(6) spaces between cols + 1 leading space in fs } @@ -109,7 +115,7 @@ class TwTxHistory(TwView): t = d.txid_disp( width=cw.txid, color=color ) if hasattr(cw,'txid') else None, d = d.age_disp( self.age_fmt, width=self.age_w, color=color ), i = d.vouts_disp( 'inputs', width=cw.inputs, color=color ), - A = d.amt_disp(self.show_total_amt).fmt( prec=self.disp_prec, color=color ), + A = d.amt_disp(self.show_total_amt).fmt( iwidth=cw.iwidth, prec=self.disp_prec, color=color ), o = d.vouts_disp( 'outputs', width=cw.outputs, color=color ), c = d.comment.fmt( width=cw.comment, color=color, nullrepl='-' ) ).rstrip() diff --git a/mmgen/tw/unspent.py b/mmgen/tw/unspent.py index a50c0c7b..d01a7905 100755 --- a/mmgen/tw/unspent.py +++ b/mmgen/tw/unspent.py @@ -132,8 +132,8 @@ class TwUnspentOutputs(TwView): 'num': max(2,len(str(len(data)))+1), 'vout': 4, 'mmid': max(len(d.twmmid.disp) for d in data) if self.show_mmid else 0, - 'amt': self.disp_prec + 5, - 'amt2': 0, + 'amt': self.amt_widths['amt'], + 'amt2': self.amt_widths.get('amt2',0), 'block': self.age_col_params['block'][0] if wide else 0, 'date_time': self.age_col_params['date_time'][0] if wide else 0, 'date': self.age_w, @@ -177,8 +177,8 @@ class TwUnspentOutputs(TwView): m = (MMGenID.fmtc( '.'*cw.mmid, color=color ) if d.skip == 'addr' else d.twmmid.fmt( width=cw.mmid, color=color )) if cw.mmid else None, c = d.comment.fmt( width=cw.comment, color=color, nullrepl='-' ) if cw.comment else None, - A = d.amt.fmt( color=color, prec=self.disp_prec ), - B = d.amt2.fmt( color=color, prec=self.disp_prec ) if cw.amt2 else None, + A = d.amt.fmt( color=color, iwidth=cw.iwidth, prec=self.disp_prec ), + B = d.amt2.fmt( color=color, iwidth=cw.iwidth2, prec=self.disp_prec ) if cw.amt2 else None, d = self.age_disp(d,self.age_fmt), ) @@ -203,8 +203,8 @@ class TwUnspentOutputs(TwView): v = ' ' + d.vout.fmt( width=cw.vout-1, color=color ) if cw.vout else None, a = d.addr.fmt( width=cw.addr, color=color ), m = d.twmmid.fmt( width=cw.mmid, color=color ), - A = d.amt.fmt( color=color, prec=self.disp_prec ), - B = d.amt2.fmt( color=color, prec=self.disp_prec ) if cw.amt2 else None, + A = d.amt.fmt( color=color, iwidth=cw.iwidth, prec=self.disp_prec ), + B = d.amt2.fmt( color=color, iwidth=cw.iwidth2, prec=self.disp_prec ) if cw.amt2 else None, b = self.age_disp(d,'block'), D = self.age_disp(d,'date_time'), c = d.comment.fmt( width=cw.comment, color=color, nullrepl='-' ), diff --git a/mmgen/tw/view.py b/mmgen/tw/view.py index b6003396..f3435acb 100755 --- a/mmgen/tw/view.py +++ b/mmgen/tw/view.py @@ -121,6 +121,7 @@ class TwView(MMGenObject,metaclass=AsyncInit): if self.has_wallet: from .ctl import TrackingWallet self.wallet = await TrackingWallet(proto,mode='w') + self.amt_keys = {'amt':'iwidth','amt2':'iwidth2'} if self.has_amt2 else {'amt':'iwidth'} @property def age_w(self): @@ -225,10 +226,12 @@ class TwView(MMGenObject,metaclass=AsyncInit): def do_ret(freews): widths.update({k:minws[k] + freews.get(k,0) for k in minws}) + widths.update({ikey: widths[key] - self.disp_prec - 1 for key,ikey in self.amt_keys.items()}) return namedtuple('column_widths',widths.keys())(*widths.values()) def do_ret_max(): widths.update({k:max(minws[k],maxws[k]) for k in minws}) + widths.update({ikey: widths[key] - self.disp_prec - 1 for key,ikey in self.amt_keys.items()}) return namedtuple('column_widths',widths.keys())(*widths.values()) def get_freews(cols,varws,varw,minw): @@ -308,6 +311,12 @@ class TwView(MMGenObject,metaclass=AsyncInit): self.proto.dcoin ) if hasattr(self,'total') else '' + def set_amt_widths(self,data): + # width of amts column: min(7,width of integer part) + len('.') + width of fractional part + self.amt_widths = {k: + min(7,max(len(str(getattr(d,k).to_integral_value())) for d in data)) + 1 + self.disp_prec + for k in self.amt_keys} + async def format(self,display_type,color=True,cached=False,interactive=False): if not cached: @@ -322,6 +331,7 @@ class TwView(MMGenObject,metaclass=AsyncInit): data = self.disp_data = list(self.filter_data()) # method could be a generator if data and dt.need_column_widths: + self.set_amt_widths(data) cw = self.get_column_widths(data,wide=dt.detail) cwh = cw._asdict() fp = self.fs_params diff --git a/mmgen/xmrwallet.py b/mmgen/xmrwallet.py index 07091b33..2c9652d2 100755 --- a/mmgen/xmrwallet.py +++ b/mmgen/xmrwallet.py @@ -276,7 +276,7 @@ class MoneroWalletOps: uarg_info = xmrwallet_uarg_info def fmt_amt(amt): - return self.proto.coin_amt(amt,from_unit='atomic').fmt(fs='5.12',color=True) + return self.proto.coin_amt(amt,from_unit='atomic').fmt( iwidth=5, prec=12, color=True ) def hl_amt(amt): return self.proto.coin_amt(amt,from_unit='atomic').hl()