Browse Source

move Hilite,InitErrors to objmethods.py

The MMGen Project 3 years ago
parent
commit
74ec5efd63
8 changed files with 140 additions and 107 deletions
  1. 1 0
      mmgen/addr.py
  2. 1 1
      mmgen/amt.py
  3. 1 104
      mmgen/obj.py
  4. 131 0
      mmgen/objmethods.py
  5. 1 0
      mmgen/rpc.py
  6. 2 1
      mmgen/seed.py
  7. 1 0
      mmgen/tw.py
  8. 2 1
      mmgen/xmrwallet.py

+ 1 - 0
mmgen/addr.py

@@ -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

+ 1 - 1
mmgen/amt.py

@@ -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
 

+ 1 - 104
mmgen/obj.py

@@ -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 - 0
mmgen/objmethods.py

@@ -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__) )

+ 1 - 0
mmgen/rpc.py

@@ -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("""

+ 2 - 1
mmgen/seed.py

@@ -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):

+ 1 - 0
mmgen/tw.py

@@ -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

+ 2 - 1
mmgen/xmrwallet.py

@@ -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: {