diff --git a/mmgen/addr.py b/mmgen/addr.py index 70d706f9..e4b25e26 100755 --- a/mmgen/addr.py +++ b/mmgen/addr.py @@ -290,18 +290,18 @@ class KeyGeneratorDummy(KeyGenerator): return PubKey(privhex,compressed=privhex.compressed) class AddrListEntry(MMGenListItem): - addr = MMGenListItemAttr('addr','CoinAddr') - idx = MMGenListItemAttr('idx','AddrIdx') # not present in flat addrlists - label = MMGenListItemAttr('label','TwComment',reassign_ok=True) - sec = MMGenListItemAttr('sec',PrivKey,typeconv=False) - viewkey = MMGenListItemAttr('viewkey','ViewKey') - wallet_passwd = MMGenListItemAttr('wallet_passwd','WalletPassword') + addr = ListItemAttr('CoinAddr') + idx = ListItemAttr('AddrIdx') # not present in flat addrlists + label = ListItemAttr('TwComment',reassign_ok=True) + sec = ListItemAttr(PrivKey,typeconv=False) + viewkey = ListItemAttr('ViewKey') + wallet_passwd = ListItemAttr('WalletPassword') class PasswordListEntry(MMGenListItem): - passwd = MMGenListItemAttr('passwd',str,typeconv=False) # TODO: create Password type - idx = MMGenImmutableAttr('idx','AddrIdx') - label = MMGenListItemAttr('label','TwComment',reassign_ok=True) - sec = MMGenListItemAttr('sec',PrivKey,typeconv=False) + passwd = ListItemAttr(str,typeconv=False) # TODO: create Password type + idx = ImmutableAttr('AddrIdx') + label = ListItemAttr('TwComment',reassign_ok=True) + sec = ListItemAttr(PrivKey,typeconv=False) class AddrListChksum(str,Hilite): color = 'pink' diff --git a/mmgen/altcoins/eth/tw.py b/mmgen/altcoins/eth/tw.py index 8e36c1a6..d0cfa73b 100755 --- a/mmgen/altcoins/eth/tw.py +++ b/mmgen/altcoins/eth/tw.py @@ -21,7 +21,7 @@ altcoins.eth.tw: Ethereum tracking wallet and related classes for the MMGen suit """ from mmgen.common import * -from mmgen.obj import ETHAmt,TwLabel,is_coin_addr,is_mmgen_id,MMGenListItem,MMGenListItemAttr,MMGenImmutableAttr +from mmgen.obj import ETHAmt,TwLabel,is_coin_addr,is_mmgen_id,MMGenListItem,ListItemAttr,ImmutableAttr from mmgen.tw import TrackingWallet,TwAddrList,TwUnspentOutputs from mmgen.addr import AddrData from .contract import Token @@ -296,15 +296,15 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, } for d in wl] class MMGenTwUnspentOutput(MMGenListItem): - txid = MMGenListItemAttr('txid','CoinTxID') - vout = MMGenListItemAttr('vout',int,typeconv=False) - amt = MMGenImmutableAttr('amt',lambda:g.proto.coin_amt,typeconv=False) - amt2 = MMGenListItemAttr('amt2',lambda:g.proto.coin_amt,typeconv=False) - label = MMGenListItemAttr('label','TwComment',reassign_ok=True) - twmmid = MMGenImmutableAttr('twmmid','TwMMGenID') - addr = MMGenImmutableAttr('addr','CoinAddr') - confs = MMGenImmutableAttr('confs',int,typeconv=False) - skip = MMGenListItemAttr('skip',str,typeconv=False,reassign_ok=True) + txid = ListItemAttr('CoinTxID') + vout = ListItemAttr(int,typeconv=False) + amt = ImmutableAttr(lambda:g.proto.coin_amt,typeconv=False) + amt2 = ListItemAttr(lambda:g.proto.coin_amt,typeconv=False) + label = ListItemAttr('TwComment',reassign_ok=True) + twmmid = ImmutableAttr('TwMMGenID') + addr = ImmutableAttr('CoinAddr') + confs = ImmutableAttr(int,typeconv=False) + skip = ListItemAttr(str,typeconv=False,reassign_ok=True) def age_disp(self,o,age_fmt): # TODO return None diff --git a/mmgen/devtools.py b/mmgen/devtools.py index 49eccca6..43f597ae 100755 --- a/mmgen/devtools.py +++ b/mmgen/devtools.py @@ -113,7 +113,7 @@ if os.getenv('MMGEN_DEBUG') or os.getenv('MMGEN_TEST_SUITE') or os.getenv('MMGEN break else: rdie(3,'unable to find descriptor {}.{}'.format(cls.__name__,attrname)) - if type(attr).__name__ == 'MMGenImmutableAttr': + if type(attr).__name__ == 'ImmutableAttr': if attrname not in self.__dict__: fs = 'attribute {!r} of {} has not been initialized in constructor!' rdie(3,fs.format(attrname,cls.__name__)) diff --git a/mmgen/obj.py b/mmgen/obj.py index e07e7cfa..3282aa9a 100755 --- a/mmgen/obj.py +++ b/mmgen/obj.py @@ -210,17 +210,19 @@ class Int(int,Hilite,InitErrors): # For attrs that are always present in the data instance # Reassignment and deletion forbidden -class MMGenImmutableAttr(object): # Descriptor +class ImmutableAttr(object): # Descriptor ok_dtypes = (str,type,type(None),type(lambda:0)) - def __init__(self,name,dtype,typeconv=True,set_none_ok=False): + def __init__(self,dtype,typeconv=True,set_none_ok=False): self.typeconv = typeconv self.set_none_ok = set_none_ok assert isinstance(dtype,self.ok_dtypes),'{!r}: invalid dtype arg'.format(dtype) - self.name = name self.dtype = dtype + def __set_name__(self,owner,name): + self.name = name + def __get__(self,instance,owner): return instance.__dict__[self.name] @@ -252,12 +254,12 @@ class MMGenImmutableAttr(object): # Descriptor # For attrs that might not be present in the data instance # Reassignment or deletion allowed if specified -class MMGenListItemAttr(MMGenImmutableAttr): # Descriptor +class ListItemAttr(ImmutableAttr): # Descriptor - def __init__(self,name,dtype,typeconv=True,reassign_ok=False,delete_ok=False): + def __init__(self,dtype,typeconv=True,reassign_ok=False,delete_ok=False): self.reassign_ok = reassign_ok self.delete_ok = delete_ok - MMGenImmutableAttr.__init__(self,name,dtype,typeconv=typeconv) + ImmutableAttr.__init__(self,dtype,typeconv=typeconv) # return None if attribute doesn't exist def __get__(self,instance,owner): @@ -272,7 +274,7 @@ class MMGenListItemAttr(MMGenImmutableAttr): # Descriptor if self.name in instance.__dict__: del instance.__dict__[self.name] else: - MMGenImmutableAttr.__delete__(self,instance) + ImmutableAttr.__delete__(self,instance) class MMGenListItem(MMGenObject): @@ -729,8 +731,8 @@ class PrivKey(str,Hilite,InitErrors,MMGenObject): width = 64 trunc_ok = False - compressed = MMGenImmutableAttr('compressed',bool,typeconv=False) - wif = MMGenImmutableAttr('wif',WifKey,typeconv=False) + compressed = ImmutableAttr(bool,typeconv=False) + wif = ImmutableAttr(WifKey,typeconv=False) # initialize with (priv_bin,compressed), WIF or self def __new__(cls,s=None,compressed=None,wif=None,pubkey_type=None,on_fail='die'): @@ -881,14 +883,14 @@ class MMGenAddrType(str,Hilite,InitErrors,MMGenObject): trunc_ok = False color = 'blue' - name = MMGenImmutableAttr('name',str) - pubkey_type = MMGenImmutableAttr('pubkey_type',str) - compressed = MMGenImmutableAttr('compressed',bool,set_none_ok=True) - gen_method = MMGenImmutableAttr('gen_method',str,set_none_ok=True) - addr_fmt = MMGenImmutableAttr('addr_fmt',str,set_none_ok=True) - wif_label = MMGenImmutableAttr('wif_label',str,set_none_ok=True) - extra_attrs = MMGenImmutableAttr('extra_attrs',tuple,set_none_ok=True) - desc = MMGenImmutableAttr('desc',str) + name = ImmutableAttr(str) + pubkey_type = ImmutableAttr(str) + compressed = ImmutableAttr(bool,set_none_ok=True) + gen_method = ImmutableAttr(str,set_none_ok=True) + addr_fmt = ImmutableAttr(str,set_none_ok=True) + wif_label = ImmutableAttr(str,set_none_ok=True) + extra_attrs = ImmutableAttr(tuple,set_none_ok=True) + desc = ImmutableAttr(str) mmtypes = { 'L': ati('legacy', 'std', False,'p2pkh', 'p2pkh', 'wif', (), 'Legacy uncompressed address'), diff --git a/mmgen/seed.py b/mmgen/seed.py index 6ab25ee6..f1b1c90b 100755 --- a/mmgen/seed.py +++ b/mmgen/seed.py @@ -51,8 +51,8 @@ def is_mmgen_mnemonic(s): return _is_mnemonic(s,fmt='words') class SeedBase(MMGenObject): - data = MMGenImmutableAttr('data',bytes,typeconv=False) - sid = MMGenImmutableAttr('sid',SeedID,typeconv=False) + data = ImmutableAttr(bytes,typeconv=False) + sid = ImmutableAttr(SeedID,typeconv=False) def __init__(self,seed_bin=None): if not seed_bin: @@ -262,9 +262,9 @@ class Seed(SeedBase): class SubSeed(SeedBase): - idx = MMGenImmutableAttr('idx',int,typeconv=False) - nonce = MMGenImmutableAttr('nonce',int,typeconv=False) - ss_idx = MMGenImmutableAttr('ss_idx',SubSeedIdx) + idx = ImmutableAttr(int,typeconv=False) + nonce = ImmutableAttr(int,typeconv=False) + ss_idx = ImmutableAttr(SubSeedIdx) max_nonce = 1000 def __init__(self,parent_list,idx,nonce,length): @@ -286,8 +286,8 @@ class SeedShareList(SubSeedList): have_short = False split_type = 'N-of-N' - count = MMGenImmutableAttr('count',SeedShareCount) - id_str = MMGenImmutableAttr('id_str',SeedSplitIDString) + count = ImmutableAttr(SeedShareCount) + id_str = ImmutableAttr(SeedSplitIDString) def __init__(self,parent_seed,count,id_str=None,master_idx=None,debug_last_share=False): self.member_type = SeedShare @@ -429,7 +429,7 @@ class SeedShare(SeedShareBase,SubSeed): class SeedShareLast(SeedShareBase,SeedBase): - idx = MMGenImmutableAttr('idx',SeedShareIdx) + idx = ImmutableAttr(SeedShareIdx) nonce = 0 def __init__(self,parent_list): @@ -450,8 +450,8 @@ class SeedShareLast(SeedShareBase,SeedBase): class SeedShareMaster(SeedBase,SeedShareBase): - idx = MMGenImmutableAttr('idx',MasterShareIdx) - nonce = MMGenImmutableAttr('nonce',int,typeconv=False) + idx = ImmutableAttr(MasterShareIdx) + nonce = ImmutableAttr(int,typeconv=False) def __init__(self,parent_list,idx,nonce): self.idx = idx @@ -488,8 +488,8 @@ class SeedShareMaster(SeedBase,SeedShareBase): class SeedShareMasterJoining(SeedShareMaster): - id_str = MMGenImmutableAttr('id_str',SeedSplitIDString) - count = MMGenImmutableAttr('count',SeedShareCount) + id_str = ImmutableAttr(SeedSplitIDString) + count = ImmutableAttr(SeedShareCount) def __init__(self,idx,base_seed,id_str,count): SeedBase.__init__(self,seed_bin=base_seed.data) diff --git a/mmgen/tw.py b/mmgen/tw.py index 4d0f0439..08981987 100755 --- a/mmgen/tw.py +++ b/mmgen/tw.py @@ -98,17 +98,17 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, add [l]abel: class MMGenTwOutputList(list,MMGenObject): pass class MMGenTwUnspentOutput(MMGenListItem): - txid = MMGenListItemAttr('txid','CoinTxID') - vout = MMGenListItemAttr('vout',int,typeconv=False) - amt = MMGenImmutableAttr('amt',lambda:g.proto.coin_amt,typeconv=False) - amt2 = MMGenListItemAttr('amt2',lambda:g.proto.coin_amt,typeconv=False) - label = MMGenListItemAttr('label','TwComment',reassign_ok=True) - twmmid = MMGenImmutableAttr('twmmid','TwMMGenID') - addr = MMGenImmutableAttr('addr','CoinAddr') - confs = MMGenImmutableAttr('confs',int,typeconv=False) - date = MMGenListItemAttr('date',int,typeconv=False,reassign_ok=True) - scriptPubKey = MMGenImmutableAttr('scriptPubKey','HexStr') - skip = MMGenListItemAttr('skip',str,typeconv=False,reassign_ok=True) + txid = ListItemAttr('CoinTxID') + vout = ListItemAttr(int,typeconv=False) + amt = ImmutableAttr(lambda:g.proto.coin_amt,typeconv=False) + amt2 = ListItemAttr(lambda:g.proto.coin_amt,typeconv=False) + label = ListItemAttr('TwComment',reassign_ok=True) + twmmid = ImmutableAttr('TwMMGenID') + addr = ImmutableAttr('CoinAddr') + confs = ImmutableAttr(int,typeconv=False) + date = ListItemAttr(int,typeconv=False,reassign_ok=True) + scriptPubKey = ImmutableAttr('HexStr') + skip = ListItemAttr(str,typeconv=False,reassign_ok=True) wmsg = { 'no_spendable_outputs': """ diff --git a/mmgen/tx.py b/mmgen/tx.py index 2cc0dfaf..532d3bc0 100755 --- a/mmgen/tx.py +++ b/mmgen/tx.py @@ -221,23 +221,23 @@ class DeserializedTX(dict,MMGenObject): dict.__init__(self,d) class MMGenTxIO(MMGenListItem): - vout = MMGenListItemAttr('vout',int,typeconv=False) - amt = MMGenImmutableAttr('amt',lambda:g.proto.coin_amt,typeconv=False) - label = MMGenListItemAttr('label','TwComment',reassign_ok=True) - mmid = MMGenListItemAttr('mmid','MMGenID') - addr = MMGenImmutableAttr('addr','CoinAddr') - confs = MMGenListItemAttr('confs',int,typeconv=True) # confs of type long exist in the wild, so convert - txid = MMGenListItemAttr('txid','CoinTxID') - have_wif = MMGenListItemAttr('have_wif',bool,typeconv=False,delete_ok=True) + vout = ListItemAttr(int,typeconv=False) + amt = ImmutableAttr(lambda:g.proto.coin_amt,typeconv=False) + label = ListItemAttr('TwComment',reassign_ok=True) + mmid = ListItemAttr('MMGenID') + addr = ImmutableAttr('CoinAddr') + confs = ListItemAttr(int,typeconv=True) # confs of type long exist in the wild, so convert + txid = ListItemAttr('CoinTxID') + have_wif = ListItemAttr(bool,typeconv=False,delete_ok=True) class MMGenTxInput(MMGenTxIO): - scriptPubKey = MMGenListItemAttr('scriptPubKey','HexStr') - sequence = MMGenListItemAttr('sequence',int,typeconv=False) + scriptPubKey = ListItemAttr('HexStr') + sequence = ListItemAttr(int,typeconv=False) # required by copy_inputs_from_tw() copy_attrs = { 'scriptPubKey','vout','amt','label','mmid','addr','confs','txid' } class MMGenTxOutput(MMGenTxIO): - is_chg = MMGenListItemAttr('is_chg',bool,typeconv=False) + is_chg = ListItemAttr(bool,typeconv=False) class MMGenTxInputList(list,MMGenObject): diff --git a/test/objattrtest.py b/test/objattrtest.py index 0c20f18e..cc211fbf 100755 --- a/test/objattrtest.py +++ b/test/objattrtest.py @@ -82,8 +82,8 @@ def test_attr_perm(obj,attrname,perm_name,perm_value,dobj,attrval_type): so = sample_objs[attrval_type.__name__] except: raise SampleObjError('unable to find sample object of type {!r}'.format(attrval_type.__name__)) - # MMGenListItemAttr allows setting an attribute if its value is None - if type(dobj) == MMGenListItemAttr and getattr(obj,attrname) == None: + # ListItemAttr allows setting an attribute if its value is None + if type(dobj) == ListItemAttr and getattr(obj,attrname) == None: setattr(obj,attrname,so) setattr(obj,attrname,so) elif perm_name == 'delete_ok':