Source code for idpconfgen.libs.libtimer

"""Manages time."""
import functools
import logging
import os
import sys
from time import time

from idpconfgen import assert_subclass, log
from idpconfgen.logger import S


[docs]def record_time(process_name='', *args, **kwargs): """ Record time of function execution. Use as decorator. """ def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): start = time() result = func(*args, **kwargs) log.info(S(f'elapsed time :{process_name}: {time() - start}')) return result return wrapper return decorator
# # def timeme(func): # @wraps(func) # def wrapper(*args, **kwargs): # s = time() # result = func(*args, **kwargs) # log.info(f'elapsed {func.__name__}: {time() - s:.3f} segs') # return result # return wrapper
[docs]def timeme(func, *args, **kwargs): """Log the time taken to run a function.""" s = time() result = func(*args, **kwargs) log.info(f'elapsed {func.__name__}: {time() - s:.3f} segs') return result
[docs]class ProgressWatcher: """Construct a Progress Watcher context.""" def __new__(cls, items, *args, **kwargs): """ Construct a progress representation. If possible, creates a progress bar based on the terminal window size and the length of items. If terminal window size is not measurable, mostly because execution is running on a server, ignores the creation of the bar. That is, returns a dummy representation. If items have no length (is a generator), returns a progression counter instead. Parameters ---------- items : iterable Items to represent. """ if not assert_subclass(log.handlers, logging.StreamHandler): return ProgressFake() try: # need cols later cols, lines = os.get_terminal_size() except OSError: log.warning( 'WARNING: Could not retrieve size from terminal window. ' 'Ignoring progress watcher.' ) return ProgressFake() try: litems = len(items) except TypeError: return ProgressCounter(**kwargs) else: return ProgressBar(litems, *args, bar_length=cols // 2, **kwargs)
[docs]class ProgressBar: """ Contextualize a Progress Bar. Parameters ---------- total : int convertable The total number o iteractions expected. prefix : str Some prefix to enhance readability. suffix : str Some suffix to enhance readability. decimals : int-convertable The demicals to show in percentage. Defaults to `1`. bar_length : int, float, -convertable The length of the bar. If not provided (``None``), uses 20. Thanks to for the initial template function: https://dev.to/natamacm/progressbar-in-python-a3n Examples -------- >>> with ProgressBar(5000, suffix='frames') as PB: >>> for i in trajectory: >>> # do something >>> PB.increment() """ def __init__( self, total, prefix='', suffix='', decimals=1, bar_length=20, ): self.total = int(total) self.prefix = prefix self.suffix = suffix self.percent_format = "{:>5." + str(int(decimals)) + "f}%" totals_format = "{:>" + str(len(str(self.total))) + "}" self.totals_format = f"{totals_format}/{totals_format}" self.counter = 0 self.bar_length = bar_length def __enter__(self): bar = '-' * self.bar_length percents = self.percent_format.format(0) totals = self.totals_format.format(self.counter, self.total) sys.stdout.write( f'\r{self.prefix} ' f'{percents} {totals} {self.suffix} |{bar}|' ) self.counter += 1 return self def __exit__(self, *args): sys.stdout.write('\n') sys.stdout.flush()
[docs] def increment(self): """Print next progress bar increment.""" t = self.total c = self.counter bl = self.bar_length percents = self.percent_format.format(c / t * 100) totals = self.totals_format.format(c, t) fl = int(round(bl * c // t)) bar = f"{'█' * fl}{'-' * (bl - fl)}" sys.stdout.write( f'\r{self.prefix} {percents} {totals} {self.suffix} ' f'|{bar}|' ) self.counter += 1
[docs]class ProgressCounter: """Represent progression via a counter.""" def __init__(self, suffix='Running operations', **kwargs): """ Represent a progress counter. Used for progresses with unknown length. """ self.counter = 0 self.suffix = suffix def __enter__(self, *args, **kwargs): sys.stdout.write(f'\r{self.suffix}: 0') return self def __exit__(self, *args): sys.stdout.write('\n') sys.stdout.flush()
[docs] def increment(self): """ Increment counter by one. Represent progression in terminal. """ self.counter += 1 sys.stdout.write(f'\rRunning operations {self.suffix}: {self.counter}') return
[docs]class ProgressFake: """ Simulate the interface of ProgressBar but does nothing. Used in servers where ProgressBar makes no sense. """ def __init__(self, *args, **kwargs): return def __enter__(self, *args, **kwargs): return self def __exit__(self, *args, **kwargs): return
[docs] def increment(self): """ Simulate ProgressBar interface. Does nothing. """ return