utils COM decorators
utils_COM_decorators ¶
Module providing decorators to support Python COM object programming. Decorators provided allow a passing of parameters by name as well as a call logging.
calltypewrapper(COMcall) ¶
decorator to enable a more comfortable call of COM object methods.
The decorator provides two modes:
- convert tuples (param, value) to entry in kwargs dictionary
- convert string parameter param:=value to entry in kwargs dictionary
Source code in src\utils_COMobjects\utils_COM_decorators.py
def calltypewrapper(COMcall):
"""
decorator to enable a more comfortable call of COM object methods.
The decorator provides two modes:
1. convert tuples (param, value) to entry in kwargs dictionary
2. convert string parameter param:=value to entry in kwargs dictionary
"""
@functools.wraps(COMcall)
def wrapper_calltypewrapper(self, *args, **kwargs):
def adddictfull(kwargdict, key: str, value: Any, classname: str, methodname: str, ):
if key in kwargdict:
raise COMException(
description=f"Duplicate parameter '{key}' calling '{methodname}' in '{classname}'.",
scode=winerror.E_FAIL,
source=f"call of '{methodname}' in '{classname}'."
)
else:
kwargdict[key] = value
# set caller information for COM exception for duplicate parameter error
# watch out for issue with keyword arguments as described here:
# https://stackoverflow.com/questions/24755463/functools-partial-wants-to-use-a-positional-argument-as-a-keyword-argument
adddict = functools.partial(adddictfull, classname=self.__class__.__name__, methodname=COMcall.__name__)
# process args
args_new = []
kwargs_new = {}
COMcall_signature = inspect.signature(COMcall)
for arg in args:
if isinstance(arg, str):
argsplit = arg.split(":=")
if len(argsplit) == 2:
keyword = argsplit[0]
value = argsplit[1]
if keyword in COMcall_signature.parameters:
if COMcall_signature.parameters[keyword].annotation != inspect.Parameter.empty:
adddict(kwargs_new, keyword, COMcall_signature.parameters[keyword].annotation(value))
else:
try:
adddict(kwargs_new, keyword, float(value))
except BaseException:
adddict(kwargs_new, keyword, value)
else:
args_new.append(arg)
else:
args_new.append(arg)
elif isinstance(arg, tuple):
if len(arg) == 2 and arg[0] in COMcall_signature.parameters:
adddict(kwargs_new, arg[0], arg[1])
else:
args_new.append(arg)
else:
args_new.append(arg)
return COMcall(self, *args_new, **kwargs_new)
return wrapper_calltypewrapper
logcall(COMcall) ¶
logcall - decorator to activate logging of calls of an COM object method.
Call logging is activated by
- registering COM object in debug mode
- set logcalls attribute in COM class
Source code in src\utils_COMobjects\utils_COM_decorators.py
def logcall(COMcall):
"""
logcall - decorator to activate logging of calls of an COM object method.
Call logging is activated by
- registering COM object in debug mode
- set logcalls attribute in COM class
"""
def calllogger(func, self, *args, **kwargs):
args_repr = [repr(a) for a in args]
kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]
signature = ", ".join(args_repr + kwargs_repr)
print(f"Calling {self.__class__.__name__}.{func.__name__}({signature})")
if self._logger is not None:
self._logger.info(f"Calling {self.__class__.__name__}.{func.__name__}({signature})")
@functools.wraps(COMcall)
def wrapper_logcall(self, *args, **kwargs):
logged = False
if hasattr(self, "_checkDebug"):
if COMcall.__name__ != "_checkDebug": # safeguard against endless recursive calling
if self._checkDebug():
# log because registered in debug mode
calllogger(COMcall, self, *args, **kwargs)
logged = True
if not logged and hasattr(self, "logcalls"):
if getattr(self, "logcalls"):
# log because log flag set
calllogger(COMcall, self, *args, **kwargs)
logged = True
return COMcall(self, *args, **kwargs)
return wrapper_logcall