Source code for chemfit.debug_utils
import inspect
from functools import wraps
from typing import Any, Callable, TypeVar, cast
T = TypeVar("T")
[docs]
def log_invocation(
func: Callable[[Any], T],
log_func: Callable[[str], None],
log_args: bool = True,
log_res: bool = True,
) -> Callable[[Any], T]:
@wraps(func)
def wrapped_with_logging(*args, **kwargs) -> T:
log_func(f"Pre {func.__name__}")
if log_args and len(args) > 0:
log_func(f" {args = }")
if log_args and len(kwargs) > 0:
log_func(f" {kwargs = }")
res = func(*args, **kwargs)
if log_res:
log_func(f" {res = }")
log_func(f"Post {func.__name__}")
return res
return wrapped_with_logging
LoggedObject = TypeVar("LoggedObject", bound=object)
[docs]
def log_all_methods(
obj: LoggedObject, log_func: Callable[[str], None], *args, **kwargs
) -> LoggedObject:
"""Return a proxy object that logs method calls and delegates everything to `obj`."""
class Proxy:
def __init__(self, wrapped: LoggedObject):
super().__setattr__("_wrapped", wrapped)
def __getattribute__(self, name: str) -> Any:
if name == "_wrapped":
return super().__getattribute__(name)
wrapped = super().__getattribute__("_wrapped")
attr = getattr(wrapped, name)
if inspect.ismethod(attr) or inspect.isfunction(attr):
# Use your log_invocation directly
return log_invocation(attr, log_func, *args, **kwargs)
return attr
def __setattr__(self, name: str, value: Any):
wrapped = super().__getattribute__("_wrapped")
setattr(wrapped, name, value)
def __delattr__(self, name: str):
wrapped = super().__getattribute__("_wrapped")
try:
delattr(wrapped, name)
except AttributeError:
super().__delattr__(name)
def __call__(self, *args, **kwargs):
wrapped = super().__getattribute__("_wrapped")
if not callable(wrapped):
msg = "Wrapped object is not callable"
raise Exception(msg)
tmp = log_invocation(wrapped.__call__, log_func, *args, **kwargs)
return tmp(*args, **kwargs)
def __dir__(self):
wrapped = super().__getattribute__("_wrapped")
return sorted(set(dir(type(self)) + dir(wrapped)))
return cast("LoggedObject", Proxy(obj))