Source code for energia.utils.decorators
"""Decorators for functions"""
import logging
import time
from functools import wraps
[docs]
def once(func):
"""Ensures the function is executed only once"""
def wrapper(*args, **kwargs):
if not hasattr(wrapper, "has_run"):
wrapper.has_run = True
return func(*args, **kwargs)
return wrapper
[docs]
def timer(
logger: logging.Logger,
kind=None,
level=logging.INFO,
):
"""
Logs execution time and optionally shows a full computation using function arguments and result.
"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
# returns the result if successful, else False
result = func(*args, **kwargs)
elapsed = time.time() - start
if result is not False:
if kind == 'balance-update':
msg = f"⚖ Updated {result[0].commodity} balance with {result[1]}{result[0]}"
elif kind == 'balance-init':
msg = f"⚖ Initiated {result.commodity} balance in ({result.space}, {result.time})"
elif kind == 'map':
msg = f"🧭 Mapped {(result[1] - result[2])[0]} for {result[0]} {result[1]} ⟺ {result[2]}"
elif kind == 'bind':
sample = result[0]
aspect = sample.aspect
domain = sample.domain
rel = result[1]
if rel == "ub":
rel = "≤"
elif rel == "lb":
rel = "≥"
else:
rel = "="
msg = f"🔗 Bound [{rel}] {domain.primary} {aspect} in ({domain.space}, {domain.time})"
elif kind == 'assume-capacity':
msg = f"💡 Assumed {result[0]} capacity unbounded in ({result[1]}, {result[2]})"
elif kind == 'assume-operate':
msg = f"💡 Assumed {result[0]} operate bounded by capacity in ({result[1]}, {result[2]})"
elif kind == 'assume-inventory':
msg = f"💡 Assumed {result[0]} inventory bounded by capacity in ({result[1]}, {result[2]})"
elif kind == 'locate':
msg = f"🌍 Located {result[0]} in {', '.join([str(s) for s in result[1]])}"
elif kind == 'production':
msg = f"🏭 Operating streams introduced for {result[0]} in {', '.join([str(s) for s in result[1]])}"
elif kind == 'construction':
msg = f"🏗 Construction streams introduced for {result[0]} in {', '.join([str(s) for s in result[1]])}"
else:
msg = f" Executed {func.__name__}"
logger.log(
level,
f"{msg:<75} ⏱ {elapsed:.4f} s",
)
return wrapper
return decorator