Source code for looptime._internal.chronometers

from __future__ import annotations

import time
from typing import Any, Callable, TypeVar

from . import math

_SelfT = TypeVar('_SelfT', bound="Chronometer")


[docs] class Chronometer(math.Numeric): """ A helper context manager to measure the time of the code-blocks. Usage: .. code-block:: python import time def test_chronometer(): with Chronometer() as chronometer: time.sleep(1.23) # do something slow print(f"Executing for {chronometer.seconds}s already.") time.sleep(2.34) # do something slow again print(f"Executed in {chronometer.seconds}s.") assert chronometer.seconds < 5.0 # 3.57s or slightly more """ def __init__(self, clock: Callable[[], float] = time.perf_counter) -> None: super().__init__() self._clock = clock self._ts: float | None = None self._te: float | None = None @property def _value(self) -> float: return float(self.seconds or 0) @property def seconds(self) -> float | None: """The elapsed time in seconds (fractional).""" if self._ts is None: return None elif self._te is None: return self._clock() - self._ts else: return self._te - self._ts def __repr__(self) -> str: status = 'new' if self._ts is None else 'running' if self._te is None else 'finished' return f'<Chronometer: {self.seconds}s ({status})>' def __enter__(self: _SelfT) -> _SelfT: self._ts = self._clock() self._te = None return self def __exit__(self, *args: Any) -> None: self._te = self._clock() async def __aenter__(self: _SelfT) -> _SelfT: return self.__enter__() async def __aexit__(self, *args: Any) -> None: return self.__exit__(*args)
try: import pytest except ImportError: pass else: @pytest.fixture() def chronometer() -> Chronometer: return Chronometer()