Created
September 8, 2017 08:39
-
-
Save dawn110110/4e7747aec547dbf4816ee5b19552a58b to your computer and use it in GitHub Desktop.
easyprint lib py3 ver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# coding: utf-8 | |
# source code from https://github.com/dainan13/py-aluminium/blob/master/src/easyprint.py | |
# modified by zhangtianxiao@sensorsdata.cn for python3.X support. | |
from __future__ import print_function | |
import types | |
import unicodedata | |
import re | |
from pprint import pprint | |
def safestr( a ): | |
if isinstance(a, str): | |
return a | |
elif isinstance(a, bytes): | |
return a.decode('utf-8', errors='ignore') | |
else: | |
return repr(a) | |
def safelen( a ): | |
if isinstance(a, bytes): | |
return len(a) | |
if isinstance(a, str): | |
return sum( [ 2 if unicodedata.east_asian_width(c).startswith('W') else 1 | |
for c in a ]) | |
raise Exception(repr(a)) | |
def _namescore( name ): | |
score = 0 | |
name = name.lower() | |
if name in ( '!','#' ) : | |
score += 150 | |
if name.endswith('id') : | |
score += 100 | |
score -= len(name)-2 | |
if name.endswith('type') : | |
score += 81 | |
score -= len(name)-4 | |
if name.endswith('name') : | |
score += 80 | |
score -= len(name)-4 | |
if name.startswith('last-') : | |
score -= 50 | |
score -= len(name)-5 | |
if name.find('data') != -1 or name.find('time') != -1 : | |
score -= 50 | |
score -= len(name)-5 | |
if name.find('url') != -1 or name.find('address') != -1 : | |
score -= 30 | |
score -= len(name)-5 | |
return -score | |
def smartsort( kvpair ): | |
l = kvpair[:] | |
l.sort( key = lambda x : [_namescore(x[0]),x[0]] ) | |
return l | |
def _coltree( Name, d ): | |
return ( Name, {}, tuple( _coltree(k, v) | |
for k, v in smartsort( list(d.items()) ) | |
) | |
) | |
def _coldata( t ): | |
if t[2] == (): | |
return t[0] | |
return [ t[0], dict([ (v[0], _coldata(v)) for v in t[2] ]) ] | |
def getcols( data, level = 2 ): | |
cols = {} | |
# breadth-first traversal | |
s = [ ( data, 0, cols ), ] | |
while( len(s)!=0 ): | |
v, lv, r = s.pop(0) | |
if lv > level : | |
continue | |
if not (isinstance(v, list) or isinstance(v, tuple)): | |
v = [v,] | |
for vi in v : | |
if not isinstance(vi, dict): | |
continue | |
for k in vi.keys(): | |
r.setdefault( k, {} ) | |
s.append( ( vi[k], lv+1, r[k] ) ) | |
return _coltree( '', cols ) | |
def _xzip( matrix ): | |
maxlen = max( [ len(r) for r in matrix ] ) | |
m2 = [ list(r) + ['',]*(maxlen-len(r)) for r in matrix ] | |
return list(zip(*m2)) | |
def _format( v, cols ): | |
if cols == None or cols[2] == () : | |
return safestr(v).splitlines() | |
if not (isinstance(v, list) or isinstance(v, tuple)): | |
v = [v,] | |
r = [] | |
for vi in v : | |
if isinstance(vi, dict): | |
ri = [ _format( vi[subc[0]], subc ) if subc[0] in vi else '' | |
for subc in cols[2] ] | |
r.append( _xzip(ri) ) | |
else : | |
r.append( _format( vi, None ) ) | |
return sum(r,[]) | |
def _width( v, cols ): | |
if isinstance(v, tuple): | |
r = sum( [ _width( vi, cols[2][i] ) for i, vi in enumerate(v) ] ) | |
r += len(v)-1 | |
else : | |
r = safelen(v) | |
cols[1]['__width__'] = max( cols[1].get('__width__',safelen(cols[0])), r ) | |
return cols[1]['__width__'] | |
def _colwidth( cols ): | |
def none_to_neg_inf(obj_v): | |
""" make None to -inf, so comparable in python3 to int values """ | |
if obj_v is None: | |
return float('-inf') | |
else: | |
return obj_v | |
cols[1]['__width__'] = max( none_to_neg_inf(cols[1].get('__width__')), | |
sum( [ none_to_neg_inf(_colwidth(c)+1) for c in cols[2] ] ) -1, | |
*[ none_to_neg_inf(safelen(l)) for l in cols[0].splitlines()] | |
) | |
return cols[1]['__width__'] | |
def width( v, cols ): | |
_colwidth(cols) | |
for vi in v : | |
_width( vi, cols ) | |
return | |
def _print( v, cols ): | |
if isinstance(v, tuple): | |
return ' '.join([ _print(vi, cols[2][i]) for i, vi in enumerate(v) ]) | |
else : | |
j = cols[1].get( '__just__', 'left' ) | |
if callable(j): | |
j = j(v) | |
if j == 'right' : | |
return ' '*(cols[1]['__width__'] - safelen(v))+v | |
elif j == 'center' : | |
n = (cols[1]['__width__'] - safelen(v))/2 | |
m = cols[1]['__width__'] - n | |
return ' '*m+v+' '*n | |
return v + ( ' '*(cols[1]['__width__'] - safelen(v)) ) | |
def _grid( v, cols ): | |
if type(v) == types.TupleType : | |
return sum( [ _grid(vi, cols[2][i]) for i, vi in enumerate(v) ], [] ) | |
padcols = max( [len( cols[2] ), 1 ] ) - 1 | |
return [v] + ['']*padcols | |
def eprint( v, cols ): | |
for vi in v : | |
print(_print( vi, cols )) | |
def eformat( v, cols ): | |
return '\r\n'.join( [ _print( vi, cols ) for vi in v ] ) | |
def egrid( v, cols ): | |
return [ _grid( vi, cols ) for vi in v ] | |
def ifdict( di ): | |
return [ { 'Key':k, 'Value':v } for k, v in di.items() ] | |
def easyprint( data, cols = None ): | |
if isinstance(data, dict): | |
data = ifdict(data) | |
# get the cols if not fixed | |
if cols is None : | |
cols = getcols( data ) | |
elif isinstance(cols, int): | |
cols = getcols( data, cols ) | |
#print cols | |
fdata = _format( data, cols ) | |
width( fdata, cols ) | |
cdata = _coldata( cols ) | |
cdata = _format( cdata, cols ) | |
eprint( cdata, cols ) | |
print('-'*cols[1]['__width__']) | |
eprint( fdata, cols ) | |
return | |
def easygrid( data, cols = None ): | |
if isinstance(data, dict): | |
data = ifdict(data) | |
# get the cols if not fixed | |
if cols == None : | |
cols = getcols( data ) | |
elif isinstance(cols, int): | |
cols = getcols( data, cols ) | |
if len(cols[2]) == 0 : | |
return [], [] | |
#print cols | |
#print '--cols--' | |
#pprint(cols) | |
#print '--------' | |
fdata = _format( data, cols ) | |
width( fdata, cols ) | |
cdata = _coldata( cols ) | |
cdata = _format( cdata, cols ) | |
#print '--cdata--' | |
#pprint(cdata) | |
#print '--------' | |
return egrid( cdata, cols ), egrid( fdata, cols ) | |
def easyformat( data, cols = None ): | |
if isinstance(data, dict): | |
data = ifdict(data) | |
# get the cols if not fixed | |
if cols == None : | |
cols = getcols( data ) | |
elif isinstance(cols, int): | |
cols = getcols( data, cols ) | |
#print cols | |
fdata = _format( data, cols ) | |
width( fdata, cols ) | |
cdata = _coldata( cols ) | |
cdata = _format( cdata, cols ) | |
r = [ eformat( cdata, cols ), | |
'-'*cols[1]['__width__'], | |
eformat( fdata, cols ) ] | |
return '\r\n'.join(r) | |
# | |
#⠀ ⠁ ⠂ ⠃ ⠄ ⠅ ⠆ ⠇ ⠈ ⠉ ⠊ ⠋ ⠌ ⠍ ⠎ ⠏ ⠐ ⠑ ⠒ ⠓ ⠔ ⠕ ⠖ ⠗ ⠘ ⠙ ⠚ ⠛ ⠜ ⠝ ⠞ ⠟ | |
#⠠ ⠡ ⠢ ⠣ ⠤ ⠥ ⠦ ⠧ ⠨ ⠩ ⠪ ⠫ ⠬ ⠭ ⠮ ⠯ ⠰ ⠱ ⠲ ⠳ ⠴ ⠵ ⠶ ⠷ ⠸ ⠹ ⠺ ⠻ ⠼ ⠽ ⠾ ⠿ | |
#⡀ ⡁ ⡂ ⡃ ⡄ ⡅ ⡆ ⡇ ⡈ ⡉ ⡊ ⡋ ⡌ ⡍ ⡎ ⡏ ⡐ ⡑ ⡒ ⡓ ⡔ ⡕ ⡖ ⡗ ⡘ ⡙ ⡚ ⡛ ⡜ ⡝ ⡞ ⡟ | |
#⡠ ⡡ ⡢ ⡣ ⡤ ⡥ ⡦ ⡧ ⡨ ⡩ ⡪ ⡫ ⡬ ⡭ ⡮ ⡯ ⡰ ⡱ ⡲ ⡳ ⡴ ⡵ ⡶ ⡷ ⡸ ⡹ ⡺ ⡻ ⡼ ⡽ ⡾ ⡿ | |
#⢀ ⢁ ⢂ ⢃ ⢄ ⢅ ⢆ ⢇ ⢈ ⢉ ⢊ ⢋ ⢌ ⢍ ⢎ ⢏ ⢐ ⢑ ⢒ ⢓ ⢔ ⢕ ⢖ ⢗ ⢘ ⢙ ⢚ ⢛ ⢜ ⢝ ⢞ ⢟ | |
#⢠ ⢡ ⢢ ⢣ ⢤ ⢥ ⢦ ⢧ ⢨ ⢩ ⢪ ⢫ ⢬ ⢭ ⢮ ⢯ ⢰ ⢱ ⢲ ⢳ ⢴ ⢵ ⢶ ⢷ ⢸ ⢹ ⢺ ⢻ ⢼ ⢽ ⢾ ⢿ | |
#⣀ ⣁ ⣂ ⣃ ⣄ ⣅ ⣆ ⣇ ⣈ ⣉ ⣊ ⣋ ⣌ ⣍ ⣎ ⣏ ⣐ ⣑ ⣒ ⣓ ⣔ ⣕ ⣖ ⣗ ⣘ ⣙ ⣚ ⣛ ⣜ ⣝ ⣞ ⣟ | |
#⣠ ⣡ ⣢ ⣣ ⣤ ⣥ ⣦ ⣧ ⣨ ⣩ ⣪ ⣫ ⣬ ⣭ ⣮ ⣯ ⣰ ⣱ ⣲ ⣳ ⣴ ⣵ ⣶ ⣷ ⣸ ⣹ ⣺ ⣻ ⣼ ⣽ ⣾ ⣿ | |
# | |
chartchar = [ u'\u2800\u2880\u28a0\u28b0\u28b8', | |
u'\u2840\u28C0\u28E0\u28F0\u28F8', | |
u'\u2844\u28C4\u28E4\u28F4\u28FC', | |
u'\u2846\u28C6\u28E6\u28F6\u28FE', | |
u'\u2847\u28C7\u28E7\u28F7\u28FF', | |
] | |
# chartline = '⣀⠤⠒⠉'.decode('utf-8') | |
# chartlinex = '⡀⠄⠂⠁'.decode('utf-8') | |
chartline = '⣀⠤⠒⠉' | |
chartlinex = '⡀⠄⠂⠁' | |
SIprefixes = " kMGTPEZY" | |
IECprefixes = [" ", "Ki","Mi","Gi","Ti","Pi","Ei","Zi","Yi"] | |
def humanreadable( a, f=2, iec=False ): | |
p = 1024 if iec else 1000 | |
s = '%%.%df%%s' % (f,) | |
for i in range(8,0,-1): | |
z = float(a) / (p**i) | |
if z >= 1 : | |
return s % ( z, IECprefixes[i] if iec else SIprefixes[i] ) | |
if isinstance(a, int): | |
return str(a) | |
return s % ( float(a), '' ) | |
def show_chart( n, maxn = None, ratio = None): | |
maxn = maxn or max(n) | |
ratio = ratio or maxn/40 | |
ratio = ratio or 1 | |
maxh = maxn/ratio | |
hs = [ min(x/ratio, maxh) for x in n ] | |
hs = [ [x%4]+[4]*(x/4) for x in hs ] | |
hs = [ [0]*(maxh/4-len(x)) + x for x in hs ] | |
rs = zip(*hs) | |
rs = [ list(r)+[0] for r in rs ] | |
rs = [ zip(r[::2],r[1::2]) for r in rs ] | |
chrs = [ [ chartchar[a][b] for a, b in r ] for r in rs ] | |
chrs = [ ''.join(cs) for cs in chrs ] | |
for r in chrs : | |
print(r) | |
return | |
def smart_show_chart( data, height=10, points=None, iec=False, unit='', rjust=0, color=True ): | |
maxdata = max(data) | |
segmax = maxdata | |
shrink = 1 | |
enlarge = 1 | |
if not iec or segmax < 1: | |
while( segmax >= 100 ): | |
segmax = segmax/10 | |
shrink = shrink*10 | |
while( segmax < 10 ): | |
segmax = segmax*10 | |
enlarge = enlarge*10 | |
segmax = int(segmax) | |
segmax = ((int(segmax/10))+1)*10 if segmax >= 20 else ((int(segmax/5))+1)*5 | |
step = 5 if segmax <= 20 else 10 if segmax <= 50 else 20 | |
vpoints = [ (float(x)*shrink/enlarge, x*4*height/segmax) for x in range(0,segmax,step) ] | |
else : | |
while( segmax >= 16 ): | |
segmax = segmax/4 | |
shrink = shrink*4 | |
while( segmax < 4 ): | |
segmax = segmax*4 | |
enlarge = enlarge*4 | |
segmax = int(segmax) | |
segmax = segmax+1 | |
step = 1 if segmax <= 4 else 2 if segmax <= 8 else 4 | |
vpoints = [ (float(x)*shrink/enlarge, x*4*height/segmax) for x in range(0,segmax,step) ] | |
maxdata = float(segmax)*shrink/enlarge | |
if maxdata > 1 : | |
vpoints = [ ( humanreadable(p, iec=iec)+unit, x ) for p, x in vpoints ] | |
maxp = humanreadable(maxdata, iec=iec)+unit | |
else : | |
vpoints = [ ( str(p)+unit, x ) for p, x in vpoints ] | |
maxp = vpoints[-1][0] | |
vpointslen = max( len(p) for p, x in vpoints ) | |
vpointslen = max(vpointslen, len(maxp))+rjust | |
vpoints = dict( (int(x)/4,(p,int(x)%4)) for p, x in vpoints ) | |
hs = [ min(int(x*4*height/maxdata), 4*height) for x in data ] | |
hs = [ [int(x)%4]+[4]*(int(int(x)/4)) for x in hs ] | |
hs = [ [0]*(height-len(x)) + x for x in hs ] | |
rs = zip(*hs) | |
rs = [ list(r)+[0] for r in rs ] | |
rs = [ zip(r[::2],r[1::2]) for r in rs ] | |
chrs = [ [ chartchar[a][b] for a, b in r ] for r in rs ] | |
chrs = [ ''.join(cs) for cs in chrs ] | |
maxp = maxp.rjust(vpointslen) | |
if color : | |
print(maxp+chartlinex[0]+\ | |
u'\033[38;5;237m'+chartline[0]*int((len(data)+1)/2)+ u'\033[0m') | |
else : | |
print(maxp+chartlinex[0]) | |
for i, r in enumerate( chrs ) : | |
p, c = vpoints.get(height-i-1,('',None)) | |
p = p.rjust(vpointslen) | |
if c is not None: | |
#r = re.sub("([ ]+)",r'<\1>',"abc def ghi") | |
r = re.sub(u"([\u2800]+)",u'\033[38;5;237m\\1\033[0m',r) | |
r = r.replace(u'\u2800', chartline[c]) | |
c = chartlinex[c] | |
else : | |
c = ' ' | |
print(p+c+r) | |
if points != None : | |
points = points+[None,] | |
points = [ (str(p) if p else None) for p in points ] | |
points = zip(points[::2],points[1::2]) | |
points = [ ( a or b ) for a, b in points ] | |
points = [ (i, x) for i, x in enumerate(points) if x ] | |
pp, sp = zip(*points) | |
if pp[0] != 0 : | |
pplen = zip( [0]+list(pp), list(pp)+[0] ) | |
sp = ['',]+list(sp) | |
else : | |
pplen = zip( list(pp), list(pp[1:])+[0] ) | |
pplen = [ max( e-s, 0 ) for s, e in pplen ] | |
lp = [ '|' if spi else ' ' for spi in sp ] | |
lp = [ lpi.ljust(e) for lpi, e in zip(lp,pplen) ] | |
sp = [ spi[:(e or None)].ljust(e) for spi, e in zip(sp,pplen) ] | |
print(' '*(vpointslen+1)+''.join(lp)) | |
print(' '*(vpointslen+1)+''.join(sp)) | |
return | |
if __name__ == '__main__' : | |
a = [ { 'colA' : ['A','B','C','D'], 'colB' : ['A','B','C'] }, | |
{ 'colA' : ['A','B'] , 'colB' : 'A\r\nB\r\nC\r\nD' }, | |
{ 'colA' : ['A\r\nB','C\r\nD'] , 'colB' : 'A\r\nB\r\nC\r\nD' }, | |
] | |
b = [ { 'col A' : 'A.1', 'col B': 'B.1' }, | |
{ 'col A' : 'A.2', 'col B': {'subcol A': 'B.A.2', 'subcol B': 'B.B.2'} }, | |
] | |
c = [ { 'col A' : 'A.1', 'col B': 'B.1' }, | |
{ 'col A' : 'A.2', 'col B': 'B.2' }, | |
] | |
d = [ { 'colA' : 'A.1.alpha\r\nA.1.beta' , | |
'colB' : 'B.1.alpha\r\nB.1.beta\r\nB.1.gamma\r\nB.1.delta' }, | |
{ 'colA' : 'A.2.alpha\r\nA.2.beta' , | |
'colB' : 'B.2.alpha' } | |
] | |
#easyprint(a) | |
easyprint(b) | |
easyprint(c) | |
easyprint(d) | |
print(easyformat(d)) | |
import cmath | |
smart_show_chart([ x*123 for x in range(100) ]) | |
smart_show_chart( | |
[ x*123 for x in range(100) ], | |
points = [ ( x if x%10==0 else None ) for x in range(100)], | |
iec=True, unit='Byte', | |
) | |
smart_show_chart( | |
[ x*0.000345 for x in range(100) ], | |
points = [ ( x if x%10==0 else None ) for x in range(100)], | |
iec=True, unit='$', | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment