Module openpack_toolkit.utils.notebook

Reference

Expand source code
"""
Reference:
    * https://github.com/K-PTL/noglobal-python
"""

import inspect
import logging
from functools import partial
from types import FunctionType
from typing import Any, Callable, Dict, List, Optional


def setup_root_logger(log_level=logging.INFO):
    log_format = "%(asctime)s | %(levelname)s | %(name)s | %(message)s"
    logger = logging.getLogger()

    # add the handlers to the logger
    sh = logging.StreamHandler()
    sh.setLevel(log_level)
    sh_formatter = logging.Formatter(log_format, "%Y-%m-%d %H:%M:%S")
    sh.setFormatter(sh_formatter)
    logger.addHandler(sh)

    logger.setLevel(log_level)
    return logger


# -----------------------------------------------------------------------------
# Function prototype
# this is not necessary, just my pray for.
global noglobal


# https://gist.github.com/momijiame/bebf8d4c16fc0916fd80530ebe961525
def _globals_with_module_and_callable(
    globals_: Optional[Dict[str, Any]] = None, excepts: Optional[List[str]] = None
) -> Dict[str, Any]:
    """
    Args:
        globals_ (Optional[Dict[str, Any]]): base global symbol table
        excepts (Optional[List[str]]): involve the names of variables which is expected to be
            included into global symbol table

    Returns:
        Dict[str, Any]: global symbol table
    """

    def need(name, attr) -> bool:
        """if attr is need or name is in excepts, then return True, otherwise return False."""
        if name in excepts:
            return True
        if inspect.ismodule(attr):
            return True
        if callable(attr):
            return True
        return False

    if globals_ is None:
        globals_ = globals()
    if excepts is None:
        excepts = []

    filtered_globals = {name: attr for name, attr in globals_.items() if need(name, attr)}

    # If __name__ == "__main__", then we do not have to consider the dealing of builtins
    # (globals()["__builtins__"] is <module 'builtins' (built-in)>).
    # However, if __name__ != "__main__", then globals()["__builtins__"] has
    # the builtins in similar with global variables (not module).
    if not inspect.ismodule(globals_["__builtins__"]):
        for name, attr in globals_["__builtins__"].items():
            if need(name, attr):
                filtered_globals[name] = attr

    return filtered_globals


def _bind_globals(globals_: Dict[str, Any]) -> Callable:
    """decorator returning functional object for wrapping, which run the callable object on the
    specified global symbol table.

    Args:
        globals_ (Dict[str, Any]): global symbol table

    Returns:
        functional object for wrapping
    """

    def _bind_globals_func(func: FunctionType) -> FunctionType:
        bound_func = FunctionType(
            code=func.__code__,
            globals=globals_,
            name=func.__name__,
            argdefs=func.__defaults__,
            closure=func.__closure__,
        )
        return bound_func

    return _bind_globals_func


def _no_global_variable_decorator(globals_: Optional[Dict[str, Any]] = None):
    """Providing the decorator of inhibiting the use of global variables"""
    partialled = partial(_globals_with_module_and_callable, globals_=globals_)

    def _no_global_variable(excepts: Optional[List[str]] = None):
        partialled_globals_ = partialled(excepts=excepts)
        bound_func = _bind_globals(globals_=partialled_globals_)
        return bound_func

    return _no_global_variable


# substance of noglobal function
class noglobal:
    def __init__(self, excepts=None):
        self.excepts = excepts

    def __call__(self, _func):
        return _no_global_variable_decorator(globals_=_func.__globals__)(
            excepts=self.excepts  # arg of _no_global_variable
        )(
            func=_func
        )  # arg of _bind_globals

Functions

def setup_root_logger(log_level=20)
Expand source code
def setup_root_logger(log_level=logging.INFO):
    log_format = "%(asctime)s | %(levelname)s | %(name)s | %(message)s"
    logger = logging.getLogger()

    # add the handlers to the logger
    sh = logging.StreamHandler()
    sh.setLevel(log_level)
    sh_formatter = logging.Formatter(log_format, "%Y-%m-%d %H:%M:%S")
    sh.setFormatter(sh_formatter)
    logger.addHandler(sh)

    logger.setLevel(log_level)
    return logger

Classes

class noglobal (excepts=None)
Expand source code
class noglobal:
    def __init__(self, excepts=None):
        self.excepts = excepts

    def __call__(self, _func):
        return _no_global_variable_decorator(globals_=_func.__globals__)(
            excepts=self.excepts  # arg of _no_global_variable
        )(
            func=_func
        )  # arg of _bind_globals