~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/progress.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-01-13 05:14:24 UTC
  • mfrom: (3936.1.3 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20090113051424-nrk3zkfe09h46i9y
(mbp) merge 1.11 and advance to 1.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
17
 
18
18
 
19
 
"""Simple text-mode progress indicator.
20
 
 
21
 
To display an indicator, create a ProgressBar object.  Call it,
22
 
passing Progress objects indicating the current state.  When done,
23
 
call clear().
24
 
 
25
 
Progress is suppressed when output is not sent to a terminal, so as
26
 
not to clutter log files.
 
19
"""Progress indicators.
 
20
 
 
21
The usual way to use this is via bzrlib.ui.ui_factory.nested_progress_bar which
 
22
will maintain a ProgressBarStack for you.
 
23
 
 
24
For direct use, the factory ProgressBar will return an auto-detected progress
 
25
bar that should match your terminal type. You can manually create a
 
26
ProgressBarStack too if you need multiple levels of cooperating progress bars.
 
27
Note that bzrlib's internal functions use the ui module, so if you are using
 
28
bzrlib it really is best to use bzrlib.ui.ui_factory.
27
29
"""
28
30
 
29
 
# TODO: should be a global option e.g. --silent that disables progress
30
 
# indicators, preferably without needing to adjust all code that
31
 
# potentially calls them.
32
 
 
33
 
# TODO: If not on a tty perhaps just print '......' for the benefit of IDEs, etc
34
 
 
35
31
# TODO: Optionally show elapsed time instead/as well as ETA; nicer
36
32
# when the rate is unpredictable
37
33
 
50
46
 
51
47
 
52
48
def _supports_progress(f):
 
49
    """Detect if we can use pretty progress bars on the output stream f.
 
50
 
 
51
    If this returns true we expect that a human may be looking at that 
 
52
    output, and that we can repaint a line to update it.
 
53
    """
53
54
    isatty = getattr(f, 'isatty', None)
54
55
    if isatty is None:
55
56
        return False
74
75
        if _supports_progress(to_file):
75
76
            return TTYProgressBar(to_file=to_file, **kwargs)
76
77
        else:
77
 
            return DotsProgressBar(to_file=to_file, **kwargs)
 
78
            return DummyProgress(to_file=to_file, **kwargs)
78
79
    else:
79
80
        # Minor sanitation to prevent spurious errors
80
81
        requested_bar_type = requested_bar_type.lower().strip()
188
189
    def finished(self):
189
190
        """Return this bar to its progress stack."""
190
191
        self.clear()
191
 
        assert self._stack is not None
192
192
        self._stack.return_pb(self)
193
193
 
194
194
    def note(self, fmt_string, *args, **kwargs):
293
293
        self.child_fraction = 0
294
294
        self._have_output = False
295
295
    
296
 
 
297
296
    def throttle(self, old_msg):
298
297
        """Return True if the bar was updated too recently"""
299
298
        # time.time consistently takes 40/4000 ms = 0.01 ms.
315
314
        return False
316
315
        
317
316
    def tick(self):
318
 
        self.update(self.last_msg, self.last_cnt, self.last_total, 
 
317
        self.update(self.last_msg, self.last_cnt, self.last_total,
319
318
                    self.child_fraction)
320
319
 
321
320
    def child_update(self, message, current, total):
325
324
                pass
326
325
            elif self.last_cnt + child_fraction <= self.last_total:
327
326
                self.child_fraction = child_fraction
328
 
            else:
329
 
                mutter('not updating child fraction')
330
327
        if self.last_msg is None:
331
328
            self.last_msg = ''
332
329
        self.tick()
333
330
 
334
 
    def update(self, msg, current_cnt=None, total_cnt=None, 
 
331
    def update(self, msg, current_cnt=None, total_cnt=None,
335
332
               child_fraction=0):
336
333
        """Update and redraw progress bar."""
337
334
        if msg is None:
433
430
        self._have_output = True
434
431
        #self.to_file.flush()
435
432
            
436
 
    def clear(self):        
 
433
    def clear(self):
437
434
        if self._have_output:
438
435
            self.to_file.write('\r%s\r' % (' ' * (self.width - 1)))
439
436
        self._have_output = False
456
453
 
457
454
    def update(self, msg, current_cnt=None, total_cnt=None):
458
455
        self.current = current_cnt
459
 
        self.total = total_cnt
 
456
        if total_cnt is not None:
 
457
            self.total = total_cnt
460
458
        self.message = msg
461
459
        self.child_fraction = 0
462
460
        self.tick()
485
483
    def note(self, *args, **kwargs):
486
484
        self.parent.note(*args, **kwargs)
487
485
 
488
 
 
 
486
 
 
487
class InstrumentedProgress(TTYProgressBar):
 
488
    """TTYProgress variant that tracks outcomes"""
 
489
 
 
490
    def __init__(self, *args, **kwargs):
 
491
        self.always_throttled = True
 
492
        self.never_throttle = False
 
493
        TTYProgressBar.__init__(self, *args, **kwargs)
 
494
 
 
495
    def throttle(self, old_message):
 
496
        if self.never_throttle:
 
497
            result =  False
 
498
        else:
 
499
            result = TTYProgressBar.throttle(self, old_message)
 
500
        if result is False:
 
501
            self.always_throttled = False
 
502
 
 
503
 
489
504
def str_tdelta(delt):
490
505
    if delt is None:
491
506
        return "-:--:--"
515
530
    
516
531
    total_duration = float(elapsed) * float(total) / float(current)
517
532
 
518
 
    assert total_duration >= elapsed
519
 
 
520
533
    if last_updates and len(last_updates) >= n_recent:
521
534
        avg = sum(last_updates) / float(len(last_updates))
522
535
        time_left = avg * (total - current)
543
556
            self.cur_phase = 0
544
557
        else:
545
558
            self.cur_phase += 1
546
 
        assert self.cur_phase < self.total 
547
559
        self.pb.update(self.message, self.cur_phase, self.total)
548
 
 
549
 
 
550
 
def run_tests():
551
 
    import doctest
552
 
    result = doctest.testmod()
553
 
    if result[1] > 0:
554
 
        if result[0] == 0:
555
 
            print "All tests passed"
556
 
    else:
557
 
        print "No tests to run"
558
 
 
559
 
 
560
 
def demo():
561
 
    sleep = time.sleep
562
 
    
563
 
    print 'dumb-terminal test:'
564
 
    pb = DotsProgressBar()
565
 
    for i in range(100):
566
 
        pb.update('Leoparden', i, 99)
567
 
        sleep(0.1)
568
 
    sleep(1.5)
569
 
    pb.clear()
570
 
    sleep(1.5)
571
 
    
572
 
    print 'smart-terminal test:'
573
 
    pb = ProgressBar(show_pct=True, show_bar=True, show_spinner=False)
574
 
    for i in range(100):
575
 
        pb.update('Elephanten', i, 99)
576
 
        sleep(0.1)
577
 
    sleep(2)
578
 
    pb.clear()
579
 
    sleep(1)
580
 
 
581
 
    print 'done!'
582
 
 
583
 
if __name__ == "__main__":
584
 
    demo()