Created
May 18, 2020 07:03
-
-
Save lukegre/4f02380da80e178c0f4f177f6964747a to your computer and use it in GitHub Desktop.
A few functions to help with functions that have limits for the inputs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def input_limits(return_bool=True, return_info=True, **kwargs): | |
""" | |
This is a function wrapper for functions that have defined input limits. | |
The user can define the valid limits of any of the inputs. | |
Parameters | |
---------- | |
return_bool: array-bool | |
returns a boolean array of the original function where valid or not | |
return_info: array-str | |
returns the reason output is questionable, with the function name | |
and the input argument name that are not in the valid range. | |
**kwargs: key-value pair | |
the key should be the name of one of the input arguments and the | |
value should ne a list or tuple of the upper and lower limit | |
where the limits are exclusive (>/< not >=/<=) | |
Returns | |
------- | |
dict: | |
key['output'] = the original data | |
key['bool'] = inputs are not within the range | |
key['info'] = reason that output is flagged (which variable) | |
Example | |
------- | |
>>> @input_limits(S=[5, 50]) | |
def mult(T, S): | |
return T * S | |
>>> T = np.array([4, 2, 25, 13]) | |
>>> S = np.array([5, 31, 34, 28]) | |
>>> mult(T, S) | |
{'output': array([ 20, 62, 850, 364]), | |
'bool': array([False, True, True, True]), | |
'info': array(["'S' outside limits (5, 50) for mult; ", '', '', ''], dtype='<U38')} | |
""" | |
def wrap(f): | |
def f_foo(*args, **kw): | |
argnames = f.__code__.co_varnames | |
funcname = f.__name__ | |
args_as_dict = {k:v for k, v in zip(argnames, args)} | |
inside = [] | |
info = np.array([""] * args[0].size) | |
for key in kwargs: | |
# make sure wrapper keys are in the function | |
assert key in argnames, ( | |
f"'{key}' given to 'input_limits' wrapper is not an " | |
f"argument for {funcname}. Must be one of the " | |
f"following: {argnames}" | |
) | |
# must be a list or tuple | |
assert isinstance(kwargs[key], (list, tuple)), ( | |
f"limits for '{key}' must be a list or " | |
f"tuple of lower and upper limits" | |
) | |
# must have upper and lower limit | |
assert len(kwargs[key]) == 2, ( | |
f"limits for '{key}' must be a list or " | |
f"tuple of lower and upper limits" | |
) | |
# separate lower and upper limits | |
lim0, lim1 = kwargs[key] | |
# create a dictionary from input arguments for ease of calling | |
arr = args_as_dict[key] | |
# check that the input is within the limits | |
arr_inside = np.logical_and(arr > lim0, arr < lim1) | |
# set an array with default arguments | |
msg = np.array( | |
[f"'{key}' outside limits {lim0, lim1} for {funcname}; "] * arr.size | |
) | |
# set valid inputs to no string input | |
msg[arr_inside] = "" | |
# add to previous string array | |
info = np.char.add(info, msg) | |
# append the bool string | |
inside += arr_inside, | |
inside = np.array(inside).all(0) | |
out = {'output': f(*args, **kw),} | |
if return_bool: | |
out['bool'] = inside | |
if return_info: | |
out['info'] = info | |
return out | |
return f_foo | |
return wrap |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment