Source code for tsfel.utils.add_personal_features

import importlib
import inspect
import json
import os
import sys
import warnings
from inspect import getmembers, isfunction

from tsfel.feature_extraction.features_settings import load_json
from tsfel.utils.calculate_complexity import compute_complexity


[docs] def add_feature_json(features_path, json_path): """Adds new feature to features.json. Parameters ---------- features_path: string Personal Python module directory containing new features implementation. json_path: string Personal .json file directory containing existing features from TSFEL. New customised features will be added to file in this directory. """ sys.path.append(features_path[: -len(features_path.split(os.sep)[-1]) - 1]) exec("import " + features_path.split(os.sep)[-1][:-3]) # Reload module containing the new features importlib.reload(sys.modules[features_path.split(os.sep)[-1][:-3]]) exec("import " + features_path.split(os.sep)[-1][:-3] + " as pymodule") # Functions from module containing the new features functions_list = [o for o in getmembers(locals()["pymodule"]) if isfunction(o[1])] function_names = [fname[0] for fname in functions_list] # Check if @set_domain was declared on features module vset_domain = False for fname, f in list(locals()["pymodule"].__dict__.items()): if getattr(f, "domain", None) is not None: vset_domain = True # Access to personal features.json feat_json = load_json(json_path) # Assign domain and tag domain = getattr(f, "domain", None) tag = getattr(f, "tag", None) # Feature specifications # Description if f.__doc__ is not None: descrip = f.__doc__.split("\n")[0] else: descrip = "" # Feature usage use = "yes" # Feature function arguments args_name = inspect.getfullargspec(f)[0] # Access feature parameters if args_name != "": # Retrieve default values of arguments spec = inspect.getfullargspec(f) defaults = dict(zip(spec.args[::-1], (spec.defaults or ())[::-1])) defaults.update(spec.kwonlydefaults or {}) for p in args_name[1:]: if p not in list(defaults.keys()): if p == "fs": # Assigning a default value for fs if not given defaults[p] = 100 else: defaults[p] = None if len(defaults) == 0: defaults = "" else: defaults = "" # Settings of new feature new_feature = { "description": descrip, "parameters": defaults, "function": fname, "use": use, } # Check if domain exists try: feat_json[domain][fname] = new_feature except KeyError: feat_json[domain] = {fname: new_feature} # Insert tag if it is declared if tag is not None: feat_json[domain][fname]["tag"] = tag # Write new feature on json file with open(json_path, "w") as fout: json.dump(feat_json, fout, indent=" ") # Calculate feature complexity compute_complexity(fname, domain, json_path, features_path=features_path) print("Feature " + str(fname) + " was added.") if vset_domain is False: warnings.warn( "No features were added. Please declare @set_domain.", stacklevel=2, )