Skip to content

Commit 4f9eae3

Browse files
committed
merging...
2 parents 0bb6c66 + 959bfd6 commit 4f9eae3

12 files changed

Lines changed: 302 additions & 51 deletions

.coveragerc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ source =
66
omit =
77
*/mock/*
88
*/nose/*
9+
.tox/*
910
[paths]
1011
source =
1112
progressbar

.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ python:
99
- '3.7'
1010
- pypy
1111
install:
12-
- pip install .
13-
- pip install -r tests/requirements.txt
14-
before_script: flake8 progressbar tests
12+
- pip install -U .
13+
- pip install -U -r tests/requirements.txt
14+
before_script: flake8 progressbar tests examples
1515
script:
1616
- python setup.py test
1717
- python examples.py

examples.py

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ def example(fn):
1717
'''Wrap the examples so they generate readable output'''
1818

1919
@functools.wraps(fn)
20-
def wrapped():
20+
def wrapped(*args, **kwargs):
2121
try:
2222
sys.stdout.write('Running: %s\n' % fn.__name__)
23-
fn()
23+
fn(*args, **kwargs)
2424
sys.stdout.write('\n')
2525
except KeyboardInterrupt:
2626
sys.stdout.write('\nSkipping example.\n\n')
@@ -31,6 +31,14 @@ def wrapped():
3131
return wrapped
3232

3333

34+
@example
35+
def fast_example():
36+
''' Updates bar really quickly to cause flickering '''
37+
with progressbar.ProgressBar(widgets=[progressbar.Bar()]) as bar:
38+
for i in range(100):
39+
bar.update(int(i / 10), force=True)
40+
41+
3442
@example
3543
def shortcut_example():
3644
for i in progressbar.progressbar(range(10)):
@@ -73,7 +81,8 @@ def basic_widget_example():
7381

7482
@example
7583
def color_bar_example():
76-
widgets = ['\x1b[33mColorful example\x1b[39m', progressbar.Percentage(), progressbar.Bar(marker='\x1b[32m#\x1b[39m')]
84+
widgets = ['\x1b[33mColorful example\x1b[39m', progressbar.Percentage(),
85+
progressbar.Bar(marker='\x1b[32m#\x1b[39m')]
7786
bar = progressbar.ProgressBar(widgets=widgets, max_value=10).start()
7887
for i in range(10):
7988
# do something
@@ -82,6 +91,66 @@ def color_bar_example():
8291
bar.finish()
8392

8493

94+
@example
95+
def multi_range_bar_example():
96+
markers = [
97+
'\x1b[32m█\x1b[39m', # Done
98+
'\x1b[33m#\x1b[39m', # Processing
99+
'\x1b[31m.\x1b[39m', # Scheduling
100+
' ' # Not started
101+
]
102+
widgets = [progressbar.MultiRangeBar("amounts", markers=markers)]
103+
amounts = [0] * (len(markers) - 1) + [25]
104+
105+
with progressbar.ProgressBar(widgets=widgets, max_value=10).start() as bar:
106+
while True:
107+
incomplete_items = [
108+
idx
109+
for idx, amount in enumerate(amounts)
110+
for i in range(amount)
111+
if idx != 0
112+
]
113+
if not incomplete_items:
114+
break
115+
which = random.choice(incomplete_items)
116+
amounts[which] -= 1
117+
amounts[which - 1] += 1
118+
119+
bar.update(amounts=amounts, force=True)
120+
time.sleep(0.02)
121+
122+
123+
@example
124+
def multi_progress_bar_example(left=True):
125+
jobs = [
126+
# Each job takes between 1 and 10 steps to complete
127+
[0, random.randint(1, 10)]
128+
for i in range(25) # 25 jobs total
129+
]
130+
131+
widgets = [
132+
progressbar.Percentage(),
133+
' ', progressbar.MultiProgressBar('jobs', fill_left=left),
134+
]
135+
136+
max_value = sum([total for progress, total in jobs])
137+
with progressbar.ProgressBar(widgets=widgets, max_value=max_value) as bar:
138+
while True:
139+
incomplete_jobs = [
140+
idx
141+
for idx, (progress, total) in enumerate(jobs)
142+
if progress < total
143+
]
144+
if not incomplete_jobs:
145+
break
146+
which = random.choice(incomplete_jobs)
147+
jobs[which][0] += 1
148+
progress = sum([progress for progress, total in jobs])
149+
150+
bar.update(progress, jobs=jobs, force=True)
151+
time.sleep(0.02)
152+
153+
85154
@example
86155
def file_transfer_example():
87156
widgets = [
@@ -386,9 +455,9 @@ def increment_bar_with_output_redirection():
386455
' ', progressbar.ETA(),
387456
' ', progressbar.FileTransferSpeed(),
388457
]
389-
bar = progressbar.ProgressBar(widgets=widgets, max_value=1000,
458+
bar = progressbar.ProgressBar(widgets=widgets, max_value=100,
390459
redirect_stdout=True).start()
391-
for i in range(100):
460+
for i in range(10):
392461
# do something
393462
time.sleep(0.01)
394463
bar += 10
@@ -507,11 +576,12 @@ def user_variables():
507576
with progressbar.ProgressBar(
508577
prefix='{variables.task} >> {variables.subtask}',
509578
variables={'task': '--', 'subtask': '--'},
510-
max_value=10*num_subtasks) as bar:
579+
max_value=10 * num_subtasks) as bar:
511580
for tasks_name, subtasks in tasks.items():
512581
for subtask_name in subtasks:
513582
for i in range(10):
514-
bar.update(bar.value+1, task=tasks_name, subtask=subtask_name)
583+
bar.update(bar.value + 1, task=tasks_name,
584+
subtask=subtask_name)
515585
time.sleep(0.1)
516586

517587

progressbar/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
ReverseBar,
2424
BouncingBar,
2525
RotatingMarker,
26+
VariableMixin,
27+
MultiRangeBar,
28+
MultiProgressBar,
2629
Variable,
2730
DynamicMessage,
2831
FormatCustomText,
@@ -66,6 +69,9 @@
6669
'ProgressBar',
6770
'DataTransferBar',
6871
'RotatingMarker',
72+
'VariableMixin',
73+
'MultiRangeBar',
74+
'MultiProgressBar',
6975
'Variable',
7076
'DynamicMessage',
7177
'FormatCustomText',

progressbar/bar.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,7 @@ def __init__(self, fd=sys.stderr, is_terminal=None, line_breaks=None,
6868
self.fd = fd
6969

7070
# Check if this is an interactive terminal
71-
if is_terminal is None:
72-
is_terminal = utils.env_flag('PROGRESSBAR_IS_TERMINAL', None)
73-
if is_terminal is None: # pragma: no cover
74-
try:
75-
is_terminal = fd.isatty()
76-
except Exception:
77-
is_terminal = False
78-
self.is_terminal = is_terminal
71+
self.is_terminal = is_terminal = utils.is_terminal(fd, is_terminal)
7972

8073
# Check if it should overwrite the current line (suitable for
8174
# iteractive terminals) or write line breaks (suitable for log files)
@@ -180,8 +173,9 @@ def start(self, *args, **kwargs):
180173
DefaultFdMixin.start(self, *args, **kwargs)
181174

182175
def update(self, value=None):
183-
if not self.line_breaks:
176+
if not self.line_breaks and utils.streams.needs_clear():
184177
self.fd.write('\r' + ' ' * self.term_width + '\r')
178+
185179
utils.streams.flush()
186180
DefaultFdMixin.update(self, value=value)
187181

@@ -228,15 +222,15 @@ class ProgressBar(StdRedirectMixin, ResizableMixin, ProgressBarBase):
228222
prefix (str): Prefix the progressbar with the given string
229223
suffix (str): Prefix the progressbar with the given string
230224
variables (dict): User-defined variables variables that can be used
231-
from a label using `format="{variables.my_var}"`. These values can
232-
be updated using `bar.update(my_var="newValue")` This can also be
233-
used to set initial values for `Variable`s widgets
225+
from a label using `format='{variables.my_var}'`. These values can
226+
be updated using `bar.update(my_var='newValue')` This can also be
227+
used to set initial values for variables' widgets
234228
235229
A common way of using it is like:
236230
237231
>>> progress = ProgressBar().start()
238232
>>> for i in range(100):
239-
... progress.update(i+1)
233+
... progress.update(i + 1)
240234
... # do something
241235
...
242236
>>> progress.finish()
@@ -342,7 +336,7 @@ def __init__(self, min_value=0, max_value=None, widgets=None,
342336
# A dictionary of names that can be used by Variable and FormatWidget
343337
self.variables = utils.AttributeDict(variables or {})
344338
for widget in (self.widgets or []):
345-
if isinstance(widget, widgets_module.Variable):
339+
if isinstance(widget, widgets_module.VariableMixin):
346340
if widget.name not in self.variables:
347341
self.variables[widget.name] = None
348342

@@ -734,7 +728,7 @@ def start(self, max_value=None, init=True):
734728
self.next_update = 0
735729

736730
if self.max_value is not base.UnknownLength and self.max_value < 0:
737-
raise ValueError('Value out of range')
731+
raise ValueError('max_value out of range, got %r' % self.max_value)
738732

739733
self.start_time = self.last_update_time = datetime.now()
740734
self._last_update_timer = timeit.default_timer()

progressbar/utils.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,22 @@
2020
assert epoch
2121

2222

23+
def is_terminal(fd, is_terminal=None):
24+
if is_terminal is None:
25+
if 'JPY_PARENT_PID' in os.environ:
26+
is_terminal = True
27+
else:
28+
is_terminal = env_flag('PROGRESSBAR_IS_TERMINAL', None)
29+
30+
if is_terminal is None: # pragma: no cover
31+
try:
32+
is_terminal = fd.isatty()
33+
except Exception:
34+
is_terminal = False
35+
36+
return is_terminal
37+
38+
2339
def deltas_to_seconds(*deltas, **kwargs): # default=ValueError):
2440
'''
2541
Convert timedeltas and seconds as int to seconds as float while coalescing
@@ -122,17 +138,20 @@ def __init__(self, target, capturing=False, listeners=set()):
122138
self.target = target
123139
self.capturing = capturing
124140
self.listeners = listeners
141+
self.needs_clear = False
125142

126143
def write(self, value):
127144
if self.capturing:
128145
self.buffer.write(value)
129146
if '\n' in value:
147+
self.needs_clear = True
130148
for listener in self.listeners: # pragma: no branch
131149
listener.update()
132150
else:
133151
self.target.write(value)
134152

135153
def flush(self):
154+
self.needs_clear = False
136155
self.buffer.flush()
137156

138157
def _flush(self):
@@ -249,6 +268,11 @@ def unwrap_stderr(self):
249268
sys.stderr = self.original_stderr
250269
self.wrapped_stderr = 0
251270

271+
def needs_clear(self): # pragma: no cover
272+
stdout_needs_clear = getattr(self.stdout, 'needs_clear', False)
273+
stderr_needs_clear = getattr(self.stderr, 'needs_clear', False)
274+
return stderr_needs_clear or stdout_needs_clear
275+
252276
def flush(self):
253277
if self.wrapped_stdout: # pragma: no branch
254278
try:

0 commit comments

Comments
 (0)