Coverage for /Volumes/workspace/python-progressbar/.tox/py27/lib/python2.7/site-packages/progressbar/bar.py : 100%

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.init()
333 # Convert a given timedelta to a floating point number as internal
334 # interval. We're not using timedelta's internally for two reasons:
335 # 1. Backwards compatibility (most important one)
336 # 2. Performance. Even though the amount of time it takes to compare a
337 # timedelta with a float versus a float directly is negligible, this
338 # comparison is run for _every_ update. With billions of updates
339 # (downloading a 1GiB file for example) this adds up.
340 poll_interval = utils.deltas_to_seconds(poll_interval, default=None)
341 min_poll_interval = utils.deltas_to_seconds(min_poll_interval,
342 default=None)
343 self._MINIMUM_UPDATE_INTERVAL = utils.deltas_to_seconds(
344 self._MINIMUM_UPDATE_INTERVAL)
346 # Note that the _MINIMUM_UPDATE_INTERVAL sets the minimum in case of
347 # low values.
348 self.poll_interval = poll_interval
349 self.min_poll_interval = max(
350 min_poll_interval or self._MINIMUM_UPDATE_INTERVAL,
351 self._MINIMUM_UPDATE_INTERVAL,
352 float(os.environ.get('PROGRESSBAR_MINIMUM_UPDATE_INTERVAL', 0)),
353 )
355 # A dictionary of names that can be used by Variable and FormatWidget
356 self.variables = utils.AttributeDict(variables or {})
357 for widget in (self.widgets or []):
358 if isinstance(widget, widgets_module.VariableMixin):
359 if widget.name not in self.variables:
360 self.variables[widget.name] = None
362 @property
363 def dynamic_messages(self): # pragma: no cover
364 return self.variables
366 @dynamic_messages.setter
367 def dynamic_messages(self, value): # pragma: no cover
368 self.variables = value
370 def init(self):
371 '''
372 (re)initialize values to original state so the progressbar can be
373 used (again)
374 '''
375 self.previous_value = None
376 self.last_update_time = None
377 self.start_time = None
378 self.updates = 0
379 self.end_time = None
380 self.extra = dict()
381 self._last_update_timer = timeit.default_timer()
383 @property
384 def percentage(self):
385 '''Return current percentage, returns None if no max_value is given
387 >>> progress = ProgressBar()
388 >>> progress.max_value = 10
389 >>> progress.min_value = 0
390 >>> progress.value = 0
391 >>> progress.percentage
392 0.0
393 >>>
394 >>> progress.value = 1
395 >>> progress.percentage
396 10.0
397 >>> progress.value = 10
398 >>> progress.percentage
399 100.0
400 >>> progress.min_value = -10
401 >>> progress.percentage
402 100.0
403 >>> progress.value = 0
404 >>> progress.percentage
405 50.0
406 >>> progress.value = 5
407 >>> progress.percentage
408 75.0
409 >>> progress.value = -5
410 >>> progress.percentage
411 25.0
412 >>> progress.max_value = None
413 >>> progress.percentage
414 '''
415 if self.max_value is None or self.max_value is base.UnknownLength:
416 return None
417 elif self.max_value:
418 todo = self.value - self.min_value
419 total = self.max_value - self.min_value
420 percentage = 100.0 * todo / total
421 else:
422 percentage = 100.0
424 return percentage
426 def get_last_update_time(self):
427 if self._last_update_time:
428 return datetime.fromtimestamp(self._last_update_time)
430 def set_last_update_time(self, value):
431 if value:
432 self._last_update_time = time.mktime(value.timetuple())
433 else:
434 self._last_update_time = None
436 last_update_time = property(get_last_update_time, set_last_update_time)
438 def data(self):
439 '''
441 Returns:
442 dict:
443 - `max_value`: The maximum value (can be None with
444 iterators)
445 - `start_time`: Start time of the widget
446 - `last_update_time`: Last update time of the widget
447 - `end_time`: End time of the widget
448 - `value`: The current value
449 - `previous_value`: The previous value
450 - `updates`: The total update count
451 - `total_seconds_elapsed`: The seconds since the bar started
452 - `seconds_elapsed`: The seconds since the bar started modulo
453 60
454 - `minutes_elapsed`: The minutes since the bar started modulo
455 60
456 - `hours_elapsed`: The hours since the bar started modulo 24
457 - `days_elapsed`: The hours since the bar started
458 - `time_elapsed`: The raw elapsed `datetime.timedelta` object
459 - `percentage`: Percentage as a float or `None` if no max_value
460 is available
461 - `dynamic_messages`: Deprecated, use `variables` instead.
462 - `variables`: Dictionary of user-defined variables for the
463 :py:class:`~progressbar.widgets.Variable`'s
465 '''
466 self._last_update_time = time.time()
467 self._last_update_timer = timeit.default_timer()
468 elapsed = self.last_update_time - self.start_time
469 # For Python 2.7 and higher we have _`timedelta.total_seconds`, but we
470 # want to support older versions as well
471 total_seconds_elapsed = utils.deltas_to_seconds(elapsed)
472 return dict(
473 # The maximum value (can be None with iterators)
474 max_value=self.max_value,
475 # Start time of the widget
476 start_time=self.start_time,
477 # Last update time of the widget
478 last_update_time=self.last_update_time,
479 # End time of the widget
480 end_time=self.end_time,
481 # The current value
482 value=self.value,
483 # The previous value
484 previous_value=self.previous_value,
485 # The total update count
486 updates=self.updates,
487 # The seconds since the bar started
488 total_seconds_elapsed=total_seconds_elapsed,
489 # The seconds since the bar started modulo 60
490 seconds_elapsed=(elapsed.seconds % 60) +
491 (elapsed.microseconds / 1000000.),
492 # The minutes since the bar started modulo 60
493 minutes_elapsed=(elapsed.seconds / 60) % 60,
494 # The hours since the bar started modulo 24
495 hours_elapsed=(elapsed.seconds / (60 * 60)) % 24,
496 # The hours since the bar started
497 days_elapsed=(elapsed.seconds / (60 * 60 * 24)),
498 # The raw elapsed `datetime.timedelta` object
499 time_elapsed=elapsed,
500 # Percentage as a float or `None` if no max_value is available
501 percentage=self.percentage,
502 # Dictionary of user-defined
503 # :py:class:`progressbar.widgets.Variable`'s
504 variables=self.variables,
505 # Deprecated alias for `variables`
506 dynamic_messages=self.variables,
507 )
509 def default_widgets(self):
510 if self.max_value:
511 return [
512 widgets.Percentage(**self.widget_kwargs),
513 ' ', widgets.SimpleProgress(
514 format='(%s)' % widgets.SimpleProgress.DEFAULT_FORMAT,
515 **self.widget_kwargs),
516 ' ', widgets.Bar(**self.widget_kwargs),
517 ' ', widgets.Timer(**self.widget_kwargs),
518 ' ', widgets.AdaptiveETA(**self.widget_kwargs),
519 ]
520 else:
521 return [
522 widgets.AnimatedMarker(**self.widget_kwargs),
523 ' ', widgets.BouncingBar(**self.widget_kwargs),
524 ' ', widgets.Counter(**self.widget_kwargs),
525 ' ', widgets.Timer(**self.widget_kwargs),
526 ]
528 def __call__(self, iterable, max_value=None):
529 'Use a ProgressBar to iterate through an iterable'
530 if max_value is not None:
531 self.max_value = max_value
532 elif self.max_value is None:
533 try:
534 self.max_value = len(iterable)
535 except TypeError: # pragma: no cover
536 self.max_value = base.UnknownLength
538 self._iterable = iter(iterable)
539 return self
541 def __iter__(self):
542 return self
544 def __next__(self):
545 try:
546 value = next(self._iterable)
547 if self.start_time is None:
548 self.start()
549 else:
550 self.update(self.value + 1)
551 return value
552 except StopIteration:
553 self.finish()
554 raise
555 except GeneratorExit: # pragma: no cover
556 self.finish(dirty=True)
557 raise
559 def __exit__(self, exc_type, exc_value, traceback):
560 self.finish(dirty=bool(exc_type))
562 def __enter__(self):
563 return self
565 # Create an alias so that Python 2.x won't complain about not being
566 # an iterator.
567 next = __next__
569 def __iadd__(self, value):
570 'Updates the ProgressBar by adding a new value.'
571 self.update(self.value + value)
572 return self
574 def _format_widgets(self):
575 result = []
576 expanding = []
577 width = self.term_width
578 data = self.data()
580 for index, widget in enumerate(self.widgets):
581 if isinstance(widget, widgets.WidgetBase) \
582 and not widget.check_size(self):
583 continue
584 elif isinstance(widget, widgets.AutoWidthWidgetBase):
585 result.append(widget)
586 expanding.insert(0, index)
587 elif isinstance(widget, six.string_types):
588 result.append(widget)
589 width -= self.custom_len(widget)
590 else:
591 widget_output = converters.to_unicode(widget(self, data))
592 result.append(widget_output)
593 width -= self.custom_len(widget_output)
595 count = len(expanding)
596 while expanding:
597 portion = max(int(math.ceil(width * 1. / count)), 0)
598 index = expanding.pop()
599 widget = result[index]
600 count -= 1
602 widget_output = widget(self, data, portion)
603 width -= self.custom_len(widget_output)
604 result[index] = widget_output
606 return result
608 @classmethod
609 def _to_unicode(cls, args):
610 for arg in args:
611 yield converters.to_unicode(arg)
613 def _format_line(self):
614 'Joins the widgets and justifies the line'
616 widgets = ''.join(self._to_unicode(self._format_widgets()))
618 if self.left_justify:
619 return widgets.ljust(self.term_width)
620 else:
621 return widgets.rjust(self.term_width)
623 def _needs_update(self):
624 'Returns whether the ProgressBar should redraw the line.'
625 delta = timeit.default_timer() - self._last_update_timer
626 if delta < self.min_poll_interval:
627 # Prevent updating too often
628 return False
629 elif self.poll_interval and delta > self.poll_interval:
630 # Needs to redraw timers and animations
631 return True
633 # Update if value increment is not large enough to
634 # add more bars to progressbar (according to current
635 # terminal width)
636 try:
637 divisor = self.max_value / self.term_width # float division
638 if self.value // divisor != self.previous_value // divisor:
639 return True
640 except Exception:
641 # ignore any division errors
642 pass
644 # No need to redraw yet
645 return False
647 def update(self, value=None, force=False, **kwargs):
648 'Updates the ProgressBar to a new value.'
649 if self.start_time is None:
650 self.start()
651 return self.update(value, force=force, **kwargs)
653 if value is not None and value is not base.UnknownLength:
654 if self.max_value is base.UnknownLength:
655 # Can't compare against unknown lengths so just update
656 pass
657 elif self.min_value <= value <= self.max_value: # pragma: no cover
658 # Correct value, let's accept
659 pass
660 elif self.max_error:
661 raise ValueError(
662 'Value %s is out of range, should be between %s and %s'
663 % (value, self.min_value, self.max_value))
664 else:
665 self.max_value = value
667 self.previous_value = self.value
668 self.value = value
670 # Save the updated values for dynamic messages
671 variables_changed = False
672 for key in kwargs:
673 if key not in self.variables:
674 raise TypeError(
675 'update() got an unexpected keyword ' +
676 'argument {0!r}'.format(key))
677 elif self.variables[key] != kwargs[key]:
678 self.variables[key] = kwargs[key]
679 variables_changed = True
681 if self._needs_update() or variables_changed or force:
682 self.updates += 1
683 ResizableMixin.update(self, value=value)
684 ProgressBarBase.update(self, value=value)
685 StdRedirectMixin.update(self, value=value)
687 # Only flush if something was actually written
688 self.fd.flush()
690 def start(self, max_value=None, init=True):
691 '''Starts measuring time, and prints the bar at 0%.
693 It returns self so you can use it like this:
695 Args:
696 max_value (int): The maximum value of the progressbar
697 reinit (bool): Initialize the progressbar, this is useful if you
698 wish to reuse the same progressbar but can be disabled if
699 data needs to be passed along to the next run
701 >>> pbar = ProgressBar().start()
702 >>> for i in range(100):
703 ... # do something
704 ... pbar.update(i+1)
705 ...
706 >>> pbar.finish()
707 '''
708 if init:
709 self.init()
711 # Prevent multiple starts
712 if self.start_time is not None: # pragma: no cover
713 return self
715 if max_value is not None:
716 self.max_value = max_value
718 if self.max_value is None:
719 self.max_value = self._DEFAULT_MAXVAL
721 StdRedirectMixin.start(self, max_value=max_value)
722 ResizableMixin.start(self, max_value=max_value)
723 ProgressBarBase.start(self, max_value=max_value)
725 # Constructing the default widgets is only done when we know max_value
726 if self.widgets is None:
727 self.widgets = self.default_widgets()
729 if self.prefix:
730 self.widgets.insert(0, widgets.FormatLabel(
731 self.prefix, new_style=True))
732 # Unset the prefix variable after applying so an extra start()
733 # won't keep copying it
734 self.prefix = None
736 if self.suffix:
737 self.widgets.append(widgets.FormatLabel(
738 self.suffix, new_style=True))
739 # Unset the suffix variable after applying so an extra start()
740 # won't keep copying it
741 self.suffix = None
743 for widget in self.widgets:
744 interval = getattr(widget, 'INTERVAL', None)
745 if interval is not None:
746 interval = utils.deltas_to_seconds(interval)
748 self.poll_interval = min(
749 self.poll_interval or interval,
750 interval,
751 )
753 self.num_intervals = max(100, self.term_width)
754 # The `next_update` is kept for compatibility with external libs:
755 # https://github.com/WoLpH/python-progressbar/issues/207
756 self.next_update = 0
758 if self.max_value is not base.UnknownLength and self.max_value < 0:
759 raise ValueError('max_value out of range, got %r' % self.max_value)
761 self.start_time = self.last_update_time = datetime.now()
762 self._last_update_timer = timeit.default_timer()
763 self.update(self.min_value, force=True)
765 return self
767 def finish(self, end='\n', dirty=False):
768 '''
769 Puts the ProgressBar bar in the finished state.
771 Also flushes and disables output buffering if this was the last
772 progressbar running.
774 Args:
775 end (str): The string to end the progressbar with, defaults to a
776 newline
777 dirty (bool): When True the progressbar kept the current state and
778 won't be set to 100 percent
779 '''
781 if not dirty:
782 self.end_time = datetime.now()
783 self.update(self.max_value, force=True)
785 StdRedirectMixin.finish(self, end=end)
786 ResizableMixin.finish(self)
787 ProgressBarBase.finish(self)
790class DataTransferBar(ProgressBar):
791 '''A progress bar with sensible defaults for downloads etc.
793 This assumes that the values its given are numbers of bytes.
794 '''
795 def default_widgets(self):
796 if self.max_value:
797 return [
798 widgets.Percentage(),
799 ' of ', widgets.DataSize('max_value'),
800 ' ', widgets.Bar(),
801 ' ', widgets.Timer(),
802 ' ', widgets.AdaptiveETA(),
803 ]
804 else:
805 return [
806 widgets.AnimatedMarker(),
807 ' ', widgets.DataSize(),
808 ' ', widgets.Timer(),
809 ]
812class NullBar(ProgressBar):
814 '''
815 Progress bar that does absolutely nothing. Useful for single verbosity
816 flags
817 '''
819 def start(self, *args, **kwargs):
820 return self
822 def update(self, *args, **kwargs):
823 return self
825 def finish(self, *args, **kwargs):
826 return self