Coverage for /Volumes/workspace/python-progressbar/.tox/py38/lib/python3.8/site-packages/progressbar/bar.py : 85%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from __future__ import absolute_import
2from __future__ import division
3from __future__ import unicode_literals
4from __future__ import with_statement
6import sys
7import math
8import os
9import time
10import timeit
11import logging
12import warnings
13from datetime import datetime
14from copy import deepcopy
15try: # pragma: no cover
16 from collections import abc
17except ImportError: # pragma: no cover
18 import collections as abc
20from python_utils import converters
22import six
24from . import widgets
25from . import widgets as widgets_module # Avoid name collision
26from . import base
27from . import utils
30logger = logging.getLogger(__name__)
33class ProgressBarMixinBase(object):
35 def __init__(self, **kwargs):
36 self._finished = False
38 def start(self, **kwargs):
39 pass
41 def update(self, value=None):
42 pass
44 def finish(self): # pragma: no cover
45 self._finished = True
47 def __del__(self):
48 if not self._finished: # pragma: no cover
49 try:
50 self.finish()
51 except Exception:
52 pass
55class ProgressBarBase(abc.Iterable, ProgressBarMixinBase):
56 pass
59class DefaultFdMixin(ProgressBarMixinBase):
61 def __init__(self, fd=sys.stderr, is_terminal=None, line_breaks=None,
62 enable_colors=None, **kwargs):
63 if fd is sys.stdout:
64 fd = utils.streams.original_stdout
66 elif fd is sys.stderr:
67 fd = utils.streams.original_stderr
69 self.fd = fd
70 self.is_ansi_terminal = utils.is_ansi_terminal(fd)
72 # Check if this is an interactive terminal
73 self.is_terminal = utils.is_terminal(
74 fd, is_terminal or self.is_ansi_terminal)
76 # Check if it should overwrite the current line (suitable for
77 # iteractive terminals) or write line breaks (suitable for log files)
78 if line_breaks is None:
79 line_breaks = utils.env_flag('PROGRESSBAR_LINE_BREAKS', not
80 self.is_terminal)
81 self.line_breaks = line_breaks
83 # Check if ANSI escape characters are enabled (suitable for iteractive
84 # terminals), or should be stripped off (suitable for log files)
85 if enable_colors is None:
86 enable_colors = utils.env_flag('PROGRESSBAR_ENABLE_COLORS',
87 self.is_ansi_terminal)
89 self.enable_colors = enable_colors
91 ProgressBarMixinBase.__init__(self, **kwargs)
93 def update(self, *args, **kwargs):
94 ProgressBarMixinBase.update(self, *args, **kwargs)
96 line = converters.to_unicode(self._format_line())
97 if not self.enable_colors:
98 line = utils.no_color(line)
100 if self.line_breaks:
101 line = line.rstrip() + '\n'
102 else:
103 line = '\r' + line
105 try: # pragma: no cover
106 self.fd.write(line)
107 except UnicodeEncodeError: # pragma: no cover
108 self.fd.write(line.encode('ascii', 'replace'))
110 def finish(self, *args, **kwargs): # pragma: no cover
111 if self._finished:
112 return
114 end = kwargs.pop('end', '\n')
115 ProgressBarMixinBase.finish(self, *args, **kwargs)
117 if end and not self.line_breaks:
118 self.fd.write(end)
120 self.fd.flush()
123class ResizableMixin(ProgressBarMixinBase):
125 def __init__(self, term_width=None, **kwargs):
126 ProgressBarMixinBase.__init__(self, **kwargs)
128 self.signal_set = False
129 if term_width:
130 self.term_width = term_width
131 else: # pragma: no cover
132 try:
133 self._handle_resize()
134 import signal
135 self._prev_handle = signal.getsignal(signal.SIGWINCH)
136 signal.signal(signal.SIGWINCH, self._handle_resize)
137 self.signal_set = True
138 except Exception:
139 pass
141 def _handle_resize(self, signum=None, frame=None):
142 'Tries to catch resize signals sent from the terminal.'
144 w, h = utils.get_terminal_size()
145 self.term_width = w
147 def finish(self): # pragma: no cover
148 ProgressBarMixinBase.finish(self)
149 if self.signal_set:
150 try:
151 import signal
152 signal.signal(signal.SIGWINCH, self._prev_handle)
153 except Exception: # pragma no cover
154 pass
157class StdRedirectMixin(DefaultFdMixin):
159 def __init__(self, redirect_stderr=False, redirect_stdout=False, **kwargs):
160 DefaultFdMixin.__init__(self, **kwargs)
161 self.redirect_stderr = redirect_stderr
162 self.redirect_stdout = redirect_stdout
163 self._stdout = self.stdout = sys.stdout
164 self._stderr = self.stderr = sys.stderr
166 def start(self, *args, **kwargs):
167 if self.redirect_stdout:
168 utils.streams.wrap_stdout()
170 if self.redirect_stderr:
171 utils.streams.wrap_stderr()
173 self._stdout = utils.streams.original_stdout
174 self._stderr = utils.streams.original_stderr
176 self.stdout = utils.streams.stdout
177 self.stderr = utils.streams.stderr
179 utils.streams.start_capturing(self)
180 DefaultFdMixin.start(self, *args, **kwargs)
182 def update(self, value=None):
183 if not self.line_breaks and utils.streams.needs_clear():
184 self.fd.write('\r' + ' ' * self.term_width + '\r')
186 utils.streams.flush()
187 DefaultFdMixin.update(self, value=value)
189 def finish(self, end='\n'):
190 DefaultFdMixin.finish(self, end=end)
191 utils.streams.stop_capturing(self)
192 if self.redirect_stdout:
193 utils.streams.unwrap_stdout()
195 if self.redirect_stderr:
196 utils.streams.unwrap_stderr()
199class ProgressBar(StdRedirectMixin, ResizableMixin, ProgressBarBase):
201 '''The ProgressBar class which updates and prints the bar.
203 Args:
204 min_value (int): The minimum/start value for the progress bar
205 max_value (int): The maximum/end value for the progress bar.
206 Defaults to `_DEFAULT_MAXVAL`
207 widgets (list): The widgets to render, defaults to the result of
208 `default_widget()`
209 left_justify (bool): Justify to the left if `True` or the right if
210 `False`
211 initial_value (int): The value to start with
212 poll_interval (float): The update interval in seconds.
213 Note that if your widgets include timers or animations, the actual
214 interval may be smaller (faster updates). Also note that updates
215 never happens faster than `min_poll_interval` which can be used for
216 reduced output in logs
217 min_poll_interval (float): The minimum update interval in seconds.
218 The bar will _not_ be updated faster than this, despite changes in
219 the progress, unless `force=True`. This is limited to be at least
220 `_MINIMUM_UPDATE_INTERVAL`. If available, it is also bound by the
221 environment variable PROGRESSBAR_MINIMUM_UPDATE_INTERVAL
222 widget_kwargs (dict): The default keyword arguments for widgets
223 custom_len (function): Method to override how the line width is
224 calculated. When using non-latin characters the width
225 calculation might be off by default
226 max_error (bool): When True the progressbar will raise an error if it
227 goes beyond it's set max_value. Otherwise the max_value is simply
228 raised when needed
229 prefix (str): Prefix the progressbar with the given string
230 suffix (str): Prefix the progressbar with the given string
231 variables (dict): User-defined variables variables that can be used
232 from a label using `format='{variables.my_var}'`. These values can
233 be updated using `bar.update(my_var='newValue')` This can also be
234 used to set initial values for variables' widgets
236 A common way of using it is like:
238 >>> progress = ProgressBar().start()
239 >>> for i in range(100):
240 ... progress.update(i + 1)
241 ... # do something
242 ...
243 >>> progress.finish()
245 You can also use a ProgressBar as an iterator:
247 >>> progress = ProgressBar()
248 >>> some_iterable = range(100)
249 >>> for i in progress(some_iterable):
250 ... # do something
251 ... pass
252 ...
254 Since the progress bar is incredibly customizable you can specify
255 different widgets of any type in any order. You can even write your own
256 widgets! However, since there are already a good number of widgets you
257 should probably play around with them before moving on to create your own
258 widgets.
260 The term_width parameter represents the current terminal width. If the
261 parameter is set to an integer then the progress bar will use that,
262 otherwise it will attempt to determine the terminal width falling back to
263 80 columns if the width cannot be determined.
265 When implementing a widget's update method you are passed a reference to
266 the current progress bar. As a result, you have access to the
267 ProgressBar's methods and attributes. Although there is nothing preventing
268 you from changing the ProgressBar you should treat it as read only.
270 Useful methods and attributes include (Public API):
271 - value: current progress (min_value <= value <= max_value)
272 - max_value: maximum (and final) value
273 - end_time: not None if the bar has finished (reached 100%)
274 - start_time: the time when start() method of ProgressBar was called
275 - seconds_elapsed: seconds elapsed since start_time and last call to
276 update
277 '''
279 _DEFAULT_MAXVAL = base.UnknownLength
280 # update every 50 milliseconds (up to a 20 times per second)
281 _MINIMUM_UPDATE_INTERVAL = 0.050
283 def __init__(self, min_value=0, max_value=None, widgets=None,
284 left_justify=True, initial_value=0, poll_interval=None,
285 widget_kwargs=None, custom_len=utils.len_color,
286 max_error=True, prefix=None, suffix=None, variables=None,
287 min_poll_interval=None, **kwargs):
288 '''
289 Initializes a progress bar with sane defaults
290 '''
291 StdRedirectMixin.__init__(self, **kwargs)
292 ResizableMixin.__init__(self, **kwargs)
293 ProgressBarBase.__init__(self, **kwargs)
294 if not max_value and kwargs.get('maxval') is not None:
295 warnings.warn('The usage of `maxval` is deprecated, please use '
296 '`max_value` instead', DeprecationWarning)
297 max_value = kwargs.get('maxval')
299 if not poll_interval and kwargs.get('poll'):
300 warnings.warn('The usage of `poll` is deprecated, please use '
301 '`poll_interval` instead', DeprecationWarning)
302 poll_interval = kwargs.get('poll')
304 if max_value:
305 if min_value > max_value:
306 raise ValueError('Max value needs to be bigger than the min '
307 'value')
308 self.min_value = min_value
309 self.max_value = max_value
310 self.max_error = max_error
312 # Only copy the widget if it's safe to copy. Most widgets are so we
313 # assume this to be true
314 if widgets is None:
315 self.widgets = widgets
316 else:
317 self.widgets = []
318 for widget in widgets:
319 if getattr(widget, 'copy', True):
320 widget = deepcopy(widget)
321 self.widgets.append(widget)
323 self.widgets = widgets
324 self.prefix = prefix
325 self.suffix = suffix
326 self.widget_kwargs = widget_kwargs or {}
327 self.left_justify = left_justify
328 self.value = initial_value
329 self._iterable = None
330 self.custom_len = custom_len
331 self.initial_start_time = kwargs.get('start_time')
332 self.init()
334 # Convert a given timedelta to a floating point number as internal
335 # interval. We're not using timedelta's internally for two reasons:
336 # 1. Backwards compatibility (most important one)
337 # 2. Performance. Even though the amount of time it takes to compare a
338 # timedelta with a float versus a float directly is negligible, this
339 # comparison is run for _every_ update. With billions of updates
340 # (downloading a 1GiB file for example) this adds up.
341 poll_interval = utils.deltas_to_seconds(poll_interval, default=None)
342 min_poll_interval = utils.deltas_to_seconds(min_poll_interval,
343 default=None)
344 self._MINIMUM_UPDATE_INTERVAL = utils.deltas_to_seconds(
345 self._MINIMUM_UPDATE_INTERVAL)
347 # Note that the _MINIMUM_UPDATE_INTERVAL sets the minimum in case of
348 # low values.
349 self.poll_interval = poll_interval
350 self.min_poll_interval = max(
351 min_poll_interval or self._MINIMUM_UPDATE_INTERVAL,
352 self._MINIMUM_UPDATE_INTERVAL,
353 float(os.environ.get('PROGRESSBAR_MINIMUM_UPDATE_INTERVAL', 0)),
354 )
356 # A dictionary of names that can be used by Variable and FormatWidget
357 self.variables = utils.AttributeDict(variables or {})
358 for widget in (self.widgets or []):
359 if isinstance(widget, widgets_module.VariableMixin):
360 if widget.name not in self.variables:
361 self.variables[widget.name] = None
363 @property
364 def dynamic_messages(self): # pragma: no cover
365 return self.variables
367 @dynamic_messages.setter
368 def dynamic_messages(self, value): # pragma: no cover
369 self.variables = value
371 def init(self):
372 '''
373 (re)initialize values to original state so the progressbar can be
374 used (again)
375 '''
376 self.previous_value = None
377 self.last_update_time = None
378 self.start_time = None
379 self.updates = 0
380 self.end_time = None
381 self.extra = dict()
382 self._last_update_timer = timeit.default_timer()
384 @property
385 def percentage(self):
386 '''Return current percentage, returns None if no max_value is given
388 >>> progress = ProgressBar()
389 >>> progress.max_value = 10
390 >>> progress.min_value = 0
391 >>> progress.value = 0
392 >>> progress.percentage
393 0.0
394 >>>
395 >>> progress.value = 1
396 >>> progress.percentage
397 10.0
398 >>> progress.value = 10
399 >>> progress.percentage
400 100.0
401 >>> progress.min_value = -10
402 >>> progress.percentage
403 100.0
404 >>> progress.value = 0
405 >>> progress.percentage
406 50.0
407 >>> progress.value = 5
408 >>> progress.percentage
409 75.0
410 >>> progress.value = -5
411 >>> progress.percentage
412 25.0
413 >>> progress.max_value = None
414 >>> progress.percentage
415 '''
416 if self.max_value is None or self.max_value is base.UnknownLength:
417 return None
418 elif self.max_value:
419 todo = self.value - self.min_value
420 total = self.max_value - self.min_value
421 percentage = 100.0 * todo / total
422 else:
423 percentage = 100.0
425 return percentage
427 def get_last_update_time(self):
428 if self._last_update_time:
429 return datetime.fromtimestamp(self._last_update_time)
431 def set_last_update_time(self, value):
432 if value:
433 self._last_update_time = time.mktime(value.timetuple())
434 else:
435 self._last_update_time = None
437 last_update_time = property(get_last_update_time, set_last_update_time)
439 def data(self):
440 '''
442 Returns:
443 dict:
444 - `max_value`: The maximum value (can be None with
445 iterators)
446 - `start_time`: Start time of the widget
447 - `last_update_time`: Last update time of the widget
448 - `end_time`: End time of the widget
449 - `value`: The current value
450 - `previous_value`: The previous value
451 - `updates`: The total update count
452 - `total_seconds_elapsed`: The seconds since the bar started
453 - `seconds_elapsed`: The seconds since the bar started modulo
454 60
455 - `minutes_elapsed`: The minutes since the bar started modulo
456 60
457 - `hours_elapsed`: The hours since the bar started modulo 24
458 - `days_elapsed`: The hours since the bar started
459 - `time_elapsed`: The raw elapsed `datetime.timedelta` object
460 - `percentage`: Percentage as a float or `None` if no max_value
461 is available
462 - `dynamic_messages`: Deprecated, use `variables` instead.
463 - `variables`: Dictionary of user-defined variables for the
464 :py:class:`~progressbar.widgets.Variable`'s
466 '''
467 self._last_update_time = time.time()
468 self._last_update_timer = timeit.default_timer()
469 elapsed = self.last_update_time - self.start_time
470 # For Python 2.7 and higher we have _`timedelta.total_seconds`, but we
471 # want to support older versions as well
472 total_seconds_elapsed = utils.deltas_to_seconds(elapsed)
473 return dict(
474 # The maximum value (can be None with iterators)
475 max_value=self.max_value,
476 # Start time of the widget
477 start_time=self.start_time,
478 # Last update time of the widget
479 last_update_time=self.last_update_time,
480 # End time of the widget
481 end_time=self.end_time,
482 # The current value
483 value=self.value,
484 # The previous value
485 previous_value=self.previous_value,
486 # The total update count
487 updates=self.updates,
488 # The seconds since the bar started
489 total_seconds_elapsed=total_seconds_elapsed,
490 # The seconds since the bar started modulo 60
491 seconds_elapsed=(elapsed.seconds % 60) +
492 (elapsed.microseconds / 1000000.),
493 # The minutes since the bar started modulo 60
494 minutes_elapsed=(elapsed.seconds / 60) % 60,
495 # The hours since the bar started modulo 24
496 hours_elapsed=(elapsed.seconds / (60 * 60)) % 24,
497 # The hours since the bar started
498 days_elapsed=(elapsed.seconds / (60 * 60 * 24)),
499 # The raw elapsed `datetime.timedelta` object
500 time_elapsed=elapsed,
501 # Percentage as a float or `None` if no max_value is available
502 percentage=self.percentage,
503 # Dictionary of user-defined
504 # :py:class:`progressbar.widgets.Variable`'s
505 variables=self.variables,
506 # Deprecated alias for `variables`
507 dynamic_messages=self.variables,
508 )
510 def default_widgets(self):
511 if self.max_value:
512 return [
513 widgets.Percentage(**self.widget_kwargs),
514 ' ', widgets.SimpleProgress(
515 format='(%s)' % widgets.SimpleProgress.DEFAULT_FORMAT,
516 **self.widget_kwargs),
517 ' ', widgets.Bar(**self.widget_kwargs),
518 ' ', widgets.Timer(**self.widget_kwargs),
519 ' ', widgets.AdaptiveETA(**self.widget_kwargs),
520 ]
521 else:
522 return [
523 widgets.AnimatedMarker(**self.widget_kwargs),
524 ' ', widgets.BouncingBar(**self.widget_kwargs),
525 ' ', widgets.Counter(**self.widget_kwargs),
526 ' ', widgets.Timer(**self.widget_kwargs),
527 ]
529 def __call__(self, iterable, max_value=None):
530 'Use a ProgressBar to iterate through an iterable'
531 if max_value is not None:
532 self.max_value = max_value
533 elif self.max_value is None:
534 try:
535 self.max_value = len(iterable)
536 except TypeError: # pragma: no cover
537 self.max_value = base.UnknownLength
539 self._iterable = iter(iterable)
540 return self
542 def __iter__(self):
543 return self
545 def __next__(self):
546 try:
547 value = next(self._iterable)
548 if self.start_time is None:
549 self.start()
550 else:
551 self.update(self.value + 1)
552 return value
553 except StopIteration:
554 self.finish()
555 raise
556 except GeneratorExit: # pragma: no cover
557 self.finish(dirty=True)
558 raise
560 def __exit__(self, exc_type, exc_value, traceback):
561 self.finish(dirty=bool(exc_type))
563 def __enter__(self):
564 return self
566 # Create an alias so that Python 2.x won't complain about not being
567 # an iterator.
568 next = __next__
570 def __iadd__(self, value):
571 'Updates the ProgressBar by adding a new value.'
572 self.update(self.value + value)
573 return self
575 def _format_widgets(self):
576 result = []
577 expanding = []
578 width = self.term_width
579 data = self.data()
581 for index, widget in enumerate(self.widgets):
582 if isinstance(widget, widgets.WidgetBase) \
583 and not widget.check_size(self):
584 continue
585 elif isinstance(widget, widgets.AutoWidthWidgetBase):
586 result.append(widget)
587 expanding.insert(0, index)
588 elif isinstance(widget, six.string_types):
589 result.append(widget)
590 width -= self.custom_len(widget)
591 else:
592 widget_output = converters.to_unicode(widget(self, data))
593 result.append(widget_output)
594 width -= self.custom_len(widget_output)
596 count = len(expanding)
597 while expanding:
598 portion = max(int(math.ceil(width * 1. / count)), 0)
599 index = expanding.pop()
600 widget = result[index]
601 count -= 1
603 widget_output = widget(self, data, portion)
604 width -= self.custom_len(widget_output)
605 result[index] = widget_output
607 return result
609 @classmethod
610 def _to_unicode(cls, args):
611 for arg in args:
612 yield converters.to_unicode(arg)
614 def _format_line(self):
615 'Joins the widgets and justifies the line'
617 widgets = ''.join(self._to_unicode(self._format_widgets()))
619 if self.left_justify:
620 return widgets.ljust(self.term_width)
621 else:
622 return widgets.rjust(self.term_width)
624 def _needs_update(self):
625 'Returns whether the ProgressBar should redraw the line.'
626 delta = timeit.default_timer() - self._last_update_timer
627 if delta < self.min_poll_interval:
628 # Prevent updating too often
629 return False
630 elif self.poll_interval and delta > self.poll_interval:
631 # Needs to redraw timers and animations
632 return True
634 # Update if value increment is not large enough to
635 # add more bars to progressbar (according to current
636 # terminal width)
637 try:
638 divisor = self.max_value / self.term_width # float division
639 if self.value // divisor != self.previous_value // divisor:
640 return True
641 except Exception:
642 # ignore any division errors
643 pass
645 # No need to redraw yet
646 return False
648 def update(self, value=None, force=False, **kwargs):
649 'Updates the ProgressBar to a new value.'
650 if self.start_time is None:
651 self.start()
652 return self.update(value, force=force, **kwargs)
654 if value is not None and value is not base.UnknownLength:
655 if self.max_value is base.UnknownLength:
656 # Can't compare against unknown lengths so just update
657 pass
658 elif self.min_value <= value <= self.max_value: # pragma: no cover
659 # Correct value, let's accept
660 pass
661 elif self.max_error:
662 raise ValueError(
663 'Value %s is out of range, should be between %s and %s'
664 % (value, self.min_value, self.max_value))
665 else:
666 self.max_value = value
668 self.previous_value = self.value
669 self.value = value
671 # Save the updated values for dynamic messages
672 variables_changed = False
673 for key in kwargs:
674 if key not in self.variables:
675 raise TypeError(
676 'update() got an unexpected keyword ' +
677 'argument {0!r}'.format(key))
678 elif self.variables[key] != kwargs[key]:
679 self.variables[key] = kwargs[key]
680 variables_changed = True
682 if self._needs_update() or variables_changed or force:
683 self.updates += 1
684 ResizableMixin.update(self, value=value)
685 ProgressBarBase.update(self, value=value)
686 StdRedirectMixin.update(self, value=value)
688 # Only flush if something was actually written
689 self.fd.flush()
691 def start(self, max_value=None, init=True):
692 '''Starts measuring time, and prints the bar at 0%.
694 It returns self so you can use it like this:
696 Args:
697 max_value (int): The maximum value of the progressbar
698 reinit (bool): Initialize the progressbar, this is useful if you
699 wish to reuse the same progressbar but can be disabled if
700 data needs to be passed along to the next run
702 >>> pbar = ProgressBar().start()
703 >>> for i in range(100):
704 ... # do something
705 ... pbar.update(i+1)
706 ...
707 >>> pbar.finish()
708 '''
709 if init:
710 self.init()
712 # Prevent multiple starts
713 if self.start_time is not None: # pragma: no cover
714 return self
716 if max_value is not None:
717 self.max_value = max_value
719 if self.max_value is None:
720 self.max_value = self._DEFAULT_MAXVAL
722 StdRedirectMixin.start(self, max_value=max_value)
723 ResizableMixin.start(self, max_value=max_value)
724 ProgressBarBase.start(self, max_value=max_value)
726 # Constructing the default widgets is only done when we know max_value
727 if self.widgets is None:
728 self.widgets = self.default_widgets()
730 if self.prefix:
731 self.widgets.insert(0, widgets.FormatLabel(
732 self.prefix, new_style=True))
733 # Unset the prefix variable after applying so an extra start()
734 # won't keep copying it
735 self.prefix = None
737 if self.suffix:
738 self.widgets.append(widgets.FormatLabel(
739 self.suffix, new_style=True))
740 # Unset the suffix variable after applying so an extra start()
741 # won't keep copying it
742 self.suffix = None
744 for widget in self.widgets:
745 interval = getattr(widget, 'INTERVAL', None)
746 if interval is not None:
747 interval = utils.deltas_to_seconds(interval)
749 self.poll_interval = min(
750 self.poll_interval or interval,
751 interval,
752 )
754 self.num_intervals = max(100, self.term_width)
755 # The `next_update` is kept for compatibility with external libs:
756 # https://github.com/WoLpH/python-progressbar/issues/207
757 self.next_update = 0
759 if self.max_value is not base.UnknownLength and self.max_value < 0:
760 raise ValueError('max_value out of range, got %r' % self.max_value)
762 now = datetime.now()
763 self.start_time = self.initial_start_time or now
764 self.last_update_time = now
765 self._last_update_timer = timeit.default_timer()
766 self.update(self.min_value, force=True)
768 return self
770 def finish(self, end='\n', dirty=False):
771 '''
772 Puts the ProgressBar bar in the finished state.
774 Also flushes and disables output buffering if this was the last
775 progressbar running.
777 Args:
778 end (str): The string to end the progressbar with, defaults to a
779 newline
780 dirty (bool): When True the progressbar kept the current state and
781 won't be set to 100 percent
782 '''
784 if not dirty:
785 self.end_time = datetime.now()
786 self.update(self.max_value, force=True)
788 StdRedirectMixin.finish(self, end=end)
789 ResizableMixin.finish(self)
790 ProgressBarBase.finish(self)
793class DataTransferBar(ProgressBar):
794 '''A progress bar with sensible defaults for downloads etc.
796 This assumes that the values its given are numbers of bytes.
797 '''
798 def default_widgets(self):
799 if self.max_value:
800 return [
801 widgets.Percentage(),
802 ' of ', widgets.DataSize('max_value'),
803 ' ', widgets.Bar(),
804 ' ', widgets.Timer(),
805 ' ', widgets.AdaptiveETA(),
806 ]
807 else:
808 return [
809 widgets.AnimatedMarker(),
810 ' ', widgets.DataSize(),
811 ' ', widgets.Timer(),
812 ]
815class NullBar(ProgressBar):
817 '''
818 Progress bar that does absolutely nothing. Useful for single verbosity
819 flags
820 '''
822 def start(self, *args, **kwargs):
823 return self
825 def update(self, *args, **kwargs):
826 return self
828 def finish(self, *args, **kwargs):
829 return self