MMGenImmutableAttr: allow callable dtype arg, remove 'no_type_check' option

This commit is contained in:
The MMGen Project 2019-10-19 17:27:24 +00:00
commit 174caeebd3
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
7 changed files with 17 additions and 31 deletions

View file

@ -298,8 +298,8 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view,
class MMGenTwUnspentOutput(MMGenListItem):
txid = MMGenListItemAttr('txid','CoinTxID')
vout = MMGenListItemAttr('vout',int,typeconv=False)
amt = MMGenImmutableAttr('amt',g.proto.coin_amt.__name__)
amt2 = MMGenListItemAttr('amt2',g.proto.coin_amt.__name__)
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')

View file

@ -278,7 +278,7 @@ def print_summary(signed_txs):
msg(fs.format(
tx.txid.fmt(width=t_wid,color=True) if nm is non_mmgen[0] else ' '*t_wid,
nm.addr.fmt(width=a_wid,color=True),
nm._amt.hl() + ' ' + yellow(tx.coin)))
nm.amt.hl() + ' ' + yellow(tx.coin)))
else:
msg('No non-MMGen outputs')

View file

@ -187,11 +187,12 @@ class Int(int,Hilite): pass
# Reassignment and deletion forbidden
class MMGenImmutableAttr(object): # Descriptor
def __init__(self,name,dtype,typeconv=True,no_type_check=False,set_none_ok=False):
ok_dtypes = (str,type,type(None),type(lambda:0))
def __init__(self,name,dtype,typeconv=True,set_none_ok=False):
self.typeconv = typeconv
self.no_type_check = no_type_check
self.set_none_ok = set_none_ok
assert isinstance(dtype,(str,type,type(None))),'{!r}: invalid dtype arg'.format(dtype)
assert isinstance(dtype,self.ok_dtypes),'{!r}: invalid dtype arg'.format(dtype)
self.name = name
self.dtype = dtype
@ -201,7 +202,6 @@ class MMGenImmutableAttr(object): # Descriptor
# forbid all reassignment
def set_attr_ok(self,instance):
return not self.name in instance.__dict__
# return not hasattr(instance,self.name)
def __set__(self,instance,value):
if not self.set_attr_ok(instance):
@ -212,8 +212,10 @@ class MMGenImmutableAttr(object): # Descriptor
elif self.typeconv: # convert type
instance.__dict__[self.name] = \
globals()[self.dtype](value,on_fail='raise') if type(self.dtype) == str else self.dtype(value)
else: # check type
if type(value) == self.dtype or self.no_type_check:
else: # check type
if type(value) == self.dtype:
instance.__dict__[self.name] = value
elif callable(self.dtype) and type(value) == self.dtype():
instance.__dict__[self.name] = value
else:
m = "Attribute '{}' of {} instance must of type {}"

View file

@ -63,8 +63,8 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, add [l]abel:
class MMGenTwUnspentOutput(MMGenListItem):
txid = MMGenListItemAttr('txid','CoinTxID')
vout = MMGenListItemAttr('vout',int,typeconv=False)
amt = MMGenImmutableAttr('amt',g.proto.coin_amt.__name__)
amt2 = MMGenListItemAttr('amt2',g.proto.coin_amt.__name__)
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')

View file

@ -220,7 +220,7 @@ class DeserializedTX(dict,MMGenObject):
class MMGenTxIO(MMGenListItem):
vout = MMGenListItemAttr('vout',int,typeconv=False)
_amt = MMGenImmutableAttr('amt',None,no_type_check=True,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')
@ -228,22 +228,6 @@ class MMGenTxIO(MMGenListItem):
txid = MMGenListItemAttr('txid','CoinTxID')
have_wif = MMGenListItemAttr('have_wif',bool,typeconv=False,delete_ok=True)
valid_attrs_extra = {'amt'}
# Setting self.amt is runtime-dependent, so make it a property
# Make underlying self._amt an MMGenImmutableAttr to prevent reassignment
@property
def amt(self):
if type(self._amt) != g.proto.coin_amt:
raise ValueError('{}: invalid coin_amt type (must be {})'.format(type(self._amt),g.proto.coin_amt))
return self._amt
@amt.setter
def amt(self,val):
if type(val) != g.proto.coin_amt:
raise ValueError('{}: invalid coin_amt type (must be {})'.format(type(val),g.proto.coin_amt))
self._amt = val
class MMGenTxInput(MMGenTxIO):
scriptPubKey = MMGenListItemAttr('scriptPubKey','HexStr')
sequence = MMGenListItemAttr('sequence',int,typeconv=False)

View file

@ -51,8 +51,6 @@ opts_data = {
}
cmd_args = opts.init(opts_data)
init_coin(g.coin)
from mmgen.tw import *
pd = namedtuple('permission_bits', ['read_ok','delete_ok','reassign_ok'])
@ -121,7 +119,7 @@ def test_attr(data,obj,attrname,dobj,bits,attrval_type):
msg_r(' {}={!r}'.format(k,d[k]))
if opt.show_nonstandard_init:
for k,v in (('typeconv',False),('no_type_check',True),('set_none_ok',True)):
for k,v in (('typeconv',False),('set_none_ok',True)):
if d[k] == v:
msg_r(' {}={}'.format(k,v))
@ -161,4 +159,5 @@ def do_loop():
msg(clr('Testing {}'.format(obj)))
test_object(test_data,obj)
init_coin(g.coin)
do_loop()

View file

@ -15,6 +15,7 @@ from mmgen.seed import *
from mmgen.protocol import *
from mmgen.addr import *
from mmgen.tx import *
from mmgen.tw import *
from collections import namedtuple
atd = namedtuple('attrtest_entry',['attrs','args','kwargs'])