1- from .color import Color
1+ from . import color
22from time import time
33import datetime
44
55class Bar ():
6- def __init__ (self , max = 1 , width = 80 , prefix = "" , eta = True , decimals = 0 , duration = True ):
6+
7+
8+
9+ # ________________________________________________________________________________
10+ # Create a progress bar
11+
12+ def __init__ (self , max :float | int = 1 , width :int = 80 , prefix :str = "" , eta :bool = True , decimals :int = 0 , show_duration :bool = True , average_ETA :int = 10 ):
713 self .max = max
8- self .width = width if type (width ) == int else 80
14+ self .width = width if isinstance (width , int ) else 80
915 self .prefix = prefix
1016 self .eta = eta
1117 self .decimals = decimals
12- self .lastProgress = 0
13- self .lastUpdate = None
18+ self .previous_progress = [ 0 ]
19+ self .previous_update = []
1420 self .lastETA = "-"
1521 self .start_at = time ()
16- self .duration = duration
22+ self .duration = show_duration
23+ self .average_ETA = average_ETA
24+
25+
26+ # ________________________________________________________________________________
27+ # Compute the ETA
1728
1829 def update_eta (self , progress ):
19- if self .lastUpdate is not None and time ()- self .lastUpdate < 1 : return self .lastETA
2030
21- progression = progress - self .lastProgress
22- left = (self .max - progress )
31+ # Get index of the i-th revious update to average the ETA on i updates
32+ if len (self .previous_progress ) <= self .average_ETA :
33+ i = 0
34+ else :
35+ i = - self .average_ETA
36+
37+ # Compute progression since the i-th previous update
38+ progression = progress - self .previous_progress [i ]
39+ todo = self .max - progress
2340
24- if progression == 0 or self .lastUpdate is None :
25- self .lastUpdate = time ()
26- self .lastProgress = progress
41+ # If there is no progression or the bar was just created, it update the data but return the same ETA
42+ if progression == 0 or self .previous_update == []:
43+ self .previous_update .append (time ())
44+ self .previous_progress .append (progress )
2745 self .lastETA = "-"
2846 return self .lastETA
2947
30- seconds = left / progression * (time () - self .lastUpdate )
31- self .lastUpdate = time ()
32- self .lastProgress = progress
33- if seconds < 0 : self .lastETA = "-"
34- else : self .lastETA = str (datetime .timedelta (seconds = seconds )).split ("." )[0 ]
48+ # If the bar was updated less than one second before,
49+ # we don't update it again to not slow the program
50+ if time ()- self .previous_update [- 1 ] < 1 :
51+ return self .lastETA
52+
53+ # Compute the ETA in seconds
54+ try :
55+ seconds = todo / progression * (time () - self .previous_update [i ])
56+ except :
57+ print (len (self .previous_update ), i )
58+
59+ # Update bar data
60+ self .previous_update .append (time ())
61+ self .previous_progress .append (progress )
62+
63+ # If the ETA is negative, then we show an undefined ETA
64+ if seconds < 0 :
65+ self .lastETA = "-"
66+ # Else we return the number of seconds
67+ else :
68+ self .lastETA = str (datetime .timedelta (seconds = seconds )).split ("." )[0 ]
69+
3570 return self .lastETA
3671
72+
73+
74+ # ________________________________________________________________________________
75+ # Update the progress bar
76+
3777 def __call__ (self , progress : float , prefix = None , stop = False ):
3878 if prefix is None : prefix = self .prefix
3979 else : prefix = str (prefix )
4080
4181 progress_normed = progress / self .max
4282 if progress == self .max : stop = True
43- color = Color .Yellow if stop and progress_normed != 1 else Color .LightGreen
83+ color_bar = color .Yellow if stop and progress_normed != 1 else color .LightGreen
4484
4585 if stop : end = "\n "
4686 else : end = "\r "
4787
4888 if type (progress ) == float : progress = round (progress , self .decimals )
49- percent = f" { color } { round (progress_normed * 100 ,self .decimals ) if self .decimals > 0 else int (progress_normed * 100 )} %"
50- frac = f" { Color .LightRed } { progress } /{ self .max } " if self .max is not None else ''
51- eta = f" { Color .NC } eta { Color .Blue } { self .update_eta (progress )} " if not stop else ''
52- duration = f" { Color .Purple } { str (datetime .timedelta (seconds = time () - self .start_at )).split ('.' )[0 ]} " if self .duration else ''
89+ percent = f" { color_bar } { round (progress_normed * 100 ,self .decimals ) if self .decimals > 0 else int (progress_normed * 100 )} %"
90+ frac = f" { color .LightRed } { progress } /{ self .max } " if self .max is not None else ''
91+ eta = f" { color .NC } eta { color .Blue } { self .update_eta (progress )} " if not stop else ''
92+ duration = f" { color .Purple } { str (datetime .timedelta (seconds = time () - self .start_at )).split ('.' )[0 ]} " if self .duration else ''
5393
54- prefix = '' if prefix == '' else Color .NC + prefix + ' '
94+ prefix = '' if prefix == '' else color .NC + prefix + ' '
5595 suffix = f"{ percent } { frac } { duration } { eta } "
5696
57- barwidth = self .width - len (Color .clear (suffix )) - len (Color .clear (prefix ))
97+ barwidth = self .width - len (color .clear (suffix )) - len (color .clear (prefix ))
5898 barwidth = max (barwidth ,10 )
5999
60100 currentBar = int (round (min (progress_normed * barwidth ,barwidth )))
61101 minBar = int (min (progress_normed * barwidth ,barwidth ))
62102
63- if progress_normed == 0 : bar = Color .White + '━' * barwidth
64- elif progress_normed == 1 : bar = Color .LightGreen + '━' * barwidth
65- elif currentBar == minBar : bar = color + '━' * currentBar + Color .White + '╺' + Color .White + '━' * (barwidth - currentBar - 1 )
66- else : bar = color + '━' * (currentBar - 1 ) + color + '╸' + Color .White + '━' * (barwidth - currentBar )
103+ if progress_normed == 0 : bar = color .White + '━' * barwidth
104+ elif progress_normed == 1 : bar = color .LightGreen + '━' * barwidth
105+ elif currentBar == minBar : bar = color_bar + '━' * currentBar + color .White + '╺' + color .White + '━' * (barwidth - currentBar - 1 )
106+ else : bar = color_bar + '━' * (currentBar - 1 ) + color_bar + '╸' + color .White + '━' * (barwidth - currentBar )
67107
68- msg = f"{ prefix } { bar } { suffix } { Color .NC } "
108+ msg = f"{ prefix } { bar } { suffix } { color .NC } "
69109 print (msg , end = end )
70110
111+
112+
113+ # ________________________________________________________________________________
114+ # Stop the progress bar
115+
71116 def stop (self ):
72- self (self .lastProgress , stop = True )
73- self .lastProgress = 0
117+ self (self .previous_progress [ - 1 ] , stop = True )
118+ self .previous_progress = [ 0 ]
74119 self .lastUpdate = None
0 commit comments