move Hilite,InitErrors to objmethods.py

This commit is contained in:
The MMGen Project 2022-01-15 14:00:07 +00:00
commit 74ec5efd63
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
8 changed files with 140 additions and 107 deletions

View file

@ -23,6 +23,7 @@ addr.py: Address generation/display routines for the MMGen suite
from hashlib import sha256,sha512
from .common import *
from .base_obj import AsyncInit
from .objmethods import Hilite,InitErrors,MMGenObject
from .obj import *
from .baseconv import *
from .protocol import init_proto,hash160

View file

@ -21,7 +21,7 @@ amt.py: MMGen CoinAmt and related classes
"""
from decimal import Decimal
from .obj import Hilite,InitErrors
from .objmethods import Hilite,InitErrors
class UnknownCoinAmt(Decimal): pass

View file

@ -27,6 +27,7 @@ from string import hexdigits,ascii_letters,digits
from .exception import *
from .globalvars import *
from .color import *
from .objmethods import *
def get_obj(objname,*args,**kwargs):
"""
@ -63,17 +64,6 @@ def is_mmgen_id(proto,s): return get_obj(MMGenID, proto=proto, id_str=s, silen
def is_coin_addr(proto,s): return get_obj(CoinAddr, proto=proto, addr=s, silent=True,return_bool=True)
def is_wif(proto,s): return get_obj(WifKey, proto=proto, wif=s, silent=True,return_bool=True)
def truncate_str(s,width): # width = screen width
wide_count = 0
for i in range(len(s)):
wide_count += unicodedata.east_asian_width(s[i]) in ('F','W')
if wide_count + i >= width:
return s[:i] + ('',' ')[
unicodedata.east_asian_width(s[i]) in ('F','W')
and wide_count + i == width]
else: # pad the string to width if necessary
return s + ' '*(width-len(s)-wide_count)
# dict that keeps a list of keys for efficient lookup by index
class IndexedDict(dict):
@ -108,99 +98,6 @@ class MMGenList(list,MMGenObject): pass
class MMGenDict(dict,MMGenObject): pass
class AddrListData(list,MMGenObject): pass
class InitErrors:
@classmethod
def init_fail(cls,e,m,e2=None,m2=None,objname=None,preformat=False):
if preformat:
errmsg = m
else:
errmsg = '{!r}: value cannot be converted to {} {}({!s})'.format(
m,
(objname or cls.__name__),
(f'({e2!s}) ' if e2 else ''),
e )
if m2:
errmsg = repr(m2) + '\n' + errmsg
if hasattr(cls,'passthru_excs') and type(e) in cls.passthru_excs:
raise
elif hasattr(cls,'exc'):
raise cls.exc(errmsg)
else:
raise ObjectInitError(errmsg)
@classmethod
def method_not_implemented(cls):
import traceback
raise NotImplementedError(
'method {}() not implemented for class {!r}'.format(
traceback.extract_stack()[-2].name, cls.__name__) )
class Hilite(object):
color = 'red'
width = 0
trunc_ok = True
@classmethod
# 'width' is screen width (greater than len(s) for CJK strings)
# 'append_chars' and 'encl' must consist of single-width chars only
def fmtc(cls,s,width=None,color=False,encl='',trunc_ok=None,
center=False,nullrepl='',append_chars='',append_color=False):
s_wide_count = len([1 for ch in s if unicodedata.east_asian_width(ch) in ('F','W')])
if encl:
a,b = list(encl)
add_len = len(append_chars) + 2
else:
a,b = ('','')
add_len = len(append_chars)
if width == None:
width = cls.width
if trunc_ok == None:
trunc_ok = cls.trunc_ok
if g.test_suite:
assert isinstance(encl,str) and len(encl) in (0,2),"'encl' must be 2-character str"
assert width >= 2 + add_len, f'{s!r}: invalid width ({width}) (must be at least 2)' # CJK: 2 cells
if len(s) + s_wide_count + add_len > width:
assert trunc_ok, "If 'trunc_ok' is false, 'width' must be >= screen width of string"
s = truncate_str(s,width-add_len)
if s == '' and nullrepl:
s = nullrepl.center(width)
else:
s = a+s+b
if center:
s = s.center(width)
if append_chars:
return (
cls.colorize(s,color=color)
+ cls.colorize(
append_chars.ljust(width-len(s)-s_wide_count),
color_override = append_color ))
else:
return cls.colorize(s.ljust(width-s_wide_count),color=color)
@classmethod
def colorize(cls,s,color=True,color_override=''):
return globals()[color_override or cls.color](s) if color else s
def fmt(self,*args,**kwargs):
assert args == () # forbid invocation w/o keywords
return self.fmtc(self,*args,**kwargs)
@classmethod
def hlc(cls,s,color=True,encl=''):
if encl:
assert isinstance(encl,str) and len(encl) == 2, "'encl' must be 2-character str"
s = encl[0] + s + encl[1]
return cls.colorize(s,color=color)
def hl(self,*args,**kwargs):
assert args == () # forbid invocation w/o keywords
return self.hlc(self,*args,**kwargs)
class Str(str,Hilite): pass
class Int(int,Hilite,InitErrors):

131
mmgen/objmethods.py Executable file
View file

@ -0,0 +1,131 @@
#!/usr/bin/env python3
#
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
# Copyright (C)2013-2022 The MMGen Project <mmgen@tuta.io>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
objmethods.py: Mixin classes for MMGen data objects
"""
import unicodedata
from .color import *
from .globalvars import g
from .devtools import *
def truncate_str(s,width): # width = screen width
wide_count = 0
for i in range(len(s)):
wide_count += unicodedata.east_asian_width(s[i]) in ('F','W')
if wide_count + i >= width:
return s[:i] + ('',' ')[
unicodedata.east_asian_width(s[i]) in ('F','W')
and wide_count + i == width]
else: # pad the string to width if necessary
return s + ' '*(width-len(s)-wide_count)
class Hilite:
color = 'red'
width = 0
trunc_ok = True
@classmethod
# 'width' is screen width (greater than len(s) for CJK strings)
# 'append_chars' and 'encl' must consist of single-width chars only
def fmtc(cls,s,width=None,color=False,encl='',trunc_ok=None,
center=False,nullrepl='',append_chars='',append_color=False):
s_wide_count = len([1 for ch in s if unicodedata.east_asian_width(ch) in ('F','W')])
if encl:
a,b = list(encl)
add_len = len(append_chars) + 2
else:
a,b = ('','')
add_len = len(append_chars)
if width == None:
width = cls.width
if trunc_ok == None:
trunc_ok = cls.trunc_ok
if g.test_suite:
assert isinstance(encl,str) and len(encl) in (0,2),"'encl' must be 2-character str"
assert width >= 2 + add_len, f'{s!r}: invalid width ({width}) (must be at least 2)' # CJK: 2 cells
if len(s) + s_wide_count + add_len > width:
assert trunc_ok, "If 'trunc_ok' is false, 'width' must be >= screen width of string"
s = truncate_str(s,width-add_len)
if s == '' and nullrepl:
s = nullrepl.center(width)
else:
s = a+s+b
if center:
s = s.center(width)
if append_chars:
return (
cls.colorize(s,color=color)
+ cls.colorize(
append_chars.ljust(width-len(s)-s_wide_count),
color_override = append_color ))
else:
return cls.colorize(s.ljust(width-s_wide_count),color=color)
@classmethod
def colorize(cls,s,color=True,color_override=''):
return globals()[color_override or cls.color](s) if color else s
def fmt(self,*args,**kwargs):
assert args == () # forbid invocation w/o keywords
return self.fmtc(self,*args,**kwargs)
@classmethod
def hlc(cls,s,color=True,encl=''):
if encl:
assert isinstance(encl,str) and len(encl) == 2, "'encl' must be 2-character str"
s = encl[0] + s + encl[1]
return cls.colorize(s,color=color)
def hl(self,*args,**kwargs):
assert args == () # forbid invocation w/o keywords
return self.hlc(self,*args,**kwargs)
class InitErrors:
@classmethod
def init_fail(cls,e,m,e2=None,m2=None,objname=None,preformat=False):
if preformat:
errmsg = m
else:
errmsg = '{!r}: value cannot be converted to {} {}({!s})'.format(
m,
(objname or cls.__name__),
(f'({e2!s}) ' if e2 else ''),
e )
if m2:
errmsg = repr(m2) + '\n' + errmsg
if hasattr(cls,'passthru_excs') and type(e) in cls.passthru_excs:
raise
elif hasattr(cls,'exc'):
raise cls.exc(errmsg)
else:
from .exception import ObjectInitError
raise ObjectInitError(errmsg)
@classmethod
def method_not_implemented(cls):
import traceback
raise NotImplementedError(
'method {}() not implemented for class {!r}'.format(
traceback.extract_stack()[-2].name, cls.__name__) )

View file

@ -23,6 +23,7 @@ rpc.py: Cryptocoin RPC library for the MMGen suite
import base64,json,asyncio
from decimal import Decimal
from .common import *
from .objmethods import Hilite,InitErrors
from .base_obj import AsyncInit
rpc_credentials_msg = '\n'+fmt("""

View file

@ -21,7 +21,8 @@ seed.py: Seed-related classes and methods for the MMGen suite
"""
from .common import *
from .obj import *
from .objmethods import Hilite,InitErrors
from .obj import ImmutableAttr,get_obj
from .crypto import get_random,scramble_seed
class SeedID(str,Hilite,InitErrors):

View file

@ -25,6 +25,7 @@ from collections import namedtuple
from .exception import *
from .common import *
from .base_obj import AsyncInit
from .objmethods import Hilite,InitErrors,MMGenObject
from .obj import *
from .tx import is_mmgen_id,is_coin_addr
from .rpc import rpc_init

View file

@ -23,12 +23,13 @@ xmrwallet.py - MoneroWalletOps class
import os,re,time,json
from collections import namedtuple
from .common import *
from .objmethods import Hilite,InitErrors
from .addr import KeyAddrList,AddrIdxList
from .rpc import MoneroRPCClientRaw,MoneroWalletRPCClient,json_encoder
from .seed import SeedID
from .daemon import MoneroWalletDaemon
from .protocol import _b58a,init_proto
from .obj import CoinAddr,CoinTxID,AddrIdx,Hilite,InitErrors
from .obj import CoinAddr,CoinTxID,AddrIdx
xmrwallet_uarg_info = (
lambda e,hp: {