Created
December 14, 2020 23:02
-
-
Save groner/b06262f5c57e52edfe993c3ec1229ba5 to your computer and use it in GitHub Desktop.
stopwatch for terminal (python)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env python3 | |
import argparse | |
from contextlib import contextmanager | |
from datetime import datetime | |
from datetime import timedelta | |
from select import select | |
import termios | |
def main(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument('step', metavar='STEP', nargs='?', default='0.1', | |
help='time interval in seconds to update display') | |
parser.add_argument('-p', '--precision', metavar='PRECISION', type=int, | |
help='how many decimal places to show in seconds, defaults to the number in STEP') | |
args = parser.parse_args() | |
precision = args.precision | |
if precision is None: | |
precision = precision_of(args.step) | |
stopwatch(float(args.step), precision) | |
def stopwatch(step, precision): | |
# timedelta formats with microseconds, we want to trim any excess decimals | |
prec_pos = -6+precision | |
if prec_pos == -6: | |
prec_pos = -7 | |
fmt = lambda s: str(s)[:prec_pos] | |
# format is fixed width, so don't worry about clear to EOL | |
t0 = datetime.now() | |
with no_icanon_no_echo(): | |
while True: | |
print(f'\r{fmt(datetime.now()-t0)}', end='') | |
r,_,x = select([0], [], [0], step) | |
if r or x: | |
break | |
print(f'\r{fmt(datetime.now()-t0)}') | |
def precision_of(f): | |
# try to determine how much precision was specified after the decimal | |
if isinstance(f, str): | |
s = f | |
else: | |
s = f'{f:10f}'.rstrip('0') | |
if '.' in s: | |
return len(s.split('.', 1)[1]) | |
return 0 | |
@contextmanager | |
def no_icanon_no_echo(fd=0): | |
iflag, oflag, cflag, lflag, ispeed, ospeed, cc = termios.tcgetattr(fd) | |
termios.tcsetattr(fd, termios.TCSANOW, [ | |
iflag, | |
oflag, | |
cflag, | |
lflag & ~termios.ICANON & ~termios.ECHO, | |
ispeed, | |
ospeed, | |
cc]) | |
try: | |
yield | |
finally: | |
termios.tcflush(fd, termios.TCIFLUSH) | |
termios.tcsetattr(fd, termios.TCSANOW, [ | |
iflag, | |
oflag, | |
cflag, | |
lflag, | |
ispeed, | |
ospeed, | |
cc]) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Neat. Free lap-counter mode: