From 465770bc9357fece2fd8ce598c2e817fb8ed4c5a Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Mon, 24 Nov 2025 12:48:48 +0000 Subject: [PATCH] tw.view: grouping cleanups --- mmgen/proto/btc/tw/unspent.py | 5 ++++- mmgen/tw/addresses.py | 7 ++----- mmgen/tw/unspent.py | 24 +++++++++++------------- mmgen/tw/view.py | 7 ++++--- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/mmgen/proto/btc/tw/unspent.py b/mmgen/proto/btc/tw/unspent.py index 0be1cb84..d68a744b 100755 --- a/mmgen/proto/btc/tw/unspent.py +++ b/mmgen/proto/btc/tw/unspent.py @@ -45,7 +45,10 @@ class BitcoinTwUnspentOutputs(BitcoinTwView, TwUnspentOutputs): scriptPubKey = ImmutableAttr(HexStr) has_age = True - can_group = True + groupable = { + 'addr': 'addr', + 'twmmid': 'addr', + 'txid': 'txid'} disp_spc = 5 vout_w = 4 hdr_lbl = 'unspent outputs' diff --git a/mmgen/tw/addresses.py b/mmgen/tw/addresses.py index 355c14a3..48d56b9a 100755 --- a/mmgen/tw/addresses.py +++ b/mmgen/tw/addresses.py @@ -79,8 +79,7 @@ class TwAddresses(TwView): 'amt', 'recvd', 'is_used', - 'date', - 'skip'} + 'date'} invalid_attrs = {'proto'} twmmid = ImmutableAttr(TwMMGenID, include_proto=True) # contains confs,txid(unused),date(unused),al_id @@ -92,7 +91,6 @@ class TwAddresses(TwView): recvd = ImmutableAttr(CoinAmtChk, include_proto=True) is_used = ImmutableAttr(bool) date = ListItemAttr(int, typeconv=False, reassign_ok=True) - skip = ListItemAttr(str, typeconv=False, reassign_ok=True) def __init__(self, proto, **kwargs): self.__dict__['proto'] = proto @@ -165,8 +163,7 @@ class TwAddresses(TwView): amt = data['amt'], recvd = data['recvd'], is_used = data['is_used'], - date = 0, - skip = '') + date = 0) for twmmid, data in rpc_data.items()) def get_disp_data(self): diff --git a/mmgen/tw/unspent.py b/mmgen/tw/unspent.py index d3471f13..296082b5 100755 --- a/mmgen/tw/unspent.py +++ b/mmgen/tw/unspent.py @@ -36,7 +36,6 @@ from .view import TwView class TwUnspentOutputs(TwView): has_age = False - can_group = False show_mmid = True hdr_lbl = 'tracked addresses' desc = 'address balances' @@ -120,7 +119,8 @@ class TwUnspentOutputs(TwView): 'twmmid': l.mmid, 'comment': l.comment or '', 'addr': CoinAddr(self.proto, o['address']), - 'confs': o['confirmations']}) + 'confs': o['confirmations'], + 'skip': ''}) yield self.MMGenTwUnspentOutput( self.proto, **{k: v for k, v in o.items() if k in self.MMGenTwUnspentOutput.valid_attrs}) @@ -140,19 +140,17 @@ class TwUnspentOutputs(TwView): def get_disp_data(self): - data = self.data.copy() - - for d in data: + for d in self.data: d.skip = '' - gkeys = {'addr': 'addr', 'twmmid': 'addr', 'txid': 'txid'} - if self.group and self.sort_key in gkeys: - for a, b in [(data[i], data[i+1]) for i in range(len(data)-1)]: - for k in gkeys: - if self.sort_key == k and getattr(a, k) == getattr(b, k): - b.skip = gkeys[k] + if self.group and (e := self.sort_key) in self.groupable: + data = self.data + skip = self.groupable[e] + for i in range(len(data) - 1): + if getattr(data[i], e) == getattr(data[i + 1], e): + data[i + 1].skip = skip - return data + return self.data def get_column_widths(self, data, *, wide, interactive): @@ -272,5 +270,5 @@ class TwUnspentOutputs(TwView): parent.show_mmid = not parent.show_mmid def d_group(self, parent): - if parent.can_group: + if parent.groupable: parent.group = not parent.group diff --git a/mmgen/tw/view.py b/mmgen/tw/view.py index a244960e..dba9fb86 100755 --- a/mmgen/tw/view.py +++ b/mmgen/tw/view.py @@ -85,6 +85,7 @@ class TwView(MMGenObject, metaclass=AsyncInit): dates_set = False reverse = False group = False + groupable = {} use_cached = False minconf = 1 txid_w = 0 @@ -260,7 +261,7 @@ class TwView(MMGenObject, metaclass=AsyncInit): def sort_info(self, *, include_group=True): ret = ([], ['Reverse'])[self.reverse] ret.append(self.sort_disp[self.sort_key]) - if include_group and self.group and (self.sort_key in ('addr', 'txid', 'twmmid')): + if include_group and self.group and self.sort_key in self.groupable: ret.append('Grouped') return ret @@ -288,13 +289,13 @@ class TwView(MMGenObject, metaclass=AsyncInit): await self.gen_data(rpc_data, lbl_id) if isAsync(self.gen_data) else self.gen_data(rpc_data, lbl_id)) - self.disp_data = tuple(self.get_disp_data()) - if not self.data: die(1, f'No {self.item_desc_pl} in tracking wallet!') self.sort_data(self.sort_key) + self.disp_data = tuple(self.get_disp_data()) + # get_data() is immediately followed by display header, and get_rpc_data() produces output, # so add NL here (' ' required because CUR_HOME erases preceding blank lines) msg(' ')