[pypy-svn] r71833 - pypy/trunk/pypy/tool

fijal at codespeak.net fijal at codespeak.net
Sat Mar 6 00:31:55 CET 2010


Author: fijal
Date: Sat Mar  6 00:31:54 2010
New Revision: 71833

Added:
   pypy/trunk/pypy/tool/progressbar.py   (contents, props changed)
   pypy/trunk/pypy/tool/terminal.py   (contents, props changed)
Modified:
   pypy/trunk/pypy/tool/logparser.py
Log:
Having fun with fancier progress bars. Comes from here:
http://nadiana.com/animated-terminal-progress-bar-in-python

I like it more than the previous one.

Also make sure we don't output png to stdout


Modified: pypy/trunk/pypy/tool/logparser.py
==============================================================================
--- pypy/trunk/pypy/tool/logparser.py	(original)
+++ pypy/trunk/pypy/tool/logparser.py	Sat Mar  6 00:31:54 2010
@@ -9,6 +9,7 @@
 import autopath
 import sys, re
 from pypy.rlib.debug import DebugLog
+from pypy.tool import progressbar
 
 def parse_log_file(filename, verbose=True):
     r_start = re.compile(r"\[([0-9a-fA-F]+)\] \{([\w-]+)$")
@@ -29,14 +30,23 @@
     lines = f.readlines()
     f.close()
     #
+    if sys.stdout.isatty():
+        progress = progressbar.ProgressBar(color='green')
+    single_percent = len(lines) / 100
     if verbose:
-        vnext = 0
+        vnext = single_percent
     else:
         vnext = len(lines)
+    counter = 0
     for i, line in enumerate(lines):
         if i == vnext:
-            sys.stderr.write('%d%%..' % int(100.0*i/len(lines)))
-            vnext += 500000
+            counter += 1
+            if sys.stdout.isatty():
+                progress.render(counter)
+                vnext += single_percent
+            else:
+                sys.stderr.write('%d%%..' % int(100.0*i/len(lines)))
+                vnext += 500000
         line = line.rstrip()
         match = r_start.match(line)
         if match:
@@ -358,13 +368,13 @@
 
 if __name__ == '__main__':
     import getopt
-    if len(sys.argv) < 2:
+    if len(sys.argv) < 3:
         print __doc__
         sys.exit(2)
     action = sys.argv[1]
     func, longopts = ACTIONS[action]
     options, args = getopt.gnu_getopt(sys.argv[2:], '', longopts)
-    if len(args) != 1:
+    if len(args) != 2:
         print __doc__
         sys.exit(2)
 
@@ -373,4 +383,4 @@
         assert name.startswith('--')
         kwds[name[2:]] = value
     log = parse_log_file(args[0])
-    func(log, **kwds)
+    func(log, args[1], **kwds)

Added: pypy/trunk/pypy/tool/progressbar.py
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/tool/progressbar.py	Sat Mar  6 00:31:54 2010
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+# Copyright: 2009 Nadia Alramli
+# License: BSD
+"""Draws an animated terminal progress bar
+Usage:
+    p = ProgressBar("blue")
+    p.render(percentage, message)
+"""
+ 
+from pypy.tool import terminal
+import sys
+ 
+class ProgressBar(object):
+    """Terminal progress bar class"""
+    TEMPLATE = (
+     '%(percent)-2s%% %(color)s%(progress)s%(normal)s%(empty)s %(message)s\n'
+    )
+    PADDING = 7
+ 
+    def __init__(self, color=None, width=None, block='█', empty=' '):
+        """
+        color -- color name (BLUE GREEN CYAN RED MAGENTA YELLOW WHITE BLACK)
+        width -- bar width (optinal)
+        block -- progress display character (default '█')
+        empty -- bar display character (default ' ')
+        """
+        if color:
+            self.color = getattr(terminal, color.upper())
+        else:
+            self.color = ''
+        if width and width < terminal.COLUMNS - self.PADDING:
+            self.width = width
+        else:
+            # Adjust to the width of the terminal
+            self.width = terminal.COLUMNS - self.PADDING
+        self.block = block
+        self.empty = empty
+        self.progress = None
+        self.lines = 0
+ 
+    def render(self, percent, message = ''):
+        """Print the progress bar
+        percent -- the progress percentage %
+        message -- message string (optional)
+        """
+        inline_msg_len = 0
+        if message:
+            # The length of the first line in the message
+            inline_msg_len = len(message.splitlines()[0])
+        if inline_msg_len + self.width + self.PADDING > terminal.COLUMNS:
+            # The message is too long to fit in one line.
+            # Adjust the bar width to fit.
+            bar_width = terminal.COLUMNS - inline_msg_len -self.PADDING
+        else:
+            bar_width = self.width
+ 
+        # Check if render is called for the first time
+        if self.progress != None:
+            self.clear()
+        self.progress = (bar_width * percent) / 100
+        data = self.TEMPLATE % {
+            'percent': percent,
+            'color': self.color,
+            'progress': self.block * self.progress,
+            'normal': terminal.NORMAL,
+            'empty': self.empty * (bar_width - self.progress),
+            'message': message
+        }
+        sys.stdout.write(data)
+        sys.stdout.flush()
+        # The number of lines printed
+        self.lines = len(data.splitlines())
+ 
+    def clear(self):
+        """Clear all printed lines"""
+        sys.stdout.write(
+            self.lines * (terminal.UP + terminal.BOL + terminal.CLEAR_EOL)
+        )

