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

332 

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) 

345 

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 ) 

354 

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 

361 

362 @property 

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

364 return self.variables 

365 

366 @dynamic_messages.setter 

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

368 self.variables = value 

369 

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

382 

383 @property 

384 def percentage(self): 

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

386 

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 

423 

424 return percentage 

425 

426 def get_last_update_time(self): 

427 if self._last_update_time: 

428 return datetime.fromtimestamp(self._last_update_time) 

429 

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 

435 

436 last_update_time = property(get_last_update_time, set_last_update_time) 

437 

438 def data(self): 

439 ''' 

440 

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 

464 

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 ) 

508 

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 ] 

527 

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 

537 

538 self._iterable = iter(iterable) 

539 return self 

540 

541 def __iter__(self): 

542 return self 

543 

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 

558 

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

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

561 

562 def __enter__(self): 

563 return self 

564 

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

566 # an iterator. 

567 next = __next__ 

568 

569 def __iadd__(self, value): 

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

571 self.update(self.value + value) 

572 return self 

573 

574 def _format_widgets(self): 

575 result = [] 

576 expanding = [] 

577 width = self.term_width 

578 data = self.data() 

579 

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) 

594 

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 

601 

602 widget_output = widget(self, data, portion) 

603 width -= self.custom_len(widget_output) 

604 result[index] = widget_output 

605 

606 return result 

607 

608 @classmethod 

609 def _to_unicode(cls, args): 

610 for arg in args: 

611 yield converters.to_unicode(arg) 

612 

613 def _format_line(self): 

614 'Joins the widgets and justifies the line' 

615 

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

617 

618 if self.left_justify: 

619 return widgets.ljust(self.term_width) 

620 else: 

621 return widgets.rjust(self.term_width) 

622 

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 

632 

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 

643 

644 # No need to redraw yet 

645 return False 

646 

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) 

652 

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 

666 

667 self.previous_value = self.value 

668 self.value = value 

669 

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 

680 

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) 

686 

687 # Only flush if something was actually written 

688 self.fd.flush() 

689 

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

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

692 

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

694 

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 

700 

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

710 

711 # Prevent multiple starts 

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

713 return self 

714 

715 if max_value is not None: 

716 self.max_value = max_value 

717 

718 if self.max_value is None: 

719 self.max_value = self._DEFAULT_MAXVAL 

720 

721 StdRedirectMixin.start(self, max_value=max_value) 

722 ResizableMixin.start(self, max_value=max_value) 

723 ProgressBarBase.start(self, max_value=max_value) 

724 

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

728 

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 

735 

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 

742 

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) 

747 

748 self.poll_interval = min( 

749 self.poll_interval or interval, 

750 interval, 

751 ) 

752 

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 

757 

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) 

760 

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) 

764 

765 return self 

766 

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

768 ''' 

769 Puts the ProgressBar bar in the finished state. 

770 

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

772 progressbar running. 

773 

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

780 

781 if not dirty: 

782 self.end_time = datetime.now() 

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

784 

785 StdRedirectMixin.finish(self, end=end) 

786 ResizableMixin.finish(self) 

787 ProgressBarBase.finish(self) 

788 

789 

790class DataTransferBar(ProgressBar): 

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

792 

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 ] 

810 

811 

812class NullBar(ProgressBar): 

813 

814 ''' 

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

816 flags 

817 ''' 

818 

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

820 return self 

821 

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

823 return self 

824 

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

826 return self