[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