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 self.widgets = deepcopy(widgets) 

312 self.prefix = prefix 

313 self.suffix = suffix 

314 self.widget_kwargs = widget_kwargs or {} 

315 self.left_justify = left_justify 

316 self.value = initial_value 

317 self._iterable = None 

318 self.custom_len = custom_len 

319 self.init() 

320 

321 # Convert a given timedelta to a floating point number as internal 

322 # interval. We're not using timedelta's internally for two reasons: 

323 # 1. Backwards compatibility (most important one) 

324 # 2. Performance. Even though the amount of time it takes to compare a 

325 # timedelta with a float versus a float directly is negligible, this 

326 # comparison is run for _every_ update. With billions of updates 

327 # (downloading a 1GiB file for example) this adds up. 

328 poll_interval = utils.deltas_to_seconds(poll_interval, default=None) 

329 min_poll_interval = utils.deltas_to_seconds(min_poll_interval, 

330 default=None) 

331 self._MINIMUM_UPDATE_INTERVAL = utils.deltas_to_seconds( 

332 self._MINIMUM_UPDATE_INTERVAL) 

333 

334 # Note that the _MINIMUM_UPDATE_INTERVAL sets the minimum in case of 

335 # low values. 

336 self.poll_interval = poll_interval 

337 self.min_poll_interval = max( 

338 min_poll_interval or self._MINIMUM_UPDATE_INTERVAL, 

339 self._MINIMUM_UPDATE_INTERVAL, 

340 float(os.environ.get('PROGRESSBAR_MINIMUM_UPDATE_INTERVAL', 0)), 

341 ) 

342 

343 # A dictionary of names that can be used by Variable and FormatWidget 

344 self.variables = utils.AttributeDict(variables or {}) 

345 for widget in (self.widgets or []): 

346 if isinstance(widget, widgets_module.VariableMixin): 

347 if widget.name not in self.variables: 

348 self.variables[widget.name] = None 

349 

350 @property 

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

352 return self.variables 

353 

354 @dynamic_messages.setter 

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

356 self.variables = value 

357 

358 def init(self): 

359 ''' 

360 (re)initialize values to original state so the progressbar can be 

361 used (again) 

362 ''' 

363 self.previous_value = None 

364 self.last_update_time = None 

365 self.start_time = None 

366 self.updates = 0 

367 self.end_time = None 

368 self.extra = dict() 

369 self._last_update_timer = timeit.default_timer() 

370 

371 @property 

372 def percentage(self): 

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

374 

375 >>> progress = ProgressBar() 

376 >>> progress.max_value = 10 

377 >>> progress.min_value = 0 

378 >>> progress.value = 0 

379 >>> progress.percentage 

380 0.0 

381 >>> 

382 >>> progress.value = 1 

383 >>> progress.percentage 

384 10.0 

385 >>> progress.value = 10 

386 >>> progress.percentage 

387 100.0 

388 >>> progress.min_value = -10 

389 >>> progress.percentage 

390 100.0 

391 >>> progress.value = 0 

392 >>> progress.percentage 

393 50.0 

394 >>> progress.value = 5 

395 >>> progress.percentage 

396 75.0 

397 >>> progress.value = -5 

398 >>> progress.percentage 

399 25.0 

400 >>> progress.max_value = None 

401 >>> progress.percentage 

402 ''' 

403 if self.max_value is None or self.max_value is base.UnknownLength: 

404 return None 

405 elif self.max_value: 

406 todo = self.value - self.min_value 

407 total = self.max_value - self.min_value 

408 percentage = todo / total 

409 else: 

410 percentage = 1 

411 

412 return percentage * 100 

413 

414 def get_last_update_time(self): 

415 if self._last_update_time: 

416 return datetime.fromtimestamp(self._last_update_time) 

417 

418 def set_last_update_time(self, value): 

419 if value: 

420 self._last_update_time = time.mktime(value.timetuple()) 

421 else: 

422 self._last_update_time = None 

423 

424 last_update_time = property(get_last_update_time, set_last_update_time) 

425 

426 def data(self): 

427 ''' 

428 

429 Returns: 

430 dict: 

