MM_AVH / mm_avh_working_space /utils /execution_timer.py
MattyMroz's picture
mm_avh_working_space
068ed60
"""
Module execution_timer provides an ExecutionTimer class
to measure the execution time of a code block.
It offers two usage options: as a context manager and as a decorator.
* Example usage as a context manager:
with ExecutionTimer():
main()
* Example usage as a decorator:
@execution_timer
def main():
# Code block to measure execution time
"""
from datetime import datetime
from time import perf_counter_ns
from dataclasses import dataclass
from rich.console import Console
@dataclass(slots=True)
class ExecutionTimer:
"""
ExecutionTimer is a context manager that measures the execution time of a code block.
It captures the start time, end time, and duration of the code block.
"""
start_date: datetime = None
end_date: datetime = None
start_time_ns: int = None
end_time_ns: int = None
console: Console = Console()
def __post_init__(self):
self.start_date = datetime.now()
self.start_time_ns = perf_counter_ns()
def __enter__(self) -> 'ExecutionTimer':
return self
def __exit__(self, exc_type, exc_val, exc_tb):
try:
self.end_date = datetime.now()
self.end_time_ns = perf_counter_ns()
self.display_time()
except AttributeError:
print('An error occurred: __exit__')
@staticmethod
def current_datetime(date: datetime) -> str:
"""
Formats a datetime object as a string in the format 'YYYY-MM-DD HH:MM:SS'.
"""
return f'[yellow]{date.year}-{date.month:02d}-{date.day:02d}' \
f' [white bold]{date.hour:02d}:{date.minute:02d}:{date.second:02d}'
def calculate_duration(self) -> str:
"""
Calculates the duration of the code block in hours, minutes, seconds, milliseconds,
microseconds, and nanoseconds.
"""
duration_ns: int = self.end_time_ns - self.start_time_ns
duration_s, duration_ns = map(int, divmod(duration_ns, 1_000_000_000))
duration_ms, duration_ns = map(int, divmod(duration_ns, 1_000_000))
duration_us, duration_ns = map(int, divmod(duration_ns, 1_000))
hours, remainder = map(int, divmod(duration_s, 3600))
minutes, seconds = map(int, divmod(remainder, 60))
return f'[white bold]{hours:02d}:{minutes:02d}:{seconds:02d}:' \
f'{duration_ms:03d}:{duration_us:03d}:{duration_ns:03d}'
def calculate_duration_alt(self) -> tuple[float, ...]:
"""
Calculates the duration of the code block in hours, minutes, and seconds
using an alternative method.
"""
duration_ns: int = self.end_time_ns - self.start_time_ns
hours_alt: float = duration_ns / 1_000_000_000 / 60 / 60
minutes_alt: float = duration_ns / 1_000_000_000 / 60
seconds_alt: float = duration_ns / 1_000_000_000
return hours_alt, minutes_alt, seconds_alt
def display_time(self):
"""
Displays the start date, end date, and duration of the code block execution.
"""
start_date_str: str = self.current_datetime(self.start_date)
end_date_str: str = self.current_datetime(self.end_date)
duration: str = self.calculate_duration()
hours_alt, minutes_alt, seconds_alt = map(
float, self.calculate_duration_alt())
self.console.print(
'\n[bold white]β•šβ•β•β•β•β•β•β•β•β•β•β• EXECUTION TIME ═══════════╝')
self.console.print(
'[bold bright_yellow] YYYY-MM-DD HH:MM:SS:ms :Β΅s :ns')
self.console.print(
f'[bright_red bold][[bold white]START[bright_red bold]] {start_date_str}')
self.console.print(
f'[bright_red bold][[bold white]END[bright_red bold]] {end_date_str}')
self.console.print(
f'[bright_red bold][[bold white]TIME[bright_red bold]] [bold bright_yellow]YYYY-MM-DD {duration}')
self.console.print('[bright_red bold] ^^^^^^^^^^^^')
self.console.print(
f'[bright_red bold][[bold white]TIME[bright_red bold]] [white bold]{hours_alt:.9f} hours')
self.console.print(
f'[bright_red bold][[bold white]TIME[bright_red bold]] [white bold]{minutes_alt:.9f} minutes')
self.console.print(
f'[bright_red bold][[bold white]TIME[bright_red bold]] [white bold]{seconds_alt:.9f} seconds')
def execution_timer(func):
"""
Decorator that measures the execution time of a function using ExecutionTimer.
"""
def wrapper(*args, **kwargs):
with ExecutionTimer():
result = func(*args, **kwargs)
return result
return wrapper