Hide keyboard shortcuts

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 

5 

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 

19 

20from python_utils import converters 

21 

22import six 

23 

24from . import widgets 

25from . import widgets as widgets_module # Avoid name collision 

26from . import base 

27from . import utils 

28 

29 

30logger = logging.getLogger(__name__) 

31 

32 

33class ProgressBarMixinBase(object): 

34 

35 def __init__(self, **kwargs): 

36 self._finished = False 

37 

38 def start(self, **kwargs): 

39 pass 

40 

41 def update(self, value=None): 

42 pass 

43 

44 def finish(self): # pragma: no cover 

45 self._finished = True 

46 

47 def __del__(self): 

48 if not self._finished: # pragma: no cover 

49 try: 

50 self.finish() 

51 except Exception: 

52 pass 

53 

54 

55class ProgressBarBase(abc.Iterable, ProgressBarMixinBase): 

56 pass 

57 

58 

59class DefaultFdMixin(ProgressBarMixinBase): 

60 

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 

65 

66 elif fd is sys.stderr: 

67 fd = utils.streams.original_stderr 

68 

69 self.fd = fd 

70 self.is_ansi_terminal = utils.is_ansi_terminal(fd) 

71 

72 # Check if this is an interactive terminal 

73 self.is_terminal = utils.is_terminal( 

74 fd, is_terminal or self.is_ansi_terminal) 

75 

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 

82 

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) 

88 

89 self.enable_colors = enable_colors 

90 

91 ProgressBarMixinBase.__init__(self, **kwargs) 

92 

93 def update(self, *args, **kwargs): 

94 ProgressBarMixinBase.update(self, *args, **kwargs) 

95 

96 line = converters.to_unicode(self._format_line()) 

97 if not self.enable_colors: 

98 line = utils.no_color(line) 

99 

100 if self.line_breaks: 

101 line = line.rstrip() + '\n' 

102 else: 

103 line = '\r' + line 

104 

105 try: # pragma: no cover 

106 self.fd.write(line) 

107 except UnicodeEncodeError: # pragma: no cover 

108 self.fd.write(line.encode('ascii', 'replace')) 

109 

110 def finish(self, *args, **kwargs): # pragma: no cover 

111 if self._finished: 

112 return 

113 

114 end = kwargs.pop('end', '\n') 

115 ProgressBarMixinBase.finish(self, *args, **kwargs) 

116 

117 if end and not self.line_breaks: 

118 self.fd.write(end) 

119 

120 self.fd.flush() 

121 

122 

123class ResizableMixin(ProgressBarMixinBase): 

124 

125 def __init__(self, term_width=None, **kwargs): 

126 ProgressBarMixinBase.__init__(self, **kwargs) 

127 

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 

140 

141 def _handle_resize(self, signum=None, frame=None): 

142 'Tries to catch resize signals sent from the terminal.' 

143 

144 w, h = utils.get_terminal_size() 

145 self.term_width = w 

146 

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 

155 

156 

157class StdRedirectMixin(DefaultFdMixin): 

158 

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 

165 

166 def start(self, *args, **kwargs): 

167 if self.redirect_stdout: 

168 utils.streams.wrap_stdout() 

169 

170 if self.redirect_stderr: 

171 utils.streams.wrap_stderr() 

172 

173 self._stdout = utils.streams.original_stdout 

174 self._stderr = utils.streams.original_stderr 

175 

176 self.stdout = utils.streams.stdout 

177 self.stderr = utils.streams.stderr 

178 

179 utils.streams.start_capturing(self) 

180 DefaultFdMixin.start(self, *args, **kwargs) 

181 

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') 

185 

186 utils.streams.flush() 

187 DefaultFdMixin.update(self, value=value) 

188 

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() 

194 

195 if self.redirect_stderr: 

196 utils.streams.unwrap_stderr() 

197 

198 

199class ProgressBar(StdRedirectMixin, ResizableMixin, ProgressBarBase): 

200 

201 '''The ProgressBar class which updates and prints the bar. 

202 

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 

235 

236 A common way of using it is like: 

237 

238 >>> progress = ProgressBar().start() 

239 >>> for i in range(100): 

240 ... progress.update(i + 1) 

241 ... # do something 

242 ... 

243 >>> progress.finish() 

244 

245 You can also use a ProgressBar as an iterator: 

246 

247 >>> progress = ProgressBar() 

248 >>> some_iterable = range(100) 

249 >>> for i in progress(some_iterable): 

250 ... # do something 

251 ... pass 

252 ... 

253 

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. 

259 

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. 

264 

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. 

269 

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 ''' 

278 

279 _DEFAULT_MAXVAL = base.UnknownLength 

