Source code for cloudly.util.timer

from collections.abc import Callable
from time import perf_counter


[docs] def friendly_duration(seconds: float): msg = [] if seconds >= 3600: hours, seconds = divmod(seconds, 3600) hours = int(hours) if hours > 1: msg.append(f'{hours} hours') else: msg.append(f'{hours} hour') seconds = int(seconds) if seconds >= 60: minutes, seconds = divmod(seconds, 60) minutes = int(minutes) if minutes > 1: msg.append(f'{minutes} minutes') else: msg.append(f'{minutes} minute') seconds = int(seconds) if isinstance(seconds, int): if seconds > 1: msg.append(f'{seconds} seconds') else: msg.append(f'{seconds} second') else: msg.append(f'{round(seconds, 4)} seconds') return ' '.join(msg)
[docs] class timer: """ The class ``timer`` (intentionally un-capitalized) can be used as a function decorator or a block context manager. As a function decorator:: @timer() def myfunc(...) ... As a block timer:: with timer(name='block 1'): ... ... In the first usage, you usually leave `name` to the default behavior, which plugs in the name of the function that's being decorated. In the second usage, you may choose to specify a `name` for the enclosed block; otherwise, there is no printout of "... started" and "... finished" enclosing the execution of the block. The optional `print_func` is the builtin function `print` by default. It may be useful to pass in a logging function, such as `print_func=logger.info`. However, the line-number info of the log message will be with regard to the current module rather than the context where `timer` is being used. """
[docs] def __init__(self, name: str = None, *, print_func: Callable = None): self._name = name self._print_func = print_func or print
def __call__(self, f: Callable): def decorated(*args, **kwargs): if not self._name: self._name = f"function '{f.__name__}'" # TODO: also include package.module? with self: z = f(*args, **kwargs) return z return decorated
[docs] def __enter__(self): self._t0 = perf_counter() if self._name: self._print_func(f'"{self._name}" started ...')
[docs] def __exit__(self, *args, **kwargs): dur = friendly_duration(perf_counter() - self._t0) if self._name: self._print_func(f'... "{self._name}" finished after {dur}') else: self._print_func(f'... finished after {dur}')