-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds on-the-fly enabling of function argument casting
- Loading branch information
1 parent
c2bd15e
commit 5cb2065
Showing
7 changed files
with
254 additions
and
245 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,107 @@ | ||
import functools | ||
import inspect | ||
import sys | ||
import types | ||
|
||
import numpy as np | ||
import pandas as pd | ||
import logging | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
CAST_TYPES = [list, pd.Series] | ||
|
||
|
||
def cast_array_to_original_type(arg, arg_type): | ||
"""Cast array to another array-like type | ||
def type_casting(func): | ||
"""Type casting | ||
This decorator casts input arguments of types [list, pandas.Series] to numpy.ndarray | ||
so the algorithms accept these input arguments. | ||
As a bonus, the decorator casts the return value of the algorithm to the type of the first | ||
array-like input argument. | ||
Parameters | ||
---------- | ||
arg: array-like {list, ndarray, pd.Series} | ||
arg_type: type | ||
module_or_func : [types.ModuleType, types.FunctionType] | ||
Module or function that has to be type casted. Can be None. | ||
Returns | ||
------- | ||
casted : arg_type array-like | ||
function | ||
Decorated function. | ||
""" | ||
@functools.wraps(func) | ||
def func_wrapper(*args, **kwargs): | ||
output_type = None | ||
new_args = [] | ||
|
||
for arg in args: | ||
input_type = type(arg) | ||
|
||
if input_type in CAST_TYPES: | ||
new_args.append(np.asarray(arg)) | ||
|
||
if output_type is None: | ||
# Type of first array-like argument is used for output casting | ||
output_type = input_type | ||
else: | ||
new_args.append(arg) | ||
|
||
# There is no use-case for type casting kwargs now. | ||
# If there is, this can be uncommented and tests can be added. | ||
# new_kwargs = dict() | ||
# for key, value in kwargs.items(): | ||
# input_type = type(value) | ||
|
||
# if input_type in CAST_TYPES: | ||
# new_kwargs[key] = np.asarray(value) | ||
|
||
# if output_type is None: | ||
# # Type of first array-like argument is used for output casting | ||
# output_type = input_type | ||
# else: | ||
# new_kwargs[key] = value | ||
# | ||
# output = func(*new_args, **new_kwargs) | ||
|
||
output = func(*new_args) | ||
if output_type is not None and isinstance(output, np.ndarray): | ||
return output_type(output) | ||
else: | ||
return output | ||
|
||
if arg_type == list: | ||
return list(arg) | ||
return func_wrapper | ||
|
||
|
||
def enable_type_casting(module_or_func=None): | ||
"""Enable type casting | ||
This method enables casting of input arguments to numpy.ndarray so the algorithms accept | ||
array-like input arguments of types list and pandas.Series. | ||
As a bonus, the return value of the algorithm is casted to the type of the first array-like input argument. | ||
Parameters | ||
---------- | ||
module_or_func : [types.ModuleType, types.FunctionType] | ||
Module or function that has to be type casted. Can be None. | ||
Returns | ||
------- | ||
function | ||
Decorated function. | ||
""" | ||
if module_or_func is None: | ||
# Because sys.modules changes during this operation we cannot loop over sys.modules directly | ||
key_values = [(key, value) for key, value in sys.modules.items()] | ||
for key, value in key_values: | ||
# @TODO this if statement might not cover all cases (or too much cases) | ||
if key.startswith('sweat.hrm') or key.startswith('sweat.pdm') or key.startswith('sweat.metrics'): | ||
enable_type_casting(module_or_func=value) | ||
|
||
elif arg_type == np.ndarray: | ||
return np.array(arg) | ||
elif isinstance(module_or_func, types.ModuleType): | ||
for name, obj in [(name, obj) for name, obj in inspect.getmembers(module_or_func)]: | ||
if inspect.isfunction(obj) and inspect.getmodule(obj).__package__ == module_or_func.__package__: | ||
func = getattr(module_or_func, name) | ||
setattr(module_or_func, name, type_casting(func)) | ||
|
||
elif arg_type == pd.Series: | ||
return pd.Series(arg) | ||
elif isinstance(module_or_func, types.FunctionType): | ||
return type_casting(module_or_func) | ||
|
||
else: | ||
raise ValueError("arg_type must be list, ndarray or pd.Series") | ||
raise ValueError('enable_type_casting takes arguments of types [ModuleType, FunctionType]') |
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
Oops, something went wrong.