Source code for skactiveml.utils._functions
import inspect
from types import MethodType
from makefun import with_signature
[docs]def call_func(
f_callable, only_mandatory=False, ignore_var_keyword=False, **kwargs
):
"""Calls a function with the given parameters given in kwargs if they
exist as parameters in f_callable.
Parameters
----------
f_callable : callable
The function or object that is to be called
only_mandatory : boolean
If True only mandatory parameters are set.
ignore_var_keyword : boolean
If False all kwargs are passed when f_callable uses a parameter that is
of kind Parameter.VAR_KEYWORD, i.e., **kwargs. For further reference
see inspect package.
kwargs : kwargs
All parameters that could be used for calling f_callable.
Returns
-------
called object
"""
params = inspect.signature(f_callable).parameters
param_keys = params.keys()
if only_mandatory:
param_keys = list(
filter(lambda k: params[k].default == params[k].empty, param_keys)
)
has_var_keyword = any(
filter(lambda p: p.kind == p.VAR_KEYWORD, params.values())
)
if has_var_keyword and not ignore_var_keyword and not only_mandatory:
vars = kwargs
else:
vars = dict(filter(lambda e: e[0] in param_keys, kwargs.items()))
return f_callable(**vars)
[docs]def match_signature(wrapped_obj_name, func_name):
"""A decorator that matches the signature to a given method from a
reference and hides it when the reference object does not have the wrapped
function. This is especially helpful for wrapper classes whose functions
should appear. This decorator is heavily inspired by the `available_if`
decorator from `sklearn.utils.metaestimators`.
Parameters
----------
wrapped_obj_name : str
The name of the object that will be wrapped.
func_name : str
The name of the function that will be wrapped.
Returns
-------
Wrapped function
"""
class _MatchSignatureDescriptor:
"""_MatchSignatureDescriptor
A descriptor that allows a wrapper to clone the signature of a
method `func_name` from the wrapped object `wrapped_obj_name`.
Furthermore, this extends upon the conditional property as implemented
in `available_if` from from `sklearn.utils.metaestimators`.
Parameters
----------
fn: MethodType
The method that should be wrapped.
wrapped_obj_name: str
The name of the wrapped object within the wrapper class.
func_name : str
The method name of the function that should be wrapped.
"""
def __init__(self, fn, wrapped_obj_name, func_name):
self.fn = fn
self.wrapped_obj_name = wrapped_obj_name
self.func_name = func_name
self.__name__ = func_name
def __get__(self, obj, owner=None):
"""Wrap the method specified in `self.func_name` from the wrapped
object `self.wrapped_obj_name` such that the signature will be the
same.
Parameters
----------
obj: object
The wrapper object. This parameter will be None, if the method
is accessed via the class and not an instantiated object.
owner: class, default=None
The wrapper class.
Returns
-------
The wrapped method.
"""
if obj is not None:
reference_object = getattr(obj, self.wrapped_obj_name)
if not hasattr(reference_object, self.func_name):
raise AttributeError(
f"This {reference_object} has"
f" no method {self.func_name}."
)
reference_function = getattr(reference_object, self.func_name)
reference_signature = inspect.signature(reference_function)
new_fn_name = self.fn.__name__
sig_str = (
f"{new_fn_name}(self, {str(reference_signature)[1:-1]})"
)
fn = with_signature(sig_str)(self.fn)
out = MethodType(fn, obj)
else:
out = self.fn
return out
return lambda fn: _MatchSignatureDescriptor(
fn, wrapped_obj_name, func_name=func_name
)