431 - `max_value`: The maximum value (can be None with 

432 iterators) 

433 - `start_time`: Start time of the widget 

434 - `last_update_time`: Last update time of the widget 

435 - `end_time`: End time of the widget 

436 - `value`: The current value 

437 - `previous_value`: The previous value 

438 - `updates`: The total update count 

439 - `total_seconds_elapsed`: The seconds since the bar started 

440 - `seconds_elapsed`: The seconds since the bar started modulo 

441 60 

442 - `minutes_elapsed`: The minutes since the bar started modulo 

443 60 

444 - `hours_elapsed`: The hours since the bar started modulo 24 

445 - `days_elapsed`: The hours since the bar started 

446 - `time_elapsed`: The raw elapsed `datetime.timedelta` object 

447 - `percentage`: Percentage as a float or `None` if no max_value 

448 is available 

449 - `dynamic_messages`: Deprecated, use `variables` instead. 

450 - `variables`: Dictionary of user-defined variables for the 

451 :py:class:`~progressbar.widgets.Variable`'s 

452 

453 ''' 

454 self._last_update_time = time.time() 

455 self._last_update_timer = timeit.default_timer() 

456 elapsed = self.last_update_time - self.start_time 

457 # For Python 2.7 and higher we have _`timedelta.total_seconds`, but we 

458 # want to support older versions as well 

459 total_seconds_elapsed = utils.deltas_to_seconds(elapsed) 

460 return dict( 

461 # The maximum value (can be None with iterators) 

462 max_value=self.max_value, 

463 # Start time of the widget 

464 start_time=self.start_time, 

465 # Last update time of the widget 

466 last_update_time=self.last_update_time, 

467 # End time of the widget 

468 end_time=self.end_time, 

469 # The current value 

470 value=self.value, 

471 # The previous value 

472 previous_value=self.previous_value, 

473 # The total update count 

474 updates=self.updates, 

475 # The seconds since the bar started 

476 total_seconds_elapsed=total_seconds_elapsed, 

477 # The seconds since the bar started modulo 60 

478 seconds_elapsed=(elapsed.seconds % 60) + 

479 (elapsed.microseconds / 1000000.), 

480 # The minutes since the bar started modulo 60 

481 minutes_elapsed=(elapsed.seconds / 60) % 60, 

482 # The hours since the bar started modulo 24 

483 hours_elapsed=(elapsed.seconds / (60 * 60)) % 24, 

484 # The hours since the bar started 

485 days_elapsed=(elapsed.seconds / (60 * 60 * 24)), 

486 # The raw elapsed `datetime.timedelta` object 

487 time_elapsed=elapsed, 

488 # Percentage as a float or `None` if no max_value is available 

489 percentage=self.percentage, 

490 # Dictionary of user-defined 

491 # :py:class:`progressbar.widgets.Variable`'s 

492 variables=self.variables, 

493 # Deprecated alias for `variables` 

494 dynamic_messages=self.variables, 

495 ) 

496 

497 def default_widgets(self): 

498 if self.max_value: 

499 return [ 

500 widgets.Percentage(**self.widget_kwargs), 

501 ' ', widgets.SimpleProgress( 

502 format='(%s)' % widgets.SimpleProgress.DEFAULT_FORMAT, 

503 **self.widget_kwargs), 

504 ' ', widgets.Bar(**self.widget_kwargs), 

505 ' ', widgets.Timer(**self.widget_kwargs), 

506 ' ', widgets.AdaptiveETA(**self.widget_kwargs), 

507 ] 

508 else: 

509 return [ 

510 widgets.AnimatedMarker(**self.widget_kwargs), 

511 ' ', widgets.BouncingBar(**self.widget_kwargs), 

512 ' ', widgets.Counter(**self.widget_kwargs), 

513 ' ', widgets.Timer(**self.widget_kwargs), 

514 ] 

515 

516 def __call__(self, iterable, max_value=None): 

517 'Use a ProgressBar to iterate through an iterable' 

518 if max_value is not None: 

519 self.max_value = max_value 

520 elif self.max_value is None: 

521 try: 

522 self.max_value = len(iterable) 

523 except TypeError: # pragma: no cover 

524 self.max_value = base.UnknownLength 

525 

526 self._iterable = iter(iterable) 

527 return self 

528 

529 def __iter__(self): 

530 return self 

531 

532 def __next__(self): 

533 try: 

534 value = next(self._iterable) 

535 if self.start_time is None: 

536 self.start() 

537 else: 

538 self.update(self.value + 1) 

539 return value 

540 except StopIteration: 

541 self.finish() 

542 raise 

543 except GeneratorExit: # pragma: no cover 

544 self.finish(dirty=True) 

545 raise 

546 

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

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

549 

550 def __enter__(self): 

551 return self 

552 

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

554 # an iterator. 

555 next = __next__ 

556 

557 def __iadd__(self, value): 

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

559 self.update(self.value + value) 

560 return self 

561 

562 def _format_widgets(self): 

563 result = [] 

564 expanding = [] 

565 width = self.term_width 

566 data = self.data() 

567 

568 for index, widget in enumerate(self.widgets): 

569 if isinstance(widget, widgets.WidgetBase) \ 

570 and not widget.check_size(self): 

571 continue 

572 elif isinstance(widget, widgets.AutoWidthWidgetBase): 

573 result.append(widget) 

574 expanding.insert(0, index) 

575 elif isinstance(widget, six.string_types): 

576 result.append(widget) 

577 width -= self.custom_len(widget) 

578 else: 

579 widget_output = converters.to_unicode(widget(self, data)) 

580 result.append(widget_output) 

581 width -= self.custom_len(widget_output) 

582 

583 count = len(expanding) 

584 while expanding: 

585 portion = max(int(math.ceil(width * 1. / count)), 0) 

586 index = expanding.pop() 

587 widget = result[index] 

588 count -= 1 

589 

590 widget_output = widget(self, data, portion) 

591 width -= self.custom_len(widget_output) 

592 result[index] = widget_output 

593 

594 return result 

595 

596 @classmethod 

597 def _to_unicode(cls, args): 

598 for arg in args: 

599 yield converters.to_unicode(arg) 

600 

601 def _format_line(self): 

602 'Joins the widgets and justifies the line' 

603 

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

605 

606 if self.left_justify: 

607 return widgets.ljust(self.term_width) 

608 else: 

609 return widgets.rjust(self.term_width) 

610 

611 def _needs_update(self): 

612 'Returns whether the ProgressBar should redraw the line.' 

613 delta = timeit.default_timer() - self._last_update_timer 

614 if delta < self.min_poll_interval: 

615 # Prevent updating too often 

616 return False 

617 elif self.poll_interval and delta > self.poll_interval: 

618 # Needs to redraw timers and animations 

619 return True 

620 

621 # Update if value increment is not large enough to 

622 # add more bars to progressbar (according to current 

623 # terminal width) 

624 try: 

625 divisor = self.max_value / self.term_width # float division 

626 if self.value // divisor != self.previous_value // divisor: 

627 return True 

628 except Exception: 

629 # ignore any division errors 

630 pass 

631 

632 # No need to redraw yet 

633 return False 

634 

635 def update(self, value=None, force=False, **kwargs): 

636 'Updates the ProgressBar to a new value.' 

637 if self.start_time is None: 

638 self.start() 

639 return self.update(value, force=force, **kwargs) 

640 

641 if value is not None and value is not base.UnknownLength: 

642 if self.max_value is base.UnknownLength: 

643 # Can't compare against unknown lengths so just update 

644 pass 

645 elif self.min_value <= value <= self.max_value: # pragma: no cover 

646 # Correct value, let's accept 

647 pass 

648 elif self.max_error: 

649 raise ValueError( 

650 'Value %s is out of range, should be between %s and %s' 

651 % (value, self.min_value, self.max_value)) 

652 else: 

653 self.max_value = value 

654 

655 self.previous_value = self.value 

656 self.value = value 

657 

658 # Save the updated values for dynamic messages 

659 variables_changed = False 

660 for key in kwargs: 

661 if key not in self.variables: 

662 raise TypeError( 

663 'update() got an unexpected keyword ' + 

664 'argument {0!r}'.format(key)) 

665 elif self.variables[key] != kwargs[key]: 

666 self.variables[key] = kwargs[key] 

667 variables_changed = True 

668 

669 if self._needs_update() or variables_changed or force: 

670 self.updates += 1 

671 ResizableMixin.update(self, value=value) 

672 ProgressBarBase.update(self, value=value) 

673 StdRedirectMixin.update(self, value=value) 

674 

675 # Only flush if something was actually written 

676 self.fd.flush() 

677 

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

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

680 

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

682 

683 Args: 

684 max_value (int): The maximum value of the progressbar 

685 reinit (bool): Initialize the progressbar, this is useful if you 

686 wish to reuse the same progressbar but can be disabled if 

687 data needs to be passed along to the next run 

688 

689 >>> pbar = ProgressBar().start() 

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

691 ... # do something 

692 ... pbar.update(i+1) 

693 ... 

694 >>> pbar.finish() 

695 ''' 

