5 Commits
1.0.1 ... 1.0.2

Author SHA1 Message Date
Giorgos Verigakis
153733662f Bump version 2012-07-28 09:26:53 +08:00
Giorgos Verigakis
a3fb1b4fcc Add a start method
Use it to show progress without advancing
2012-07-18 10:50:56 +08:00
Giorgos Verigakis
3a3dea7069 Add hide/show cursor support 2012-05-09 16:57:08 +03:00
Giorgos Verigakis
c76da39d1a Use ANSI clear line instead of tracking line width 2012-05-09 16:56:17 +03:00
Giorgos Verigakis
32afe021ea Remove logic from update of base classes, so subclasses don't have to call super 2012-04-20 18:09:29 +03:00
5 changed files with 65 additions and 35 deletions

View File

@@ -19,7 +19,7 @@ from sys import stderr
from time import time
__version__ = '1.0.1'
__version__ = '1.0.2'
class Infinite(object):
@@ -35,28 +35,33 @@ class Infinite(object):
self.ctx[key] = val
self.index = 0
self.avg = None
self.avg = 0
self._ts = time()
def update_stats(self):
# Calculate moving average
now = time()
dt = now - self._ts
self._ts = now
w = self.avg_window
self.avg = dt if self.avg is None else (dt + w * self.avg) / (w + 1)
self.avg = dt if self.avg else (dt + w * self.avg) / (w + 1)
self._ts = now
def update(self):
self.update_stats()
kv = [(key, val) for key, val in self.__dict__.items()
if not key.startswith('_')]
self.ctx.update(kv)
def update(self):
pass
def start(self):
pass
def finish(self):
pass
def next(self):
self.index = self.index + 1
self.update_stats()
self.update()
def iter(self, it):
@@ -72,28 +77,36 @@ class Progress(Infinite):
def __init__(self, *args, **kwargs):
super(Progress, self).__init__(*args, **kwargs)
self.max = kwargs.get('max', 100)
self.eta = None
self.eta = 0
def update_stats(self):
if self.delta <= 0:
return
# Calculate moving average
now = time()
dt = (now - self._ts) / self.delta
self._ts = now
w = self.avg_window
self.avg = dt if self.avg is None else (dt + w * self.avg) / (w + 1)
self.progress = min(1, self.index / self.max)
self.percent = self.progress * 100
self.remaining = self.max - self.index
self.eta = int(ceil(self.avg * self.remaining))
# Calculate moving average
now = time()
if self.delta:
dt = (now - self._ts) / self.delta
w = self.avg_window
self.avg = dt if self.avg else (dt + w * self.avg) / (w + 1)
self.eta = int(ceil(self.avg * self.remaining))
self._ts = now
kv = [(key, val) for key, val in self.__dict__.items()
if not key.startswith('_')]
self.ctx.update(kv)
def start(self):
self.delta = 0
self.update_stats()
self.update()
def next(self):
prev = self.index
self.index = min(self.index + 1, self.max)
self.delta = self.index - prev
self.update_stats()
self.update()
def goto(self, index):
@@ -104,6 +117,7 @@ class Progress(Infinite):
self.index = index
self.delta = delta
self.update_stats()
self.update()
def iter(self, it):

View File

@@ -26,9 +26,9 @@ class Bar(WritelnMixin, Progress):
bar_suffix = '| '
empty_fill = ' '
fill = '#'
hide_cursor = True
def update(self):
super(Bar, self).update()
filled_length = int(self.width * self.progress)
empty_length = self.width - filled_length
@@ -63,8 +63,6 @@ class IncrementalBar(Bar):
phases = (u' ', u'', u'', u'', u'', u'', u'', u'', u'')
def update(self):
super(IncrementalBar, self).update()
nphases = len(self.phases)
expanded_length = int(nphases * self.width * self.progress)
filled_length = int(self.width * self.progress)

View File

@@ -20,23 +20,24 @@ from .helpers import WriteMixin
class Counter(WriteMixin, Infinite):
message = ''
hide_cursor = True
def update(self):
super(Counter, self).update()
self.write(str(self.index))
class Countdown(WriteMixin, Progress):
hide_cursor = True
def update(self):
super(Countdown, self).update()
self.write(str(self.remaining))
class Stack(WriteMixin, Progress):
phases = (u' ', u'', u'', u'', u'', u'', u'', u'', u'')
hide_cursor = True
def update(self):
super(Stack, self).update()
nphases = len(self.phases)
i = min(nphases - 1, int(self.progress * nphases))
self.write(self.phases[i])

View File

@@ -15,7 +15,13 @@
from __future__ import print_function
HIDE_CURSOR = '\x1b[?25l'
SHOW_CURSOR = '\x1b[?25h'
class WriteMixin(object):
hide_cursor = False
def __init__(self, message=None, **kwargs):
super(WriteMixin, self).__init__(**kwargs)
self._width = 0
@@ -23,6 +29,8 @@ class WriteMixin(object):
self.message = message
if self.file.isatty():
if self.hide_cursor:
print(HIDE_CURSOR, end='', file=self.file)
print(self.message, end='', file=self.file)
self.file.flush()
@@ -33,25 +41,34 @@ class WriteMixin(object):
self._width = max(self._width, len(s))
self.file.flush()
def finish(self):
if self.file.isatty() and self.hide_cursor:
print(SHOW_CURSOR, end='', file=self.file)
class WritelnMixin(object):
hide_cursor = False
def __init__(self, message=None, **kwargs):
super(WritelnMixin, self).__init__(**kwargs)
self.max_line_width = 0
if message:
self.message = message
def writeln(self, line):
if not self.file.isatty():
return
if len(line) > self.max_line_width:
self.max_line_width = len(line)
else:
line += ' ' * (self.max_line_width - len(line)) # Add padding
if self.file.isatty() and self.hide_cursor:
print(HIDE_CURSOR, end='', file=self.file)
print('\r' + line, end='', file=self.file)
self.file.flush()
def clearln(self):
if self.file.isatty():
print('\r\x1b[K', end='', file=self.file)
def writeln(self, line):
if self.file.isatty():
self.clearln()
print(line, end='', file=self.file)
self.file.flush()
def finish(self):
if self.file.isatty():
print(file=self.file)
if self.hide_cursor:
print(SHOW_CURSOR, end='', file=self.file)

View File

@@ -21,9 +21,9 @@ from .helpers import WriteMixin
class Spinner(WriteMixin, Infinite):
message = ''
phases = ('-', '\\', '|', '/')
hide_cursor = True
def update(self):
super(Spinner, self).update()
i = self.index % len(self.phases)
self.write(self.phases[i])