Browse Source

new file: devtools.py

MMGen 5 years ago
parent
commit
85d3336a9e
6 changed files with 114 additions and 77 deletions
  1. 1 1
      mmgen/common.py
  2. 102 0
      mmgen/devtools.py
  3. 5 0
      mmgen/globalvars.py
  4. 4 67
      mmgen/obj.py
  5. 1 9
      mmgen/util.py
  6. 1 0
      setup.py

+ 1 - 1
mmgen/common.py

@@ -22,7 +22,7 @@ common.py:  Common imports for all MMGen scripts
 
 import sys,os
 from mmgen.exception import *
-from mmgen.globalvars import g
+from mmgen.globalvars import *
 import mmgen.opts as opts
 from mmgen.opts import opt
 from mmgen.util import *

+ 102 - 0
mmgen/devtools.py

@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+
+import sys,os,pprint,traceback,re,json
+from decimal import Decimal
+from difflib import unified_diff
+
+def ppformat(d):
+	return pprint.PrettyPrinter(indent=4,compact=True).pformat(d)
+def ppmsg(*args):
+	sys.stderr.write(ppformat(args if len(args) > 1 else args[0]) + '\n')
+def PPmsg(*args):
+	sys.stdout.write(ppformat(args if len(args) > 1 else args[0]) + '\n')
+def ppdie(*args,exit_val=1):
+	sys.stderr.write(ppformat(args if len(args) > 1 else args[0]))
+	sys.exit(exit_val)
+def ppdie2(*args): ppdie(*args,exit_val=0)
+
+def print_stack_trace(message):
+	tb1 = traceback.extract_stack()
+	tb2 = [t for t in tb1 if t.filename[:1] != '<'][2:-2]
+	sys.stderr.write('STACK TRACE {}:\n'.format(message))
+	fs = '    {}:{}: in {}:\n        {}\n'
+	for t in tb2:
+		fn = re.sub(r'^\./','',os.path.relpath(t.filename))
+		func = t.name+'()' if t.name[-1] != '>' else t.name
+		sys.stderr.write(fs.format(fn,t.lineno,func,t.line or '(none)'))
+
+class MMGenObject(object):
+
+	# Pretty-print any object subclassed from MMGenObject, recursing into sub-objects - WIP
+	def ppmsg(self): print(self.ppformat())
+	def ppdie(self): print(self.ppformat()); sys.exit(0)
+	def ppformat(self,lvl=0,id_list=[]):
+		scalars = (str,int,float,Decimal)
+		def do_list(out,e,lvl=0,is_dict=False):
+			out.append('\n')
+			for i in e:
+				el = i if not is_dict else e[i]
+				if is_dict:
+					out.append('{s}{:<{l}}'.format(i,s=' '*(4*lvl+8),l=10,l2=8*(lvl+1)+8))
+				if hasattr(el,'ppformat'):
+					out.append('{:>{l}}{}'.format('',el.ppformat(lvl=lvl+1,id_list=id_list+[id(self)]),l=(lvl+1)*8))
+				elif type(el) in scalars:
+					if isList(e):
+						out.append('{:>{l}}{:16}\n'.format('',repr(el),l=lvl*8))
+					else:
+						out.append(' {}'.format(repr(el)))
+				elif isList(el) or isDict(el):
+					indent = 1 if is_dict else lvl*8+4
+					out.append('{:>{l}}{:16}'.format('','<'+type(el).__name__+'>',l=indent))
+					if isList(el) and type(el[0]) in scalars: out.append('\n')
+					do_list(out,el,lvl=lvl+1,is_dict=isDict(el))
+				else:
+					out.append('{:>{l}}{:16} {}\n'.format('','<'+type(el).__name__+'>',repr(el),l=(lvl*8)+8))
+				out.append('\n')
+			if not e: out.append('{}\n'.format(repr(e)))
+
+		from collections import OrderedDict
+		def isDict(obj):
+			return issubclass(type(obj),dict) or issubclass(type(obj),OrderedDict)
+		def isList(obj):
+			return issubclass(type(obj),list) and type(obj) != OrderedDict
+		def isScalar(obj):
+			return any(issubclass(type(obj),t) for t in scalars)
+
+# 		print type(self)
+# 		print dir(self)
+# 		print self.__dict__
+# 		print self.__dict__.keys()
+# 		print self.keys()
+
+		out = ['<{}>{}\n'.format(type(self).__name__,' '+repr(self) if isScalar(self) else '')]
+		if id(self) in id_list:
+			return out[-1].rstrip() + ' [RECURSION]\n'
+		if isList(self) or isDict(self):
+			do_list(out,self,lvl=lvl,is_dict=isDict(self))
+
+#		print repr(self.__dict__.keys())
+
+		for k in self.__dict__:
+			if k in ('_OrderedDict__root','_OrderedDict__map'): continue # exclude these because of recursion
+			e = getattr(self,k)
+			if isList(e) or isDict(e):
+				out.append('{:>{l}}{:<10} {:16}'.format('',k,'<'+type(e).__name__+'>',l=(lvl*8)+4))
+				do_list(out,e,lvl=lvl,is_dict=isDict(e))
+			elif hasattr(e,'ppformat') and type(e) != type:
+				out.append('{:>{l}}{:10} {}'.format('',k,e.ppformat(lvl=lvl+1,id_list=id_list+[id(self)]),l=(lvl*8)+4))
+			else:
+				out.append('{:>{l}}{:<10} {:16} {}\n'.format(
+					'',k,'<'+type(e).__name__+'>',repr(e),l=(lvl*8)+4))
+
+		import re
+		return re.sub('\n+','\n',''.join(out))
+
+def print_diff(a,b,from_json=True):
+	if from_json:
+		a = json.dumps(json.loads(a),indent=4).split('\n') if a else []
+		b = json.dumps(json.loads(b),indent=4).split('\n') if b else []
+	else:
+		a = a.split('\n')
+		b = b.split('\n')
+	sys.stderr.write('  DIFF:\n    {}\n'.format('\n    '.join(unified_diff(a,b))))

