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