696 if init: 

697 self.init() 

698 

699 # Prevent multiple starts 

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

701 return self 

702 

703 if max_value is not None: 

704 self.max_value = max_value 

705 

706 if self.max_value is None: 

707 self.max_value = self._DEFAULT_MAXVAL 

708 

709 StdRedirectMixin.start(self, max_value=max_value) 

710 ResizableMixin.start(self, max_value=max_value) 

711 ProgressBarBase.start(self, max_value=max_value) 

712 

713 # Constructing the default widgets is only done when we know max_value 

714 if self.widgets is None: 

715 self.widgets = self.default_widgets() 

716 

717 if self.prefix: 

718 self.widgets.insert(0, widgets.FormatLabel( 

719 self.prefix, new_style=True)) 

720 

721 if self.suffix: 

722 self.widgets.append(widgets.FormatLabel( 

723 self.suffix, new_style=True)) 

724 

725 for widget in self.widgets: 

726 interval = getattr(widget, 'INTERVAL', None) 

727 if interval is not None: 

728 interval = utils.deltas_to_seconds(interval) 

729 

730 self.poll_interval = min( 

731 self.poll_interval or interval, 

732 interval, 

733 ) 

734 

735 self.num_intervals = max(100, self.term_width) 

736 # The `next_update` is kept for compatibility with external libs: 

