Skip to content

Commit 13a1d7a

Browse files
committed
Add GranularBar widget
`GranularBar` is a widget that displays progress at a sub-character granularity by using multiple marker characters. Using the `GranularBar` in its default configuration will show a smooth progress bar using unicode block characters. More examples are provided in `examples.py`
1 parent 055d80b commit 13a1d7a

5 files changed

Lines changed: 91 additions & 0 deletions

File tree

README.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ of widgets:
6060
- `FormatCustomText <http://progressbar-2.readthedocs.io/en/latest/_modules/progressbar/widgets.html#FormatCustomText>`_
6161
- `FormatLabel <http://progressbar-2.readthedocs.io/en/latest/_modules/progressbar/widgets.html#FormatLabel>`_
6262
- `FormatLabelBar <http://progressbar-2.readthedocs.io/en/latest/_modules/progressbar/widgets.html#FormatLabel>`_
63+
- `GranularBar <http://progressbar-2.readthedocs.io/en/latest/_modules/progressbar/widgets.html#GranularBar>`_
6364
- `Percentage <http://progressbar-2.readthedocs.io/en/latest/_modules/progressbar/widgets.html#Percentage>`_
6465
- `PercentageLabelBar <http://progressbar-2.readthedocs.io/en/latest/_modules/progressbar/widgets.html#PercentageLabelBar>`_
6566
- `ReverseBar <http://progressbar-2.readthedocs.io/en/latest/_modules/progressbar/widgets.html#ReverseBar>`_

examples.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,19 @@ def multi_progress_bar_example(left=True):
176176
bar.update(progress, jobs=jobs, force=True)
177177
time.sleep(0.02)
178178

179+
@example
180+
def granular_progress_example():
181+
widgets=[
182+
progressbar.GranularBar(markers=" ▏▎▍▌▋▊▉█", left='', right='|'),
183+
progressbar.GranularBar(markers=" ▁▂▃▄▅▆▇█", left='', right='|'),
184+
progressbar.GranularBar(markers=" ▖▌▛█", left='', right='|'),
185+
progressbar.GranularBar(markers=" ░▒▓█", left='', right='|'),
186+
progressbar.GranularBar(markers=" ⡀⡄⡆⡇⣇⣧⣷⣿", left='', right='|'),
187+
progressbar.GranularBar(markers=" .oO", left='', right=''),
188+
]
189+
for i in progressbar.progressbar(range(100), widgets=widgets):
190+
time.sleep(0.03)
191+
179192

180193
@example
181194
def percentage_label_bar_example():

progressbar/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
VariableMixin,
2727
MultiRangeBar,
2828
MultiProgressBar,
29+
GranularBar,
2930
FormatLabelBar,
3031
PercentageLabelBar,
3132
Variable,
@@ -74,6 +75,7 @@
7475
'VariableMixin',
7576
'MultiRangeBar',
7677
'MultiProgressBar',
78+
'GranularBar',
7779
'FormatLabelBar',
7880
'PercentageLabelBar',
7981
'Variable',

progressbar/widgets.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,62 @@ def get_values(self, progress, data):
909909
return ranges
910910

911911

912+
class GranularBar(AutoWidthWidgetBase):
913+
'''A progressbar that can display progress at a sub-character granularity
914+
by using multiple marker characters.
915+
916+
Examples of markers:
917+
- Smooth: ` ▏▎▍▌▋▊▉█` (default)
918+
- Bar: ` ▁▂▃▄▅▆▇█`
919+
- Snake: ` ▖▌▛█`
920+
- Fade in: ` ░▒▓█`
921+
- Dots: ` ⡀⡄⡆⡇⣇⣧⣷⣿`
922+
- Growing circles: ` .oO`
923+
'''
924+
925+
def __init__(self, markers=' ▏▎▍▌▋▊▉█', left='|', right='|', **kwargs):
926+
'''Creates a customizable progress bar.
927+
928+
markers - string of characters to use as granular progress markers. The
929+
first character should represent 0% and the last 100%.
930+
Ex: ` .oO`
931+
left - string or callable object to use as a left border
932+
right - string or callable object to use as a right border
933+
'''
934+
self.markers = markers
935+
self.left = string_or_lambda(left)
936+
self.right = string_or_lambda(right)
937+
938+
AutoWidthWidgetBase.__init__(self, **kwargs)
939+
940+
def __call__(self, progress, data, width):
941+
left = converters.to_unicode(self.left(progress, data, width))
942+
right = converters.to_unicode(self.right(progress, data, width))
943+
width -= progress.custom_len(left) + progress.custom_len(right)
944+
945+
if progress.max_value is not base.UnknownLength \
946+
and progress.max_value > 0:
947+
percent = progress.value / progress.max_value
948+
else:
949+
percent = 0
950+
951+
num_chars = percent * width
952+
953+
marker = self.markers[-1] * int(num_chars)
954+
955+
marker_idx = int((num_chars % 1) * (len(self.markers) - 1))
956+
if marker_idx:
957+
marker += self.markers[marker_idx]
958+
959+
marker = converters.to_unicode(marker)
960+
961+
# Make sure we ignore invisible characters when filling
962+
width += len(marker) - progress.custom_len(marker)
963+
marker = marker.ljust(width, self.markers[0])
964+
965+
return left + marker + right
966+
967+
912968
class FormatLabelBar(FormatLabel, Bar):
913969
'''A bar which has a formatted label in the center.'''
914970
def __init__(self, format, **kwargs):

tests/test_monitor_progress.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,25 @@ def test_percentage_label_bar(testdir):
206206
]
207207

208208

209+
def test_granular_bar(testdir):
210+
result = testdir.runpython(testdir.makepyfile(_create_script(
211+
widgets='[progressbar.GranularBar(markers=" .oO")]',
212+
line_breaks=False,
213+
items=list(range(5)),
214+
)))
215+
pprint.pprint(result.stderr.lines, width=70)
216+
assert result.stderr.lines == [u'',
217+
u'| |',
218+
u'|OOOOOOOOOOO. |',
219+
u'|OOOOOOOOOOOOOOOOOOOOOOO |',
220+
u'|OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo |',
221+
u'|OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO. |',
222+
u'|OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO|',
223+
u'',
224+
u'|OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO|'
225+
]
226+
227+
209228
def test_colors(testdir):
210229
kwargs = dict(
211230
items=range(1),

0 commit comments

Comments
 (0)