"""
Decorator utilities
===================
This module contains a series of decorators in order to add logging functionalities to some of the class methods. The decorators are regularly purposed for logging, printing, neutering funcitons. etc.
"""
# ============================================================================
# STANDARD IMPORTS
# ============================================================================
from functools import wraps
from typing import Callable
# ============================================================================
# INTERNAL IMPORTS
# ============================================================================
from ensemble.tools.screen import log_in_terminal, log_success
# ============================================================================
# CLASS AND DEFINITIONS
# ============================================================================
[docs]def logger_func(orig_func: Callable):
"""Logs execution of a function/method and arguments into a file called with the function name
Args:
orig_func (Callable): A function/method to be logged
Returns:
(Callable): Wrapped method after log
"""
import logging
logging.basicConfig(
filename="{}.log".format(orig_func.__name__), level=logging.INFO
)
@wraps(orig_func)
def wrapper(*args, **kwargs):
logging.info("Ran with args: {}, and kwargs: {}".format(args, kwargs))
return orig_func(*args, **kwargs)
return wrapper
[docs]def timer_func(orig_func: Callable) -> Callable:
"""Prints in terminal the execution time of a code
Args:
orig_func (Callable): A function/method to be temporized
Returns:
Callable: Wrapped method after timming execution time
"""
import time
@wraps(orig_func)
def wrapper(*args, **kwargs):
t1 = time.time()
result = orig_func(*args, **kwargs)
t2 = time.time() - t1
log_success("{} ran in: {} sec".format(orig_func.__name__, t2))
return result
return wrapper
[docs]def printer_time(orig_func: Callable) -> Callable:
"""Prints in terminal the current time step of a simulation.
Args:
orig_func (Callable): Connector class containing the `simulationstep` status via an attribute. Decorated method is `run_step`
Returns:
Callable: Wrapped step execution
"""
# This is useful in the case of chaining decorators.
# See: https://youtu.be/FsAPt_9Bf3U?t=1343
# @wraps(orig_func)
def wrapper(*args, **kwargs):
log_in_terminal(f"Step: {args[0].simulationstep}")
return orig_func(*args, **kwargs)
return wrapper
[docs]def conditional(cond: bool, warning: str = "") -> Callable:
"""Disables the execution of the decorated method/function
Args:
cond (bool): Flag to execute
warning (str, optional): Warning to login. Defaults to "".
Returns:
Callable: Wrapped method
"""
# Top decorator for disabling a function execution:
# See: https://stackoverflow.com/questions/17946024/deactivate-function-with-decorator
def noop_decorator(func):
return func # pass through
def neutered_function(func):
def neutered(*args, **kw):
if warning != "":
log.warn(warning)
return
return neutered
return noop_decorator if cond else neutered_function