737 # https://github.com/WoLpH/python-progressbar/issues/207 

738 self.next_update = 0 

739 

740 if self.max_value is not base.UnknownLength and self.max_value < 0: 

741 raise ValueError('max_value out of range, got %r' % self.max_value) 

742 

743 self.start_time = self.last_update_time = datetime.now() 

744 self._last_update_timer = timeit.default_timer() 

745 self.update(self.min_value, force=True) 

746 

747 return self 

748 

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

750 ''' 

751 Puts the ProgressBar bar in the finished state. 

752 

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

754 progressbar running. 

755 

756 Args: 

757 end (str): The string to end the progressbar with, defaults to a 

758 newline 

759 dirty (bool): When True the progressbar kept the current state and 

760 won't be set to 100 percent 

761 ''' 

762 

763 if not dirty: 

764 self.end_time = datetime.now() 

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

766 

767 StdRedirectMixin.finish(self, end=end) 

768 ResizableMixin.finish(self) 

769 ProgressBarBase.finish(self) 

770 

771 

772class DataTransferBar(ProgressBar): 

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

774 

775 This assumes that the values its given are numbers of bytes. 

776 ''' 

777 def default_widgets(self): 

778 if self.max_value: 

779 return [ 

780 widgets.Percentage(), 

781 ' of ', widgets.DataSize('max_value'), 

782 ' ', widgets.Bar(), 

783 ' ', widgets.Timer(), 

784 ' ', widgets.AdaptiveETA(), 

785 ] 

786 else: 

787 return [ 

788 widgets.AnimatedMarker(), 

789 ' ', widgets.DataSize(), 

790 ' ', widgets.Timer(), 

791 ] 

792 

793 

794class NullBar(ProgressBar): 

795 

796 ''' 

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

798 flags 

799 ''' 

800 

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

802 return self 

803 

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

805 return self 

806 

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

808 return self