280 # update every 50 milliseconds (up to a 20 times per second) 

281 _MINIMUM_UPDATE_INTERVAL = 0.050 

282 

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') 

298 

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') 

303 

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 

311 

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) 

322 

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() 

333 

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) 

346 

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 ) 

355 

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 

362 

363 @property 

364 def dynamic_messages(self): # pragma: no cover 

365 return self.variables 

366 

367 @dynamic_messages.setter 

368 def dynamic_messages(self, value): # pragma: no cover 

369 self.variables = value 

370 

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() 

383 

384 @property 

385 def percentage(self): 

386 '''Return current percentage, returns None if no max_value is given 

387 

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 

424 

425 return percentage 

426 

427 def get_last_update_time(self): 

428 if self._last_update_time: 

429 return datetime.fromtimestamp(self._last_update_time) 

430 

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 

436 

437 last_update_time = property(get_last_update_time, set_last_update_time) 

438 

439 def data(self): 

440 ''' 

441 

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 

465 

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 ) 

509 

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 ] 

528 

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 

538 

539 self._iterable = iter(iterable) 

540 return self 

541 

542 def __iter__(self): 

543 return self 

544 

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 

559 

560 def __exit__(self, exc_type, exc_value, traceback): 

561 self.finish(dirty=bool(exc_type)) 

562 

563 def __enter__(self): 

564 return self 

565 

566 # Create an alias so that Python 2.x won't complain about not being 

567 # an iterator. 

568 next = __next__ 

569 

570 def __iadd__(self, value): 

571 'Updates the ProgressBar by adding a new value.' 

572 self.update(self.value + value) 

573 return self 

574 

575 def _format_widgets(self): 

576 result = [] 

577 expanding = [] 

578 width = self.term_width 

579 data = self.data() 

580 

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) 

595 

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 

602 

603 widget_output = widget(self, data, portion) 

604 width -= self.custom_len(widget_output) 

605 result[index] = widget_output 

606 

607 return result 

608 

609 @classmethod 

610 def _to_unicode(cls, args): 

611 for arg in args: 

612 yield converters.to_unicode(arg) 

613 

614 def _format_line(self): 

615 'Joins the widgets and justifies the line' 

616 

617 widgets = ''.join(self._to_unicode(self._format_widgets())) 

618 

619 if self.left_justify: 

620 return widgets.ljust(self.term_width) 

621 else: 

622 return widgets.rjust(self.term_width) 

623 

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 

633 

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 

644 

645 # No need to redraw yet 

646 return False 

647 

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) 

653 

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 

667 

668 self.previous_value = self.value 

669 self.value = value 

670 

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 

681 

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) 

687 

688 # Only flush if something was actually written 

689 self.fd.flush() 

690 

691 def start(self, max_value=None, init=True): 

692 '''Starts measuring time, and prints the bar at 0%. 

693 

694 It returns self so you can use it like this: 

695 

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 

701 

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() 

711 

712 # Prevent multiple starts 

713 if self.start_time is not None: # pragma: no cover 

714 return self 

715 

716 if max_value is not None: 

717 self.max_value = max_value 

718 

719 if self.max_value is None: 

720 self.max_value = self._DEFAULT_MAXVAL 

721 

722 StdRedirectMixin.start(self, max_value=max_value) 

723 ResizableMixin.start(self, max_value=max_value) 

724 ProgressBarBase.start(self, max_value=max_value) 

725 

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() 

729 

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 

736 

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 

743 

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) 

748 

749 self.poll_interval = min( 

750 self.poll_interval or interval, 

751 interval, 

752 ) 

753 

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 

758 

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) 

761 

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) 

767 

768 return self 

769 

770 def finish(self, end='\n', dirty=False): 

771 ''' 

772 Puts the ProgressBar bar in the finished state. 

773 

774 Also flushes and disables output buffering if this was the last 

775 progressbar running. 

776 

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 ''' 

783 

784 if not dirty: 

785 self.end_time = datetime.now() 

786 self.update(self.max_value, force=True) 

787 

788 StdRedirectMixin.finish(self, end=end) 

789 ResizableMixin.finish(self) 

790 ProgressBarBase.finish(self) 

791 

792 

793class DataTransferBar(ProgressBar): 

794 '''A progress bar with sensible defaults for downloads etc. 

795 

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 ] 

813 

814 

815class NullBar(ProgressBar): 

816 

817 ''' 

818 Progress bar that does absolutely nothing. Useful for single verbosity 

819 flags 

820 ''' 

821 

822 def start(self, *args, **kwargs): 

823 return self 

824 

825 def update(self, *args, **kwargs): 

826 return self 

827 

828 def finish(self, *args, **kwargs): 

829 return self