[Pkg-bazaar-commits] ./bzr/unstable r649: - some cleanups for the progressbar method

Martin Pool mbp at sourcefrog.net
Fri Apr 10 08:20:01 UTC 2009


------------------------------------------------------------
revno: 649
committer: Martin Pool <mbp at sourcefrog.net>
timestamp: Fri 2005-06-10 17:10:25 +1000
message:
  - some cleanups for the progressbar method
modified:
  bzrlib/progress.py
-------------- next part --------------
=== modified file 'bzrlib/progress.py'
--- a/bzrlib/progress.py	2005-06-10 07:02:15 +0000
+++ b/bzrlib/progress.py	2005-06-10 07:10:25 +0000
@@ -1,5 +1,5 @@
-# Copyright (C) 2005 Aaron Bentley
-# <aaron.bentley at utoronto.ca>
+# Copyright (C) 2005 Aaron Bentley <aaron.bentley at utoronto.ca>
+# Copyright (C) 2005 Canonical <canonical.com>
 #
 #    This program is free software; you can redistribute it and/or modify
 #    it under the terms of the GNU General Public License as published by
@@ -15,9 +15,47 @@
 #    along with this program; if not, write to the Free Software
 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
+
+"""
+Simple text-mode progress indicator.
+
+Everyone loves ascii art!
+
+To display an indicator, create a ProgressBar object.  Call it,
+passing Progress objects indicating the current state.  When done,
+call clear().
+
+Progress is suppressed when output is not sent to a terminal, so as
+not to clutter log files.
+"""
+
+# TODO: remove functions in favour of keeping everything in one class
+
+
 import sys
 import datetime
 
+
+def _width():
+    """Return estimated terminal width.
+
+    TODO: Do something smart on Windows?
+
+    TODO: Is there anything that gets a better update when the window
+          is resized while the program is running?
+    """
+    import os
+    try:
+        return int(os.environ['COLUMNS'])
+    except (IndexError, KeyError, ValueError):
+        return 80
+
+
+def _supports_progress(f):
+    return hasattr(f, 'isatty') and f.isatty()
+
+
+
 class Progress(object):
     def __init__(self, units, current, total=None):
         self.units = units
@@ -35,17 +73,30 @@
             return "%i of %i %s %.1f%%" % (self.current, self.total, self.units,
                                          self.percent)
         else:
-            return "%i %s" (self.current, self.units) 
+            return "%i %s" (self.current, self.units)
+
+
 
 class ProgressBar(object):
-    def __init__(self):
+    def __init__(self, to_file=sys.stderr):
+        object.__init__(self)
         self.start = None
-        object.__init__(self)
+        self.to_file = to_file
+        self.suppressed = not _supports_progress(self.to_file)
+
 
     def __call__(self, progress):
         if self.start is None:
             self.start = datetime.datetime.now()
-        progress_bar(progress, start_time=self.start)
+        if not self.suppressed:
+            draw_progress_bar(progress, start_time=self.start,
+                              to_file=self.to_file)
+
+    def clear(self):
+        if not self.suppressed:
+            clear_progress_bar(self.to_file)
+    
+
         
 def divide_timedelta(delt, divisor):
     """Divides a timedelta object"""
@@ -58,6 +109,7 @@
         return "-:--:--"
     return str(datetime.timedelta(delt.days, delt.seconds))
 
+
 def get_eta(start_time, progress, enough_samples=20):
     if start_time is None or progress.current == 0:
         return None
@@ -72,7 +124,8 @@
         eta = total_duration - total_duration
     return eta
 
-def progress_bar(progress, start_time=None):
+
+def draw_progress_bar(progress, start_time=None, to_file=sys.stderr):
     eta = get_eta(start_time, progress)
     if start_time is not None:
         eta_str = " "+str_tdelta(eta)
@@ -81,18 +134,18 @@
 
     fmt = " %i of %i %s (%.1f%%)"
     f = fmt % (progress.total, progress.total, progress.units, 100.0)
-    max = len(f)
-    cols = 77 - max
+    cols = _width() - 3 - len(f)
     if start_time is not None:
         cols -= len(eta_str)
     markers = int (float(cols) * progress.current / progress.total)
     txt = fmt % (progress.current, progress.total, progress.units,
                  progress.percent)
-    sys.stderr.write("\r[%s%s]%s%s" % ('='*markers, ' '*(cols-markers), txt, 
+    to_file.write("\r[%s%s]%s%s" % ('='*markers, ' '*(cols-markers), txt, 
                                        eta_str))
 
-def clear_progress_bar():
-    sys.stderr.write('\r%s\r' % (' '*79))
+def clear_progress_bar(to_file=sys.stderr):
+    to_file.write('\r%s\r' % (' '*79))
+
 
 def spinner_str(progress, show_text=False):
     """
@@ -114,6 +167,7 @@
         text+=" %i %s" % (progress.current, progress.units)
     return text
 
+
 def spinner(progress, show_text=False, output=sys.stderr):
     """
     Update a spinner progress indicator on an output
@@ -126,6 +180,7 @@
     """
     output.write('\r%s' % spinner_str(progress, show_text))
 
+
 def run_tests():
     import doctest
     result = doctest.testmod()
@@ -134,5 +189,15 @@
             print "All tests passed"
     else:
         print "No tests to run"
+
+
+def demo():
+    from time import sleep
+    pb = ProgressBar()
+    for i in range(100):
+        pb(Progress('Elephanten', i, 100))
+        sleep(0.3)
+    print 'done!'
+
 if __name__ == "__main__":
-    run_tests()
+    demo()



More information about the Pkg-bazaar-commits mailing list