diff --git a/clint/textui/__init__.py b/clint/textui/__init__.py index 7411343..dd730f9 100644 --- a/clint/textui/__init__.py +++ b/clint/textui/__init__.py @@ -13,6 +13,7 @@ colorama.init() from . import colored +from . import elapsedtime from . import progress from . import prompt diff --git a/clint/textui/elapsedtime.py b/clint/textui/elapsedtime.py new file mode 100644 index 0000000..df766e9 --- /dev/null +++ b/clint/textui/elapsedtime.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- + +""" +clint.textui.elapsedtime +~~~~~~~~~~~~~~~~~ + +This module provides a simple timer to measure elapsed time. + +""" + +from __future__ import absolute_import +from threading import Thread + +import time +import sys + +INDICATOR_TEMPLATE = '%s %s %s\r' +NO_INDICATOR_TEMPLATE = '%s %s\r' + +INDICATOR_CHARS = ['|', '/', '-', '\\'] + +STREAM = sys.stderr + + +class ElapsedTime(object): + """Timer class for measuring elapsed time. + This provides a timer with animation. + + Intended usage: + with ElapsedTime(*kwargs): + + """ + def __enter__(self): + th = Thread(target=self._print_indicator) + th.start() + return self + + def __exit__(self, type_, value, traceback): + self._done() + self._running = False + return False + + def __init__(self, label=None, indicator_chars=INDICATOR_CHARS, + interval=0.2, hidden=False): + self._running = True + self.label = label + self.indicator_chars = indicator_chars + self.interval = interval + self.hidden = hidden + self.label = label + if not self.label: + self.label = '' + self._start = time.time() + self._indicator_index = 0 + + def show(self): + """Write elapsed time to stream, with newline, without indicator.""" + self._write_time(newline=True, show_indicator=False) + + def reset(self): + """Reset the timer.""" + self._start = time.time() + + def _done(self): + if not self.hidden: + self._write_time(newline=True) + + def _show(self): + if not self.hidden: + self._write_time() + + def _write_time(self, newline=False, show_indicator=True): + elapsed = time.time() - self._start + elapsed_disp = ElapsedTime._format_time(elapsed) + if not self.indicator_chars or not show_indicator: + STREAM.write(NO_INDICATOR_TEMPLATE % ( + self.label, elapsed_disp)) + if newline: + STREAM.write('\n') + STREAM.flush() + else: + STREAM.write(INDICATOR_TEMPLATE % ( + self.label, self.indicator_chars[self._indicator_index], + elapsed_disp)) + if newline: + STREAM.write('\n') + STREAM.flush() + self._indicator_index = ( + (self._indicator_index+1) % len(self.indicator_chars)) + + def _print_indicator(self): + while self._running: + self._show() + time.sleep(self.interval) + + @staticmethod + def _format_time(seconds): + time_ = time.gmtime(seconds) + return time.strftime('%H:%M:%S', time_) diff --git a/examples/elapsedtime.py b/examples/elapsedtime.py new file mode 100755 index 0000000..4dd34f1 --- /dev/null +++ b/examples/elapsedtime.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import print_function + +import sys +import os + +sys.path.insert(0, os.path.abspath('..')) + +from time import sleep +from clint.textui import elapsedtime + + +if __name__ == '__main__': + # Basic use + with elapsedtime.ElapsedTime(): + sleep(3) + + # Use with options + with elapsedtime.ElapsedTime( + label='Running long job...', + interval=0.1, + indicator_chars=['o', 'O', '8']): + sleep(5) + + # Use without indicator + with elapsedtime.ElapsedTime( + label='Without indicator:', + indicator_chars=None): + sleep(3) + + # Hide the animated timer + with elapsedtime.ElapsedTime( + label='Elapsed time:', + hidden=True) as et: + for i in range(3): + print('This is loop: %d/3' % (i+1)) + sleep(1) + et.show() + + # Use without 'with' statement + et = elapsedtime.ElapsedTime(label='Without with:') + print('Running long job...') + sleep(3) + et.show() + et.reset() + print('Running another long job...') + sleep(3) + et.show()