~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/progress.py

  • Committer: Alexander Belchenko
  • Date: 2007-01-30 23:05:35 UTC
  • mto: This revision was merged to the branch mainline in revision 2259.
  • Revision ID: bialix@ukr.net-20070130230535-kx1rd478rtigyc3v
standalone installer: win98 support

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
 
"""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.
 
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.
29
27
"""
30
28
 
 
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
 
31
35
# TODO: Optionally show elapsed time instead/as well as ETA; nicer
32
36
# when the rate is unpredictable
33
37
 
46
50
 
47
51
 
48
52
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
 
    """
54
53
    isatty = getattr(f, 'isatty', None)
55
54
    if isatty is None:
56
55
        return False
75
74
        if _supports_progress(to_file):
76
75
            return TTYProgressBar(to_file=to_file, **kwargs)
77
76
        else:
78
 
            return DummyProgress(to_file=to_file, **kwargs)
 
77
            return DotsProgressBar(to_file=to_file, **kwargs)
79
78
    else:
80
79
        # Minor sanitation to prevent spurious errors
81
80
        requested_bar_type = requested_bar_type.lower().strip()
294
293
        self.child_fraction = 0
295
294
        self._have_output = False
296
295
    
 
296
 
297
297
    def throttle(self, old_msg):
298
298
        """Return True if the bar was updated too recently"""
299
299
        # time.time consistently takes 40/4000 ms = 0.01 ms.
315
315
        return False
316
316
        
317
317
    def tick(self):
318
 
        self.update(self.last_msg, self.last_cnt, self.last_total,
 
318
        self.update(self.last_msg, self.last_cnt, self.last_total, 
319
319
                    self.child_fraction)
320
320
 
321
321
    def child_update(self, message, current, total):
331
331
            self.last_msg = ''
332
332
        self.tick()
333
333
 
334
 
    def update(self, msg, current_cnt=None, total_cnt=None,
 
334
    def update(self, msg, current_cnt=None, total_cnt=None, 
335
335
               child_fraction=0):
336
336
        """Update and redraw progress bar."""
337
337
        if msg is None:
433
433
        self._have_output = True
434
434
        #self.to_file.flush()
435
435
            
436
 
    def clear(self):
 
436
    def clear(self):        
437
437
        if self._have_output:
438
438
            self.to_file.write('\r%s\r' % (' ' * (self.width - 1)))
439
439
        self._have_output = False
456
456
 
457
457
    def update(self, msg, current_cnt=None, total_cnt=None):
458
458
        self.current = current_cnt
459
 
        if total_cnt is not None:
460
 
            self.total = total_cnt
 
459
        self.total = total_cnt
461
460
        self.message = msg
462
461
        self.child_fraction = 0
463
462
        self.tick()
486
485
    def note(self, *args, **kwargs):
487
486
        self.parent.note(*args, **kwargs)
488
487
 
489
 
 
490
 
class InstrumentedProgress(TTYProgressBar):
491
 
    """TTYProgress variant that tracks outcomes"""
492
 
 
493
 
    def __init__(self, *args, **kwargs):
494
 
        self.always_throttled = True
495
 
        self.never_throttle = False
496
 
        TTYProgressBar.__init__(self, *args, **kwargs)
497
 
 
498
 
    def throttle(self, old_message):
499
 
        if self.never_throttle:
500
 
            result =  False
501
 
        else:
502
 
            result = TTYProgressBar.throttle(self, old_message)
503
 
        if result is False:
504
 
            self.always_throttled = False
505
 
 
506
 
 
 
488
 
507
489
def str_tdelta(delt):
508
490
    if delt is None:
509
491
        return "-:--:--"
561
543
            self.cur_phase = 0
562
544
        else:
563
545
            self.cur_phase += 1
564
 
        assert self.cur_phase < self.total
 
546
        assert self.cur_phase < self.total 
565
547
        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()