Added: pypy/trunk/pypy/tool/terminal.py
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/tool/terminal.py	Sat Mar  6 00:31:54 2010
@@ -0,0 +1,81 @@
+# Copyright: 2009 Nadia Alramli
+# License: BSD
+
+"""Terminal controller module
+Example of usage:
+    print BG_BLUE + 'Text on blue background' + NORMAL
+    print BLUE + UNDERLINE + 'Blue underlined text' + NORMAL
+    print BLUE + BG_YELLOW + BOLD + 'text' + NORMAL
+"""
+
+import sys
+
+# The current module
+MODULE = sys.modules[__name__]
+
+COLORS = "BLUE GREEN CYAN RED MAGENTA YELLOW WHITE BLACK".split()
+# List of terminal controls, you can add more to the list.
+CONTROLS = {
+    'BOL':'cr', 'UP':'cuu1', 'DOWN':'cud1', 'LEFT':'cub1', 'RIGHT':'cuf1',
+    'CLEAR_SCREEN':'clear', 'CLEAR_EOL':'el', 'CLEAR_BOL':'el1',
+    'CLEAR_EOS':'ed', 'BOLD':'bold', 'BLINK':'blink', 'DIM':'dim',
+    'REVERSE':'rev', 'UNDERLINE':'smul', 'NORMAL':'sgr0',
+    'HIDE_CURSOR':'cinvis', 'SHOW_CURSOR':'cnorm'
+}
+
+# List of numeric capabilities
+VALUES = {
+    'COLUMNS':'cols', # Width of the terminal (None for unknown)
+    'LINES':'lines',  # Height of the terminal (None for unknown)
+    'MAX_COLORS': 'colors',
+}
+
+def default():
+    """Set the default attribute values"""
+    for color in COLORS:
+        setattr(MODULE, color, '')
+        setattr(MODULE, 'BG_%s' % color, '')
+    for control in CONTROLS:
+        setattr(MODULE, control, '')
+    for value in VALUES:
+        setattr(MODULE, value, None)
+
+def setup():
+    """Set the terminal control strings"""
+    # Initializing the terminal
+    curses.setupterm()
+    # Get the color escape sequence template or '' if not supported
+    # setab and setaf are for ANSI escape sequences
+    bgColorSeq = curses.tigetstr('setab') or curses.tigetstr('setb') or ''
+    fgColorSeq = curses.tigetstr('setaf') or curses.tigetstr('setf') or ''
+
+    for color in COLORS:
+        # Get the color index from curses
+        colorIndex = getattr(curses, 'COLOR_%s' % color)
+        # Set the color escape sequence after filling the template with index
+        setattr(MODULE, color, curses.tparm(fgColorSeq, colorIndex))
+        # Set background escape sequence
+        setattr(
+            MODULE, 'BG_%s' % color, curses.tparm(bgColorSeq, colorIndex)
+        )
+    for control in CONTROLS:
+        # Set the control escape sequence
+        setattr(MODULE, control, curses.tigetstr(CONTROLS[control]) or '')
+    for value in VALUES:
+        # Set terminal related values
+        setattr(MODULE, value, curses.tigetnum(VALUES[value]))
+
+def render(text):
+    """Helper function to apply controls easily
+    Example:
+    apply("%(GREEN)s%(BOLD)stext%(NORMAL)s") -> a bold green text
+    """
+    return text % MODULE.__dict__
+
+try:
+    import curses
+    setup()
+except Exception, e:
+    # There is a failure; set all attributes to default
+    print 'Warning: %s' % e
+    default()



More information about the Pypy-commit mailing list