immutable attr improvements
This commit is contained in:
parent
52fdf29b67
commit
aae5f122b4
5 changed files with 58 additions and 69 deletions
|
|
@ -91,18 +91,16 @@ class KeyGeneratorSecp256k1(KeyGenerator):
|
|||
return PubKey(hexlify(priv2pub(unhexlify(privhex),int(privhex.compressed))),compressed=privhex.compressed)
|
||||
|
||||
class AddrListEntry(MMGenListItem):
|
||||
reassign_ok = 'label',
|
||||
addr = MMGenListItemAttr('addr','BTCAddr')
|
||||
idx = MMGenListItemAttr('idx','AddrIdx')
|
||||
label = MMGenListItemAttr('label','TwComment')
|
||||
sec = MMGenImmutableAttr('sec',PrivKey)
|
||||
idx = MMGenImmutableAttr('idx','AddrIdx')
|
||||
label = MMGenListItemAttr('label','TwComment',reassign_ok=True)
|
||||
sec = MMGenListItemAttr('sec',PrivKey,typeconv=False)
|
||||
|
||||
class PasswordListEntry(MMGenListItem):
|
||||
reassign_ok = 'label',
|
||||
passwd = MMGenImmutableAttr('passwd',unicode) # TODO: create Password type
|
||||
idx = MMGenListItemAttr('idx','AddrIdx')
|
||||
label = MMGenListItemAttr('label','TwComment')
|
||||
sec = MMGenImmutableAttr('sec',PrivKey)
|
||||
passwd = MMGenImmutableAttr('passwd',unicode,typeconv=False) # TODO: create Password type
|
||||
idx = MMGenImmutableAttr('idx','AddrIdx')
|
||||
label = MMGenListItemAttr('label','TwComment',reassign_ok=True)
|
||||
sec = MMGenListItemAttr('sec',PrivKey,typeconv=False)
|
||||
|
||||
class AddrListChksum(str,Hilite):
|
||||
color = 'pink'
|
||||
|
|
|
|||
70
mmgen/obj.py
70
mmgen/obj.py
|
|
@ -101,19 +101,13 @@ class MMGenObject(object):
|
|||
class MMGenList(list,MMGenObject): pass
|
||||
class MMGenDict(dict,MMGenObject): pass
|
||||
|
||||
# for attrs that are always present in the data instance
|
||||
# reassignment and deletion forbidden
|
||||
class MMGenImmutableAttr(object): # Descriptor
|
||||
|
||||
typeconv = False
|
||||
builtin_typeconv = False
|
||||
|
||||
def __init__(self,name,dtype,typeconv=None,builtin_typeconv=None):
|
||||
if typeconv is not None:
|
||||
assert typeconv in (True,False)
|
||||
self.typeconv = typeconv
|
||||
if builtin_typeconv is not None:
|
||||
assert builtin_typeconv
|
||||
self.builtin_typeconv = builtin_typeconv
|
||||
self.typeconv = False # override
|
||||
def __init__(self,name,dtype,typeconv=True):
|
||||
self.typeconv = typeconv
|
||||
assert type(dtype) in (str,type)
|
||||
self.name = name
|
||||
self.dtype = dtype
|
||||
|
||||
|
|
@ -121,17 +115,16 @@ class MMGenImmutableAttr(object): # Descriptor
|
|||
return instance.__dict__[self.name]
|
||||
|
||||
# forbid all reassignment
|
||||
def chk_ok_set_attr(self,instance):
|
||||
if hasattr(instance,self.name):
|
||||
m = "Attribute '{}' of {} instance cannot be reassigned"
|
||||
raise AttributeError(m.format(self.name,type(instance)))
|
||||
def set_attr_ok(self,instance):
|
||||
return not hasattr(instance,self.name)
|
||||
|
||||
def __set__(self,instance,value):
|
||||
self.chk_ok_set_attr(instance)
|
||||
if not self.set_attr_ok(instance):
|
||||
m = "Attribute '{}' of {} instance cannot be reassigned"
|
||||
raise AttributeError(m.format(self.name,type(instance)))
|
||||
if self.typeconv: # convert type
|
||||
instance.__dict__[self.name] = globals()[self.dtype](value)
|
||||
elif self.builtin_typeconv:
|
||||
instance.__dict__[self.name] = self.dtype(value)
|
||||
instance.__dict__[self.name] = \
|
||||
globals()[self.dtype](value) if type(self.dtype) == str else self.dtype(value)
|
||||
else: # check type
|
||||
if type(value) != self.dtype:
|
||||
m = "Attribute '{}' of {} instance must of type {}"
|
||||
|
|
@ -139,36 +132,35 @@ class MMGenImmutableAttr(object): # Descriptor
|
|||
instance.__dict__[self.name] = value
|
||||
|
||||
def __delete__(self,instance):
|
||||
if self.name in instance.delete_ok:
|
||||
if self.name in instance.__dict__:
|
||||
del instance.__dict__[self.name]
|
||||
else:
|
||||
m = "Atribute '{}' of {} instance cannot be deleted"
|
||||
raise AttributeError(m.format(self.name,type(instance)))
|
||||
m = "Atribute '{}' of {} instance cannot be deleted"
|
||||
raise AttributeError(m.format(self.name,type(instance)))
|
||||
|
||||
# for attrs that might not be present in the data instance
|
||||
# reassignment or deletion allowed if specified
|
||||
class MMGenListItemAttr(MMGenImmutableAttr):
|
||||
|
||||
typeconv = True
|
||||
builtin_typeconv = False
|
||||
def __init__(self,name,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)
|
||||
|
||||
# return None if attribute doesn't exist
|
||||
def __get__(self,instance,owner):
|
||||
try: return instance.__dict__[self.name]
|
||||
except: return None
|
||||
|
||||
# allow reassignment if value is None or attr in reassign_ok list
|
||||
def chk_ok_set_attr(self,instance):
|
||||
if hasattr(instance,self.name) and not (
|
||||
getattr(instance,self.name) == None or self.name in instance.reassign_ok
|
||||
):
|
||||
m = "Attribute '{}' of {} instance cannot be reassigned"
|
||||
raise AttributeError(m.format(self.name,type(instance)))
|
||||
def set_attr_ok(self,instance):
|
||||
return getattr(instance,self.name) == None or self.reassign_ok
|
||||
|
||||
def __delete__(self,instance):
|
||||
if self.delete_ok:
|
||||
if self.name in instance.__dict__:
|
||||
del instance.__dict__[self.name]
|
||||
else:
|
||||
MMGenImmutableAttr.__delete__(self,instance)
|
||||
|
||||
class MMGenListItem(MMGenObject):
|
||||
|
||||
reassign_ok = ()
|
||||
delete_ok = ()
|
||||
|
||||
def __init__(self,*args,**kwargs):
|
||||
if args:
|
||||
raise ValueError, 'Non-keyword args not allowed'
|
||||
|
|
@ -576,8 +568,8 @@ class PrivKey(str,Hilite,InitErrors,MMGenObject):
|
|||
width = 64
|
||||
trunc_ok = False
|
||||
|
||||
compressed = MMGenImmutableAttr('compressed',bool)
|
||||
wif = MMGenImmutableAttr('wif',WifKey)
|
||||
compressed = MMGenImmutableAttr('compressed',bool,typeconv=False)
|
||||
wif = MMGenImmutableAttr('wif',WifKey,typeconv=False)
|
||||
|
||||
def __new__(*args,**kwargs): # initialize with (priv_bin,compressed), WIF or self
|
||||
cls = args[0]
|
||||
|
|
|
|||
19
mmgen/tw.py
19
mmgen/tw.py
|
|
@ -40,17 +40,16 @@ class MMGenTrackingWallet(MMGenObject):
|
|||
|
||||
class MMGenTwUnspentOutput(MMGenListItem):
|
||||
# attrs = 'txid','vout','amt','label','twmmid','addr','confs','scriptPubKey','days','skip'
|
||||
reassign_ok = 'label','skip'
|
||||
txid = MMGenListItemAttr('txid','BitcoinTxID')
|
||||
vout = MMGenListItemAttr('vout',int,typeconv=False),
|
||||
amt = MMGenListItemAttr('amt','BTCAmt'),
|
||||
label = MMGenListItemAttr('label','TwComment'),
|
||||
twmmid = MMGenListItemAttr('twmmid','TwMMGenID')
|
||||
addr = MMGenListItemAttr('addr','BTCAddr'),
|
||||
confs = MMGenListItemAttr('confs',int,typeconv=False),
|
||||
scriptPubKey = MMGenListItemAttr('scriptPubKey','HexStr')
|
||||
txid = MMGenImmutableAttr('txid','BitcoinTxID')
|
||||
vout = MMGenImmutableAttr('vout',int,typeconv=False),
|
||||
amt = MMGenImmutableAttr('amt','BTCAmt'),
|
||||
label = MMGenListItemAttr('label','TwComment',reassign_ok=True),
|
||||
twmmid = MMGenImmutableAttr('twmmid','TwMMGenID')
|
||||
addr = MMGenImmutableAttr('addr','BTCAddr'),
|
||||
confs = MMGenImmutableAttr('confs',int,typeconv=False),
|
||||
scriptPubKey = MMGenImmutableAttr('scriptPubKey','HexStr')
|
||||
days = MMGenListItemAttr('days',int,typeconv=False),
|
||||
skip = MMGenListItemAttr('skip',bool,typeconv=False),
|
||||
skip = MMGenListItemAttr('skip',bool,typeconv=False,reassign_ok=True),
|
||||
|
||||
wmsg = {
|
||||
'no_spendable_outputs': """
|
||||
|
|
|
|||
12
mmgen/tx.py
12
mmgen/tx.py
|
|
@ -114,16 +114,14 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types
|
|||
return OrderedDict.__init__(self, ((k,d[k]) for k in keys))
|
||||
|
||||
txio_attrs = {
|
||||
'reassign_ok': ('label',),
|
||||
'delete_ok': ('have_wif',),
|
||||
'vout': MMGenListItemAttr('vout',int,typeconv=False),
|
||||
'amt': MMGenListItemAttr('amt','BTCAmt'),
|
||||
'label': MMGenListItemAttr('label','TwComment'),
|
||||
'amt': MMGenImmutableAttr('amt','BTCAmt'),
|
||||
'label': MMGenListItemAttr('label','TwComment',reassign_ok=True),
|
||||
'mmid': MMGenListItemAttr('mmid','MMGenID'),
|
||||
'addr': MMGenListItemAttr('addr','BTCAddr'),
|
||||
'confs': MMGenListItemAttr('confs',int,builtin_typeconv=True), # long confs found in the wild, so convert
|
||||
'addr': MMGenImmutableAttr('addr','BTCAddr'),
|
||||
'confs': MMGenListItemAttr('confs',int,typeconv=True), # long confs exist in the wild, so convert
|
||||
'txid': MMGenListItemAttr('txid','BitcoinTxID'),
|
||||
'have_wif': MMGenListItemAttr('have_wif',bool,typeconv=False)
|
||||
'have_wif': MMGenListItemAttr('have_wif',bool,typeconv=False,delete_ok=True)
|
||||
}
|
||||
|
||||
class MMGenTX(MMGenObject):
|
||||
|
|
|
|||
|
|
@ -235,13 +235,15 @@ class MMGenToolTestSuite(object):
|
|||
die(1,red('Called process returned with an error (retcode %s)' % retcode))
|
||||
return (a,a.rstrip())[bool(strip)]
|
||||
|
||||
def run_cmd_chk(self,name,f1,f2,kwargs='',extra_msg=''):
|
||||
def run_cmd_chk(self,name,f1,f2,kwargs='',extra_msg='',strip_hex=False):
|
||||
idata = read_from_file(f1).rstrip()
|
||||
odata = read_from_file(f2).rstrip()
|
||||
ret = self.run_cmd(name,[odata],kwargs=kwargs,extra_msg=extra_msg)
|
||||
vmsg('In: ' + repr(odata))
|
||||
vmsg('Out: ' + repr(ret))
|
||||
if ret == idata: ok()
|
||||
def cmp_equal(a,b):
|
||||
return (a.lstrip('0') == b.lstrip('0')) if strip_hex else (a == b)
|
||||
if cmp_equal(ret,idata): ok()
|
||||
else:
|
||||
die(3,red(
|
||||
"Error: values don't match:\nIn: %s\nOut: %s" % (repr(idata),repr(ret))))
|
||||
|
|
@ -284,12 +286,12 @@ class MMGenToolTestSuite(object):
|
|||
def Strtob58(self,name): self.run_cmd_out(name,getrandstr(16))
|
||||
def B58tostr(self,name,f1,f2): self.run_cmd_chk(name,f1,f2)
|
||||
def Hextob58(self,name): self.run_cmd_out(name,getrandhex(32))
|
||||
def B58tohex(self,name,f1,f2): self.run_cmd_chk(name,f1,f2)
|
||||
def B58tohex(self,name,f1,f2): self.run_cmd_chk(name,f1,f2,strip_hex=True)
|
||||
def B58randenc(self,name):
|
||||
ret = self.run_cmd_out(name,Return=True)
|
||||
ok_or_die(ret,is_b58_str,'base 58 string')
|
||||
def Hextob32(self,name): self.run_cmd_out(name,getrandhex(24))
|
||||
def B32tohex(self,name,f1,f2): self.run_cmd_chk(name,f1,f2)
|
||||
def B32tohex(self,name,f1,f2): self.run_cmd_chk(name,f1,f2,strip_hex=True)
|
||||
def Randhex(self,name):
|
||||
ret = self.run_cmd_out(name,Return=True)
|
||||
ok_or_die(ret,binascii.unhexlify,'hex string')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue