import inspect
from immuneML.dsl.DefaultParamsLoader import DefaultParamsLoader
from immuneML.util.ParameterValidator import ParameterValidator
from immuneML.util.ReflectionHandler import ReflectionHandler
[docs]
class ObjectParser:
[docs]
@staticmethod
def get_class_name(specs, valid_class_names, class_name_ending, location, key):
if isinstance(specs, str):
class_name = specs
elif isinstance(specs, dict):
assert len(specs) == 1, \
f"{location}: More than one parameter passed to {class_name_ending.lower()} under key {key}. " \
f"Only one value can be specified here. Valid options are: {str(valid_class_names)[1:-1]}"
class_name = list(specs.keys())[0]
else:
raise AssertionError(f"{location}: Incorrect specification under key {key}.\n"
f"Please choose one of the following:\n"
f"(1) To specify an analysis component without parameters, simply specify the component as a single value, e.g;\n"
f"my_component: ComponentName\n"
f"\n"
f"(2) To specify an analysis component with parameter values, specify it as a key containing "
f"key-value pairs, e.g;\n"
f"my_component: ComponentName\n"
f" parameter: value\n"
f"\nMake sure the indentation is correct. Valid options are: {str(valid_class_names)[1:-1]}. \n"
f"For more information and details on how to specify parameters, please refer to the documentation.")
return class_name
[docs]
@staticmethod
def get_params(specs, class_name):
params = {}
if isinstance(specs, dict):
params = specs[class_name]
return params
[docs]
@staticmethod
def get_class(specs, valid_class_names, class_name_ending, class_path, location, key):
class_name = ObjectParser.get_class_name(specs, valid_class_names, class_name_ending, location, key)
cls = ReflectionHandler.get_class_by_name(f"{class_name}{class_name_ending}", class_path)
return cls
[docs]
@staticmethod
def get_all_params(specs, class_path, short_class_name, key: str = None):
default_params = DefaultParamsLoader.load(class_path, short_class_name)
specified_params = ObjectParser.get_params(specs, short_class_name)
params = {**default_params, **specified_params, "name": key}
return params
[docs]
@staticmethod
def parse_object(specs, valid_class_names: list, class_name_ending: str, class_path: str, location: str, key: str,
builder: bool = False, return_params_dict: bool = False):
class_name = ObjectParser.get_class_name(specs, valid_class_names, class_name_ending, location, key)
ParameterValidator.assert_in_valid_list(class_name, valid_class_names, location, key)
cls = ReflectionHandler.get_class_by_name(f"{class_name}{class_name_ending}", class_path)
params = ObjectParser.get_all_params(specs, class_path, class_name, key)
try:
if "name" not in inspect.signature(cls.__init__).parameters.keys():
del params["name"]
obj = cls.build_object(**params) if builder and hasattr(cls, "build_object") else cls(**params)
except TypeError as err:
raise AssertionError(f"{location}: invalid parameter {err.args[0]} when specifying parameters in {specs} "
f"under key {key}. Valid parameter names are: "
f"{[name for name in inspect.signature(cls.__init__).parameters.keys()]}").with_traceback(err.__traceback__)
return (obj, {class_name: params}) if return_params_dict else obj