1515
1616
1717class ProgressBar :
18+ """
19+ Usage Example:
20+ >>> pb = ProgressBar(width=20, show_percentage=False, prefix='[', suffix=']', fill='=', empty='-')
21+ >>> pb(0, 10)
22+ [/-----------------]
23+ >>> pb(1, 10)
24+ [==----------------]
25+ >>> pb(2, 10)
26+ [====\\ -------------]
27+ >>>
28+ >>> # A better example
29+ >>> import time
30+ >>> pb = ProgressBar()
31+ >>> for i in range(500):
32+ ... pb(i + 1, 500)
33+ ... time.sleep(0.01)
34+ ...
35+ |████████████████████████████████████████████████████████████████████████████████████████████| 100%
36+ >>> # Of course, You should try it yourself to see the progress! XD
37+ >>>
38+ """
1839
1940 def __init__ (self , * args , width : int = None , show_percentage : bool = True , prefix : str = '|' , suffix : str = '|' ,
20- fill : str = '█' , empty : str = ' ' , colors : dict = None , logger : '_log21.Logger' = _logger ):
41+ fill : str = '█' , empty : str = ' ' , format_ : str = None , style : str = '%' ,
42+ new_line_when_complete : bool = True , colors : dict = None , logger : '_log21.Logger' = _logger ):
2143 """
22- Example:
23- >>> pb = ProgressBar(width=20, show_percentage=False, prefix='[', suffix=']', fill='=', empty='-')
24- >>> pb(0, 10)
25- [/-----------------]
26- >>> pb(1, 10)
27- [==----------------]
28- >>> pb(2, 10)
29- [====\\ -------------]
30- >>>
31- >>> # A better example
32- >>> import time
33- >>> pb = ProgressBar()
34- >>> for i in range(500):
35- ... pb(i + 1, 500)
36- ... time.sleep(0.01)
37- ...
38- |████████████████████████████████████████████████████████████████████████████████████████████| 100%
39- >>> # Of course, You should try it yourself to see the progress! XD
40- >>>
41-
4244 :param args: Prevents the use of positional arguments
4345 :param width: The width of the progress bar
4446 :param show_percentage: Whether to show the percentage of the progress
4547 :param prefix: The prefix of the progress bar
4648 :param suffix: The suffix of the progress bar
4749 :param fill: The fill character of the progress bar
4850 :param empty: The empty character of the progress bar
51+ :param format_: The format of the progress bar
52+ :param style: The style that is used to format the progress bar
53+ :param new_line_when_complete: Whether to print a new line when the progress is complete or failed
4954 :param colors: The colors of the progress bar
5055 :param logger: The logger to use
5156 """
@@ -64,6 +69,8 @@ def __init__(self, *args, width: int = None, show_percentage: bool = True, prefi
6469 raise ValueError ('`fill` must be a single character' )
6570 if len (empty ) != 1 :
6671 raise ValueError ('`empty` must be a single character' )
72+ if style not in ['%' , '{' ]:
73+ raise ValueError ('`style` must be either `%` or `{`' )
6774
6875 self .colors = {
6976 'progress in-progress' : _gc ('LightYellow' ),
@@ -86,7 +93,14 @@ def __init__(self, *args, width: int = None, show_percentage: bool = True, prefi
8693 self .empty = empty
8794 self .prefix = prefix
8895 self .suffix = suffix
89- self .show_percentage = show_percentage
96+ if format_ :
97+ self .format = format_
98+ else :
99+ self .format = '%(prefix)s%(bar)s%(suffix)s %(percentage)s%%' if show_percentage else \
100+ '%(prefix)s%(bar)s%(suffix)s'
101+ style = '%'
102+ self .style = style
103+ self .new_line_when_complete = new_line_when_complete
90104 if colors :
91105 for key , value in colors .items ():
92106 self .colors [key ] = value
@@ -102,47 +116,113 @@ def get_bar(self, progress: float, total: float):
102116 return self .progress_in_progress (progress , total )
103117
104118 def progress_in_progress (self , progress : float , total : float ):
105- percentage = round (progress / total * 100 , 2 )
106- percentage_str = f' { percentage } %' if self .show_percentage else ''
107- fill_length = round (progress / total * (self .width - len (percentage_str ) - len (self .prefix ) - len (self .suffix )))
108- empty_length = (self .width - fill_length - len (percentage_str ) - len (self .prefix ) - len (self .suffix ))
119+ percentage = str (round (progress / total * 100 , 2 ))
120+ progress_dict = {
121+ 'prefix' : self .prefix ,
122+ 'bar' : '' ,
123+ 'suffix' : self .suffix ,
124+ 'percentage' : percentage
125+ }
126+
127+ if self .style == '%' :
128+ used_characters = len (self .format % progress_dict )
129+ elif self .style == '{' :
130+ used_characters = len (self .format .format (** progress_dict ))
131+ else :
132+ raise ValueError ('`style` must be either `%` or `{`' )
133+
134+ fill_length = round (progress / total * (self .width - used_characters ))
135+ empty_length = (self .width - (fill_length + used_characters )) - 1
109136
110137 if self .i >= 3 :
111138 self .i = 0
112139 else :
113140 self .i += 1
114141 spinner_char = self .spinner [self .i ] if empty_length > 0 else ''
115142
116- bar = '\r ' + self .colors ['prefix-color in-progress' ] + self .prefix + \
117- self .colors ['progress in-progress' ] + self .fill * fill_length + spinner_char + \
118- self .empty * (empty_length - 1 ) + \
119- self .colors ['suffix-color in-progress' ] + self .suffix
143+ progress_dict = {
144+ 'prefix' : self .colors ['prefix-color in-progress' ] + self .prefix + self .colors ['reset-color' ],
145+ 'bar' : self .colors ['progress in-progress' ] +
146+ (self .fill * fill_length + spinner_char + self .empty * empty_length ) + self .colors ['reset-color' ],
147+ 'suffix' : self .colors ['suffix-color in-progress' ] + self .suffix + self .colors ['reset-color' ],
148+ 'percentage' : self .colors ["percentage in-progress" ] + str (percentage ) + self .colors ['reset-color' ]
149+ }
150+
151+ if self .style == '%' :
152+ bar = self .format % progress_dict
153+ elif self .style == '{' :
154+ bar = self .format .format (** progress_dict )
155+ else :
156+ raise ValueError ('`style` must be either `%` or `{`' )
120157
121- return f' { bar } { self . colors [ "percentage in-progress" ] } { percentage_str } ' + self .colors ['reset-color' ]
158+ return ' \r ' + bar + self .colors ['reset-color' ]
122159
123160 def progress_complete (self ):
124- percentage_str = ' 100%' if self .show_percentage else ''
125- bar_length = self .width - len (percentage_str ) - len (self .prefix ) - len (self .suffix )
126- bar = '\r ' + self .colors ['prefix-color complete' ] + self .prefix + \
127- self .colors ['progress complete' ] + self .fill * bar_length + \
128- self .colors ['suffix-color complete' ] + self .suffix
161+ progress_dict = {
162+ 'prefix' : self .prefix ,
163+ 'bar' : '' ,
164+ 'suffix' : self .suffix ,
165+ 'percentage' : '100'
166+ }
167+
168+ if self .style == '%' :
169+ bar_length = self .width - len (self .format % progress_dict )
170+ elif self .style == '{' :
171+ bar_length = self .width - len (self .format .format (** progress_dict ))
172+ else :
173+ raise ValueError ('`style` must be either `%` or `{`' )
174+
175+ progress_dict = {
176+ 'prefix' : self .colors ['prefix-color complete' ] + self .prefix + self .colors ['reset-color' ],
177+ 'bar' : self .colors ['progress complete' ] + (self .fill * bar_length ) + self .colors ['reset-color' ],
178+ 'suffix' : self .colors ['suffix-color complete' ] + self .suffix + self .colors ['reset-color' ],
179+ 'percentage' : self .colors ["percentage complete" ] + '100' + self .colors ['reset-color' ]
180+ }
129181
130- return f'{ bar } { self .colors ["percentage complete" ]} { percentage_str } \n ' + self .colors ['reset-color' ]
182+ if self .style == '%' :
183+ bar = self .format % progress_dict
184+ elif self .style == '{' :
185+ bar = self .format .format (** progress_dict )
186+ else :
187+ raise ValueError ('`style` must be either `%` or `{`' )
188+
189+ return '\r ' + bar + self .colors ['reset-color' ] + ('\n ' if self .new_line_when_complete else '' )
131190
132191 def progress_failed (self , progress : float , total : float ):
133- percentage_str = ' Failed' if self .show_percentage else ''
134- bar_length = self .width - len (percentage_str ) - len (self .prefix ) - len (self .suffix )
192+ progress_dict = {
193+ 'prefix' : self .prefix ,
194+ 'bar' : '' ,
195+ 'suffix' : self .suffix ,
196+ 'percentage' : str (round (progress / total * 100 , 2 ))
197+ }
198+
199+ if self .style == '%' :
200+ bar_length = self .width - len (self .format % progress_dict )
201+ elif self .style == '{' :
202+ bar_length = self .width - len (self .format .format (** progress_dict ))
203+ else :
204+ raise ValueError ('`style` must be either `%` or `{`' )
135205
136206 if progress > total :
137207 bar_char = self .fill
138208 else :
139209 bar_char = self .empty
140210
141- bar = '\r ' + self .colors ['prefix-color failed' ] + self .prefix + \
142- self .colors ['progress failed' ] + bar_char * bar_length + \
143- self .colors ['suffix-color failed' ] + self .suffix
211+ progress_dict = {
212+ 'prefix' : self .colors ['prefix-color failed' ] + self .prefix + self .colors ['reset-color' ],
213+ 'bar' : self .colors ['progress failed' ] + (bar_char * bar_length ) + self .colors ['reset-color' ],
214+ 'suffix' : self .colors ['suffix-color failed' ] + self .suffix + self .colors ['reset-color' ],
215+ 'percentage' : self .colors ["percentage failed" ] + progress_dict ['percentage' ] + self .colors ['reset-color' ]
216+ }
217+
218+ if self .style == '%' :
219+ bar = self .format % progress_dict
220+ elif self .style == '{' :
221+ bar = self .format .format (** progress_dict )
222+ else :
223+ raise ValueError ('`style` must be either `%` or `{`' )
144224
145- return f' { bar } { self . colors [ "percentage failed" ] } { percentage_str } \n ' + self .colors ['reset-color' ]
225+ return ' \r ' + bar + self .colors ['reset-color' ] + ( ' \n ' if self . new_line_when_complete else '' )
146226
147227 def __call__ (self , progress : float , total : float , logger : '_log21.Logger' = None ):
148228 if not logger :
0 commit comments