+ 5 - 0
mmgen/globalvars.py

@@ -23,6 +23,11 @@ globalvars.py:  Constants and configuration options for the MMGen suite
 import sys,os
 from decimal import Decimal
 
+if os.getenv('MMGEN_DEBUG') or os.getenv('MMGEN_TEST_SUITE') or os.getenv('MMGEN_TRACEBACK'):
+	from mmgen.devtools import *
+else:
+	class MMGenObject(object): pass
+
 # Global vars are set to dfl values in class g.
 # They're overridden in this order:
 #   1 - config file

+ 4 - 67
mmgen/obj.py

@@ -24,6 +24,10 @@ import sys,os,unicodedata
 from decimal import *
 from string import hexdigits,ascii_letters,digits
 
+if os.getenv('MMGEN_DEBUG') or os.getenv('MMGEN_TEST_SUITE') or os.getenv('MMGEN_TRACEBACK'):
+	from mmgen.devtools import *
+else:
+	class MMGenObject(object): pass
 from mmgen.color import *
 from mmgen.exception import *
 
@@ -47,73 +51,6 @@ def truncate_str(s,width): # width = screen width
 	else: # pad the string to width if necessary
 		return s + ' '*(width-len(s)-wide_count)
 
-class MMGenObject(object):
-
-	# Pretty-print any object subclassed from MMGenObject, recursing into sub-objects - WIP
-	def pmsg(self): print(self.pformat())
-	def pdie(self): print(self.pformat()); sys.exit(0)
-	def pformat(self,lvl=0,id_list=[]):
-		scalars = (str,int,float,Decimal)
-		def do_list(out,e,lvl=0,is_dict=False):
-			out.append('\n')
-			for i in e:
-				el = i if not is_dict else e[i]
-				if is_dict:
-					out.append('{s}{:<{l}}'.format(i,s=' '*(4*lvl+8),l=10,l2=8*(lvl+1)+8))
-				if hasattr(el,'pformat'):
-					out.append('{:>{l}}{}'.format('',el.pformat(lvl=lvl+1,id_list=id_list+[id(self)]),l=(lvl+1)*8))
-				elif type(el) in scalars:
-					if isList(e):
-						out.append('{:>{l}}{:16}\n'.format('',repr(el),l=lvl*8))
-					else:
-						out.append(' {}'.format(repr(el)))
-				elif isList(el) or isDict(el):
-					indent = 1 if is_dict else lvl*8+4
-					out.append('{:>{l}}{:16}'.format('','<'+type(el).__name__+'>',l=indent))
-					if isList(el) and type(el[0]) in scalars: out.append('\n')
-					do_list(out,el,lvl=lvl+1,is_dict=isDict(el))
-				else:
-					out.append('{:>{l}}{:16} {}\n'.format('','<'+type(el).__name__+'>',repr(el),l=(lvl*8)+8))
-				out.append('\n')
-			if not e: out.append('{}\n'.format(repr(e)))
-
-		from collections import OrderedDict
-		def isDict(obj):
-			return issubclass(type(obj),dict) or issubclass(type(obj),OrderedDict)
-		def isList(obj):
-			return issubclass(type(obj),list) and type(obj) != OrderedDict
-		def isScalar(obj):
-			return any(issubclass(type(obj),t) for t in scalars)
-
-# 		print type(self)
-# 		print dir(self)
-# 		print self.__dict__
-# 		print self.__dict__.keys()
-# 		print self.keys()
-
-		out = ['<{}>{}\n'.format(type(self).__name__,' '+repr(self) if isScalar(self) else '')]
-		if id(self) in id_list:
-			return out[-1].rstrip() + ' [RECURSION]\n'
-		if isList(self) or isDict(self):
-			do_list(out,self,lvl=lvl,is_dict=isDict(self))
-
-#		print repr(self.__dict__.keys())
-
-		for k in self.__dict__:
-			if k in ('_OrderedDict__root','_OrderedDict__map'): continue # exclude these because of recursion
-			e = getattr(self,k)
-			if isList(e) or isDict(e):
-				out.append('{:>{l}}{:<10} {:16}'.format('',k,'<'+type(e).__name__+'>',l=(lvl*8)+4))
-				do_list(out,e,lvl=lvl,is_dict=isDict(e))
-			elif hasattr(e,'pformat') and type(e) != type:
-				out.append('{:>{l}}{:10} {}'.format('',k,e.pformat(lvl=lvl+1,id_list=id_list+[id(self)]),l=(lvl*8)+4))
-			else:
-				out.append('{:>{l}}{:<10} {:16} {}\n'.format(
-					'',k,'<'+type(e).__name__+'>',repr(e),l=(lvl*8)+4))
-
-		import re
-		return re.sub('\n+','\n',''.join(out))
-
 # dict that keeps a list of keys for efficient lookup by index
 class IndexedDict(dict):
 

+ 1 - 9
mmgen/util.py

@@ -25,7 +25,7 @@ from hashlib import sha256
 from string import hexdigits,digits
 from mmgen.color import *
 from mmgen.exception import *
-from mmgen.globalvars import g
+from mmgen.globalvars import *
 
 if g.platform == 'win':
 	def msg_r(s):
@@ -93,15 +93,7 @@ def pformat(d):
 	import pprint
 	return pprint.PrettyPrinter(indent=4,compact=True).pformat(d)
 def pmsg(*args):
-	if not args: return
 	msg(pformat(args if len(args) > 1 else args[0]))
-def Pmsg(*args):
-	if not args: return
-	Msg(pformat(args if len(args) > 1 else args[0]))
-def pdie(*args,exit_val=1):
-	if not args: sys.exit(1)
-	die(exit_val,(pformat(args if len(args) > 1 else args[0])))
-def pdie2(*args): pdie(*args,exit_val=0)
 
 def set_for_type(val,refval,desc,invert_bool=False,src=None):
 	src_str = (''," in '{}'".format(src))[bool(src)]

+ 1 - 0
setup.py

@@ -87,6 +87,7 @@ setup(
 			'mmgen.color',
 			'mmgen.common',
 			'mmgen.crypto',
+			'mmgen.devtools',
 			'mmgen.ed25519',
 			'mmgen.ed25519ll_djbec',
 			'mmgen.exception',