Source code for core.log

"""
    Module Shadowed by API function of same name log
    
    usage:
    
    from core import log
    
"""
# standard library imports
from datetime import datetime
from enum import Enum
from typing import Literal
from tqdm import tqdm
import inspect
import warnings

# third party imports
import sys
if 'ipykernel' in sys.modules: from tqdm.notebook import tqdm
else: from tqdm import tqdm
        
# sub package imports
from core import env
from string import Template
import os


[docs] class config: show_color = True
class _color: default = '\033[0m' silenced = False def __init__(self, value): self.string = value def __str__(self): return self.string if config.show_color else "" def __call__(self, string): """ boxes the provided string with its color, and reset to default afterward """ return self.string + str(string) + _color.default
[docs] class rgb: purple = _color('\033[95m') blue = _color('\033[94m') cyan = _color('\033[96m') green = _color('\033[92m') orange = _color('\033[93m') red = _color('\033[91m') bold = _color('\033[1m') underline = _color('\033[4m') default = _color(_color.default) gray = _color('\033[90m')
# set levels enums
[docs] class lvl(Enum): DEBUG = 1 INFO = 2 WARNING = 3 ERROR = 4 PROMPT = 5
# set levels colors lvl.DEBUG.color = rgb.purple lvl.INFO.color = rgb.blue lvl.WARNING.color = rgb.orange lvl.ERROR.color = rgb.red lvl.PROMPT.color = rgb.cyan lvl.DEBUG.icon = "(d)" lvl.INFO.icon = "(i)" lvl.WARNING.icon = "/!\\" lvl.ERROR.icon = "/x\\" lvl.PROMPT.icon = "(?)" # "/!\\" # "/!\\" class _internal: min_global_level = lvl.DEBUG blacklist = {} prefix = env.getvar("HYGEOS_LOG_PREFIX", default="%level %time") def format_msg(level: lvl, msg: str, mod): prefix = _internal.prefix kwargs = {} if "%level" in prefix: # status, level kwargs["level"] = f"{level.color}" + f"[{level.name.lower()}]".ljust(8+2) if "%namespace" in prefix: # namespace mod_name = "main" if not hasattr(mod, "__name__") else mod.__name__ # because if calling from main mod is None kwargs["namespace"] = f"{rgb.orange}" + f"{mod_name}" if "%icon" in prefix: # icon kwargs["icon"] = f"{level.color}" + f"{level.icon}" if "%time" in prefix: # time kwargs["time"] = f"{rgb.green}" +f"{datetime.now().strftime('%H:%M:%S')}" if "%pid" in prefix: kwargs["pid"] = f"{rgb.orange}" + f"{os.getpid()}" prefix = prefix.format(**kwargs) # add sapce if no whitespace at right hand if len(prefix) > 0 and not prefix[-1].isspace(): prefix += " " class t(Template): delimiter = "%" prefix = t(prefix).substitute(**kwargs) string = f"{prefix}{rgb.default}{msg}" return string # proxy def log(lvl: lvl, *args, **kwargs): """ log with selected lvl """ # get calling module full name frame = inspect.currentframe().f_back.f_back mod = inspect.getmodule(frame) msg = _internal.concat_mess(*args) if lvl.value < _internal.min_global_level.value: # and section not in LOG.filters: return for blmod in _internal.blacklist: # blacklisted module blname = blmod.__name__ if blname in mod.__name__ and lvl.value <= _internal.blacklist[blmod].value: return print(_internal.format_msg(lvl, msg, mod), file=sys.stderr, **kwargs) def _loading_bar(**kwargs): frame = inspect.currentframe().f_back.f_back mod = inspect.getmodule(frame) lvl = kwargs.pop('lvl') prefix = _internal.format_msg(lvl, '', mod) # kwargs['bar_format'] = prefix+'{l_bar}{bar}{r_bar}' kwargs['bar_format'] = '{l_bar}{bar}{r_bar}' kwargs.pop('kwargs') return tqdm(**kwargs) def concat_mess(*args): message = "" for arg in args: message += str(arg) return message + str(rgb.default)
[docs] def stderr(*args): msg = _internal.concat_mess(*args) print(msg, file=sys.stderr)
# filters = ...
[docs] def set_lvl(lvl: lvl): _internal.min_global_level = lvl
#interface tqdm please go to https://tqdm.github.io/docs/tqdm/ for documentation
[docs] def pbar(lvl: lvl = lvl.INFO, iterable=None, desc=None, total=None, leave=True, ncols=None, mininterval=0.1, maxinterval=10.0, miniters=None, ascii=None, disable=False, unit='it', unit_scale=False, dynamic_ncols=False, smoothing=0.3, initial=0, file=None, position=None, postfix=None, unit_divisor=1000, write_bytes=False, lock_args=None, nrows=None, colour=None, delay=0, gui=False, **kwargs): """ log a progress bar such as tqdm Args: All arguments are those from tqdm (cf. https://tqdm.github.io/docs/tqdm/) """ return _internal._loading_bar(**locals())
[docs] def silence(module, lvl_and_below : lvl = lvl.ERROR): # blacklist only below certain level ? e.g Log.silence("core.filegen", bellow_level=lvl.ERROR) if lvl_and_below == lvl.PROMPT: error("Cannot silence prompts, max level authorized: lvl.ERROR", e=ValueError) _internal.blacklist[module] = lvl_and_below
[docs] def disp(*args, **kwargs): msg = _internal.concat_mess(*args) print(msg, file=sys.stderr, **kwargs)
[docs] def log(lvl: lvl, *args, **kwargs): """ log with specified level """ _internal.log(lvl, *args, **kwargs)
[docs] def error(*args, e: Exception=RuntimeError, **kwargs): """ log with defaul level ERROR will raise e if passed """ _internal.log(lvl.ERROR, rgb.red, *args, **kwargs) if e is not None: if not issubclass(e, Exception): raise RuntimeError(f"log.error Invalid Exception type: {str(e)}, should be a subclass of {str(Exception)}") raise e(*args)
[docs] def warning(*args, w: Warning=None, **kwargs): """ log with defaul level WARNING """ _internal.log(lvl.WARNING, rgb.orange, *args, **kwargs) if w is not None: if not issubclass(w, Warning): raise RuntimeError(f"log.error Invalid Warning type: {str(e)}, should be a subclass of {str(Warning)}") msg = _internal.concat_mess(*args) warnings.warn(msg, category=w)
[docs] def info(*args, **kwargs): """ log with default level INFO """ _internal.log(lvl.INFO, *args, **kwargs)
[docs] def check(condition, *args, e: Exception=AssertionError): """ log assertion with level ERROR """ if not condition: error(*args, e=e)
[docs] def debug(*args, **kwargs): """ log with defaul level DEBUG """ _internal.log(lvl.DEBUG, *args, **kwargs)
[docs] def prompt(*args, **kwargs): """ prompt user with log format """ _internal.log(lvl.PROMPT, *args, **kwargs) return input()
[docs] def set_format(fmt: Literal["%level", "%icon", "%time", "%namespace", "%pid"]): """ valid keys: """ _internal.prefix = fmt