-
Notifications
You must be signed in to change notification settings - Fork 11
/
progressbar.py
executable file
·99 lines (81 loc) · 3.84 KB
/
progressbar.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#!/usr/bin/python
#
# Forked from Romuald Brunet, https://stackoverflow.com/questions/3160699/python-progress-bar
#
from __future__ import print_function
import sys
import re
import time, datetime
class ProgressBar(object):
def __init__(self, total_items):
"""Initialized the ProgressBar object"""
#Vars related to counts/time
self.total_items = total_items
self.current = 0
self.finished = False
self.start_epoch = None #Set to none, start when first iteration occurs
#Vars related to output
self.width = 40 #Length of progress bar
self.symbol = "#" #Needs to be 1 char
self.output = sys.stderr
self.fmt = '''%(percent)3d%% %(bar)s %(current)s/%(total_items)s %(items_per_sec)s ETA: %(eta)s'''
assert len(self.symbol) == 1 #If higher, progress bar won't populate properly
assert self.width <= 150 #If higher, it'll takeup more than one line of text
def __call__(self, num_compelted=1):
"""Actions to run when progress is run"""
#Initialize the start time as the first iteration (just in case progress bar is initialized early)
if self.start_epoch is None:
self.start_epoch = int(time.time())
#Update calculations/values
self.current += num_compelted
try:
percent = self.current / float(self.total_items)
except:
percent = 0
size = int(self.width * percent)
run_time = time.time() - self.start_epoch
remaining = self.total_items - self.current
try:
time_left = (run_time/self.current) * remaining
except:
time_left = 0
#Args to populate into fmt
args = {
'percent': (percent * 100),
'bar': '''[{symbols}{spaces}]'''.format(symbols=(self.symbol * size), spaces=' ' * (self.width - size)),
'current': "{:,}".format(self.current),
'total_items': "{:,}".format(self.total_items),
'items_per_sec': "{items_per_sec}/sec".format(items_per_sec="{:,}".format(int(self.current / run_time))),
'eta': self.get_eta(int(time_left)),
'run_time': self.get_eta(run_time),
}
#Print the update
print('\r' + self.fmt%args, file=self.output, end=' ')
def get_eta(self, time_left):
"""Print the num hour, min and/or sec for the given number of seconds"""
time_remaining = time.gmtime(time_left)
days_left = time_remaining.tm_mday-1
if days_left > 0:
return "{days_left}d {hr}h {min}m {sec}s".format(days_left=days_left, hr=time_remaining.tm_hour, min=time_remaining.tm_min, sec=time_remaining.tm_sec)
if time_remaining.tm_hour:
return "{hr}h {min}m {sec}s".format(hr=time_remaining.tm_hour, min=time_remaining.tm_min, sec=time_remaining.tm_sec)
elif time_remaining.tm_min:
return "{min}m {sec}s".format(min=time_remaining.tm_min, sec=time_remaining.tm_sec)
else:
return "{sec}s".format(sec=time_remaining.tm_sec)
def done(self):
"""Prints completion statement, only once"""
#Be sure done hasn't already been called, set if not
if not self.finished:
self.finished = True
run_time = time.gmtime(time.time() - self.start_epoch)
final_output = '''
FINISHED at {date_time}
Total time: {total_time}
Total completed: {total_items_done}'''.format(
date_time = str(datetime.datetime.now()),
total_items_done = self.current,
total_time = "{hr}h {min}m {sec}s".format(hr=run_time.tm_hour, min=run_time.tm_min, sec=run_time.tm_sec)
)
#Print final output
print('\n{final_output}\n'.format(final_output=final_output), file=self.output)