Skip to content

Commit ed7b4bc

Browse files
committed
jdt: fill screen width, fixed OOP structure
1 parent ecbaf24 commit ed7b4bc

File tree

2 files changed

+179
-89
lines changed

2 files changed

+179
-89
lines changed

jdt.py

Lines changed: 83 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -3,114 +3,108 @@
33
'''
44
from time import time
55
from math import log
6+
from terminalsize import get_terminal_size
67

7-
class _JdtAlreadyClosedError(BaseException):
8+
class JdtAlreadyClosedError(BaseException):
89
'''Cannot update Jdt after complete. '''
910

10-
class _CannotDisplayMultiJdts(BaseException):
11-
pass
12-
13-
def smartUnit(size,is_speed=False):
14-
if size==0:
11+
def smartUnit(size, is_speed=False):
12+
'''
13+
n_byte => 6-char string with smart unit (KB, MG, GB)
14+
'''
15+
if size == 0:
1516
return ' 0 '
1617
if is_speed:
17-
magnitude=int(log(size,1024))
18+
magnitude = int(log(size, 1024))
1819
else:
19-
magnitude=int(log(size/9,1024))
20-
magnitude=min(magnitude,3)
21-
return format(size/1024**magnitude,'4.0f')+ \
22-
{0:'B ',1:'KB',2:'MB',3:'GB'}[magnitude]
23-
24-
class CommJdt:
25-
'''
26-
msg [****____] 50% Total: 44MB Done: 22MB Speed: 1MB/s
27-
'''
28-
occupied=False
29-
30-
def __init__(self,goal,msg='',width=15):
31-
if self.__class__.occupied:
32-
raise _CannotDisplayMultiJdts
33-
self.__class__.occupied=True
34-
self.active=True
35-
self.width=width
36-
self.goal=goal
37-
self.msg=msg
38-
self.last_time=time()
39-
self.last_done=0
40-
41-
def update(self,done):
42-
if not self.active:
43-
raise _JdtAlreadyClosedError
44-
dt=time()-self.last_time
45-
self.last_time=time()
46-
dd=done-self.last_done
47-
self.last_done=done
48-
if dt==0:
49-
speed=999999999
50-
else:
51-
speed=dd/dt
52-
53-
progress=done/self.goal
54-
bar=int(self.width*progress)
55-
print('\r'+self.msg, \
56-
'['+'*'*bar+'_'*(self.width-bar)+']'+ \
57-
format(progress,'4.0%'), \
58-
'Total:',smartUnit(self.goal), \
59-
'Done:',smartUnit(done), \
60-
'Speed:',smartUnit(speed,is_speed=True)+'/s', \
61-
end='',flush=True)
62-
63-
def complete(self):
64-
self.active=False
65-
self.__class__.occupied=False
66-
print('\r'+self.msg,'['+'#'*self.width+'] Complete! Total:', \
67-
smartUnit(self.goal),' '*22)
20+
magnitude = int(log(size / 9, 1024))
21+
magnitude = min(magnitude, 3)
22+
return format(size / 1024**magnitude, '4.0f') + \
23+
{0: 'B ', 1: 'KB', 2: 'MB', 3: 'GB'}[magnitude]
6824

6925
class Jdt:
70-
'''
71-
msg [****____] 50% Total: 44 Done: 22
72-
'''
73-
occupied=False
74-
75-
def __init__(self,goal,msg='',width=32, UPP = 1):
76-
if self.__class__.occupied:
77-
raise _CannotDisplayMultiJdts
78-
self.__class__.occupied=True
79-
self.active=True
80-
self.width=width
81-
self.goal=goal
82-
self.msg=msg
26+
MIN_BAR_WIDTH = 6
27+
28+
def __init__(self, goal, msg='', width=None, UPP = 1):
29+
self.active = True
30+
self.goal = goal
31+
self.msg = msg
32+
if width is not None:
33+
print('jdt Warning: argument `width` is deprecated. ')
8334
self.done = 0
8435
self.UPP = UPP
8536
self.UPP_count = 0
8637
# updates per print
8738

88-
def update(self,done):
39+
def getSuffix(self, done, progress):
40+
return '%s Total: %d Done: %d' % (
41+
format(progress, '4.0%'),
42+
self.goal,
43+
done
44+
)
45+
46+
def update(self, new_done, symbol = '*', getSuffix = None):
8947
if not self.active:
90-
raise _JdtAlreadyClosedError
91-
self.done = done
92-
self.UPP_count += 1
93-
if self.UPP_count == self.UPP:
94-
self.UPP_count = 0
95-
else:
48+
raise JdtAlreadyClosedError
49+
self.done = new_done
50+
if self.UPP_count != self.UPP:
51+
self.UPP_count += 1
9652
return
97-
progress=done/self.goal
98-
bar=int(self.width*progress)
99-
print('\r'+self.msg, \
100-
'['+'*'*bar+'_'*(self.width-bar)+']'+ \
101-
format(progress,'4.0%'), \
102-
'Total:',self.goal, \
103-
'Done:',done, \
104-
end='',flush=True)
105-
53+
self.UPP_count = 0
54+
progress = new_done / self.goal
55+
terminal_width = get_terminal_size()[0] - 4
56+
if getSuffix is None:
57+
getSuffix = self.getSuffix
58+
suffix = getSuffix(new_done, progress)
59+
msg_and_bar_width = terminal_width - len(suffix)
60+
msg_width = min(len(self.msg), int(msg_and_bar_width / 2))
61+
msg_to_print = self.msg[:msg_width]
62+
bar_width = msg_and_bar_width - msg_width
63+
if bar_width < self.MIN_BAR_WIDTH:
64+
bar_width = terminal_width - 2
65+
msg_to_print = ''
66+
suffix = ''
67+
bar_inner_width = bar_width - 2
68+
bar_fill_width = int(bar_inner_width * progress)
69+
bar_empty_width = bar_inner_width - bar_fill_width
70+
print('\r', msg_to_print, ' ',
71+
'[', symbol * bar_fill_width, '_'*bar_empty_width, ']',
72+
' ', suffix,
73+
sep = '', end='',flush=True)
74+
10675
def acc(self):
10776
self.update(self.done + 1)
10877

10978
def complete(self):
110-
self.active=False
111-
self.__class__.occupied=False
112-
print('\r'+self.msg,'['+'#'*self.width+'] Complete! Total:', \
113-
self.goal,' '*22)
79+
def getSuffix(done, progress):
80+
return 'Complete! Total: %d' % self.goal
81+
self.update(self.goal), symbol = '#', getSuffix = getSuffix)
82+
self.active = False
83+
84+
class CommJdt(Jdt):
85+
def __init__(self, *argv, **kw):
86+
super(__class__, self).__init__(*argv, **kw)
87+
self.last_time = time()
88+
89+
def update(self, new_done, *argv, **kw):
90+
delta_time = time() - self.last_time
91+
self.last_time += delta_time
92+
delta_done = new_done - self.done
93+
self.done = new_done
94+
if delta_time == 0:
95+
speed = 999999999
96+
else:
97+
speed = delta_done / delta_time
98+
def getSuffix(done, progress):
99+
nonlocal speed
100+
return '%s Total: %s Done: %s Speed: %s' % (
101+
format(progress, '4.0%'),
102+
smartUnit(self.goal),
103+
smartUnit(done),
104+
smartUnit(speed, is_speed = True)
105+
)
106+
kw['getSuffix'] = getSuffix
107+
super(__class__, self).update(new_done, *argv, **kw)
114108

115109
if __name__=='__main__':
116110
from time import sleep

terminalsize.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/env python
2+
'''
3+
Author of this code: Justin Riley
4+
https://gist.github.com/jtriley/1108174
5+
I changed python2 to python3, and added crediting printing.
6+
'''
7+
import os
8+
import shlex
9+
import struct
10+
import platform
11+
import subprocess
12+
13+
14+
def get_terminal_size():
15+
""" getTerminalSize()
16+
- get width and height of console
17+
- works on linux,os x,windows,cygwin(windows)
18+
originally retrieved from:
19+
http://stackoverflow.com/questions/566746/how-to-get-console-window-width-in-python
20+
"""
21+
current_os = platform.system()
22+
tuple_xy = None
23+
if current_os == 'Windows':
24+
tuple_xy = _get_terminal_size_windows()
25+
if tuple_xy is None:
26+
tuple_xy = _get_terminal_size_tput()
27+
# needed for window's python in cygwin's xterm!
28+
if current_os in ['Linux', 'Darwin'] or current_os.startswith('CYGWIN'):
29+
tuple_xy = _get_terminal_size_linux()
30+
if tuple_xy is None:
31+
print("default")
32+
tuple_xy = (80, 25) # default value
33+
return tuple_xy
34+
35+
36+
def _get_terminal_size_windows():
37+
try:
38+
from ctypes import windll, create_string_buffer
39+
# stdin handle is -10
40+
# stdout handle is -11
41+
# stderr handle is -12
42+
h = windll.kernel32.GetStdHandle(-12)
43+
csbi = create_string_buffer(22)
44+
res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
45+
if res:
46+
(bufx, bufy, curx, cury, wattr,
47+
left, top, right, bottom,
48+
maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
49+
sizex = right - left + 1
50+
sizey = bottom - top + 1
51+
return sizex, sizey
52+
except:
53+
pass
54+
55+
56+
def _get_terminal_size_tput():
57+
# get terminal width
58+
# src: http://stackoverflow.com/questions/263890/how-do-i-find-the-width-height-of-a-terminal-window
59+
try:
60+
cols = int(subprocess.check_call(shlex.split('tput cols')))
61+
rows = int(subprocess.check_call(shlex.split('tput lines')))
62+
return (cols, rows)
63+
except:
64+
pass
65+
66+
67+
def _get_terminal_size_linux():
68+
def ioctl_GWINSZ(fd):
69+
try:
70+
import fcntl
71+
import termios
72+
cr = struct.unpack('hh',
73+
fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
74+
return cr
75+
except:
76+
pass
77+
cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
78+
if not cr:
79+
try:
80+
fd = os.open(os.ctermid(), os.O_RDONLY)
81+
cr = ioctl_GWINSZ(fd)
82+
os.close(fd)
83+
except:
84+
pass
85+
if not cr:
86+
try:
87+
cr = (os.environ['LINES'], os.environ['COLUMNS'])
88+
except:
89+
return None
90+
return int(cr[1]), int(cr[0])
91+
92+
if __name__ == "__main__":
93+
sizex, sizey = get_terminal_size()
94+
print('width =', sizex, 'height =', sizey)
95+
else:
96+
print('import terminalsize: Special thank to Justin Riley for writing a wonderful script that detects terminal size across OSes. ')

0 commit comments

Comments
 (0)