From 85d3336a9e824050ee5812964c990ce6f033058b Mon Sep 17 00:00:00 2001 From: MMGen Date: Wed, 3 Jul 2019 18:16:09 +0000 Subject: [PATCH] new file: devtools.py --- mmgen/common.py | 2 +- mmgen/devtools.py | 102 ++++++++++++++++++++++++++++++++++++++++++++ mmgen/globalvars.py | 5 +++ mmgen/obj.py | 71 ++---------------------------- mmgen/util.py | 10 +---- setup.py | 1 + 6 files changed, 114 insertions(+), 77 deletions(-) create mode 100644 mmgen/devtools.py diff --git a/mmgen/common.py b/mmgen/common.py index f79ed305..3b9b7e73 100755 --- a/mmgen/common.py +++ b/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 * diff --git a/mmgen/devtools.py b/mmgen/devtools.py new file mode 100644 index 00000000..e75bce30 --- /dev/null +++ b/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)))) diff --git a/mmgen/globalvars.py b/mmgen/globalvars.py index 657fdc55..7eb4d3ed 100755 --- a/mmgen/globalvars.py +++ b/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 diff --git a/mmgen/obj.py b/mmgen/obj.py index 280cdcd9..3fcb7d7e 100755 --- a/mmgen/obj.py +++ b/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): diff --git a/mmgen/util.py b/mmgen/util.py index a62808a1..a4ff7e90 100755 --- a/mmgen/util.py +++ b/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)] diff --git a/setup.py b/setup.py index ca6b8d02..99de5eba 100755 --- a/setup.py +++ b/setup.py @@ -87,6 +87,7 @@ setup( 'mmgen.color', 'mmgen.common', 'mmgen.crypto', + 'mmgen.devtools', 'mmgen.ed25519', 'mmgen.ed25519ll_djbec', 'mmgen.exception',