| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- #!/usr/bin/env python3
- class MMGenObject(object):
- 'placeholder - overridden when testing'
- def immutable_attr_init_check(self): pass
- import os
- if os.getenv('MMGEN_DEBUG') or os.getenv('MMGEN_TEST_SUITE') or os.getenv('MMGEN_TRACEBACK'):
- import sys,re,traceback,json,pprint
- from decimal import Decimal
- from difflib import unified_diff,ndiff
- def pmsg(*args,out=sys.stderr):
- d = args if len(args) > 1 else '' if not args else args[0]
- out.write(pprint.PrettyPrinter(indent=4).pformat(d) + '\n')
- def pdie(*args,exit_val=1,out=sys.stderr):
- pmsg(*args,out=out)
- sys.exit(exit_val)
- def pexit(*args,out=sys.stderr):
- pdie(*args,exit_val=0,out=out)
- def Pmsg(*args):
- pmsg(*args,out=sys.stdout)
- def Pdie(*args):
- pdie(*args,out=sys.stdout)
- def Pexit(*args):
- pexit(*args,out=sys.stdout)
- def print_stack_trace(message=None,fh=[],nl='\n',sep='\n '):
- if not fh:
- fh.append(open(f'devtools.trace.{os.getpid()}','w'))
- nl = ''
- tb = [t for t in traceback.extract_stack() if t.filename[:1] != '<'][:-1]
- fs = '{}:{}: in {}:\n {}'
- out = [
- fs.format(
- re.sub(r'^\./','',os.path.relpath(t.filename)),
- t.lineno,
- (t.name+'()' if t.name[-1] != '>' else t.name),
- t.line or '(none)')
- for t in tb ]
- text = f'{nl}STACK TRACE {message or "[unnamed]"}:{sep}{sep.join(out)}\n'
- sys.stderr.write(text)
- fh[0].write(text)
- class MMGenObject(object):
- # Pretty-print any object subclassed from MMGenObject, recursing into sub-objects - WIP
- def pmsg(self):
- print(self.pfmt())
- def pdie(self):
- print(self.pfmt())
- sys.exit(1)
- def pfmt(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,'pfmt'):
- out.append('{:>{l}}{}'.format(
- '',
- el.pfmt( lvl=lvl+1, id_list=id_list+[id(self)] ),
- l = (lvl+1)*8 ))
- elif isinstance(el,scalars):
- if isList(e):
- out.append( '{:>{l}}{!r:16}\n'.format( '', el, l=lvl*8 ))
- else:
- out.append(f' {el!r}')
- elif isList(el) or isDict(el):
- indent = 1 if is_dict else lvl*8+4
- out.append('{:>{l}}{:16}'.format( '', f'<{type(el).__name__}>', l=indent ))
- if isList(el) and isinstance(el[0],scalars):
- out.append('\n')
- do_list(out,el,lvl=lvl+1,is_dict=isDict(el))
- else:
- out.append('{:>{l}}{:16} {!r}\n'.format( '', f'<{type(el).__name__}>', el, l=(lvl*8)+8 ))
- out.append('\n')
- if not e:
- out.append(f'{e!r}\n')
- def isDict(obj):
- return isinstance(obj,dict)
- def isList(obj):
- return isinstance(obj,list)
- def isScalar(obj):
- return isinstance(obj,scalars)
- out = [f'<{type(self).__name__}>{" "+repr(self) if isScalar(self) else ""}\n']
- 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))
- for k in self.__dict__:
- e = getattr(self,k)
- if isList(e) or isDict(e):
- out.append('{:>{l}}{:<10} {:16}'.format( '', k, f'<{type(e).__name__}>', l=(lvl*8)+4 ))
- do_list(out,e,lvl=lvl,is_dict=isDict(e))
- elif hasattr(e,'pfmt') and type(e) != type:
- out.append('{:>{l}}{:10} {}'.format(
- '',
- k,
- e.pfmt( lvl=lvl+1, id_list=id_list+[id(self)] ),
- l = (lvl*8)+4 ))
- else:
- out.append('{:>{l}}{:<10} {:16} {}\n'.format(
- '',
- k,
- f'<{type(e).__name__}>',
- repr(e),
- l=(lvl*8)+4 ))
- import re
- return re.sub('\n+','\n',''.join(out))
- # Check that all immutables have been initialized. Expensive, so do only when testing.
- def immutable_attr_init_check(self):
- from .globalvars import g
- if g.test_suite:
- from .util import rdie
- cls = type(self)
- for attrname in sorted({a for a in self.valid_attrs if a[0] != '_'}):
- for o in (cls,cls.__bases__[0]): # assume there's only one base class
- if attrname in o.__dict__:
- attr = o.__dict__[attrname]
- break
- else:
- rdie(3,f'unable to find descriptor {cls.__name__}.{attrname}')
- if type(attr).__name__ == 'ImmutableAttr':
- if attrname not in self.__dict__:
- rdie(3,
- f'attribute {attrname!r} of {cls.__name__} has not been initialized in constructor!')
- def print_diff(a,b,from_file='',to_file='',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,from_file,to_file)) ))
- def get_ndiff(a,b):
- a = a.split('\n')
- b = b.split('\n')
- return list(ndiff(a,b))
|