Source code for pymove.utils.log

"""
Logging operations.

progress_bar
set_verbosity
timer_decorator

"""
from __future__ import annotations

import logging
import os
import time
from functools import wraps
from typing import Callable, Iterable

from IPython import get_ipython
from IPython.display import display
from ipywidgets import HTML, IntProgress, VBox
from tqdm import tqdm as _tqdm

from pymove.utils.datetime import deltatime_str

LOG_LEVEL = os.getenv('PYMOVE_VERBOSE', 'INFO')
logger = logging.getLogger('pymove')
shell_handler = logging.StreamHandler()
logger.setLevel(LOG_LEVEL)
shell_handler.setLevel(LOG_LEVEL)
logger.addHandler(shell_handler)


[docs]def set_verbosity(level): """Change logging level.""" logger.setLevel(level) shell_handler.setLevel(level)
[docs]def timer_decorator(func: Callable) -> Callable: """A decorator that prints how long a function took to run.""" @wraps(func) def wrapper(*args, **kwargs): t_start = time.time() result = func(*args, **kwargs) t_total = deltatime_str(time.time() - t_start) message = f'{func.__name__} took {t_total}' logger.debug('{}\n{}\n{}'.format('*' * len(message), message, '*' * len(message))) return result return wrapper
def _log_progress( sequence: Iterable, desc: str | None = None, total: int | None = None, miniters: int | None = None ): """ Make and display a progress bar. Parameters ---------- sequence : iterable Represents a sequence of elements. desc : str, optional Represents the description of the operation, by default None. total : int, optional Represents the total/number elements in sequence, by default None. miniters : int, optional Represents the steps in which the bar will be updated, by default None. """ if desc is None: desc = '' is_iterator = False if total is None: try: total = len(sequence) # type: ignore except TypeError: is_iterator = True if total is not None: if miniters is None: if total <= 200: miniters = 1 else: miniters = int(total / 200) else: if miniters is None: miniters = 1 if is_iterator: progress = IntProgress(min=0, max=1, value=1) progress.bar_style = 'info' else: progress = IntProgress(min=0, max=total, value=0) label = HTML() box = VBox(children=[label, progress]) display(box) index = 0 try: for index, record in enumerate(sequence, 1): if index == 1 or index % miniters == 0: if is_iterator: label.value = f'{desc}: {index} / ?' else: progress.value = index label.value = f'{desc}: {index} / {total}' yield record except Exception: progress.bar_style = 'danger' raise else: progress.bar_style = 'success' progress.value = index label.value = '{}: {}'.format(desc, str(index or '?')) try: if get_ipython().__class__.__name__ == 'ZMQInteractiveShell': _log_progress_bar = _log_progress else: raise NameError except NameError: _log_progress_bar = _tqdm
[docs]def progress_bar( sequence: Iterable, desc: str | None = None, total: int | None = None, miniters: int | None = None ): """ Make and display a progress bar. Parameters ---------- sequence : iterable Represents a sequence of elements. desc : str, optional Represents the description of the operation, by default None. total : int, optional Represents the total/number elements in sequence, by default None. miniters : int, optional Represents the steps in which the bar will be updated, by default None. Return ------ >>> from pymove.utils.log import progress_bar >>> for i in progress_bar(range(1,101), desc='Print 1 to 100'): >>> print(i) # A bar that shows the progress of the iterations """ if logger.level > logging.INFO: return sequence return _log_progress_bar(sequence, desc, total, miniters)