Source code for immuneML.dsl.definition_parsers.SignalParser

import importlib
import sys
from inspect import getmembers, isfunction
from pathlib import Path

from immuneML.dsl.symbol_table.SymbolTable import SymbolTable
from immuneML.dsl.symbol_table.SymbolType import SymbolType
from immuneML.simulation.implants.Signal import Signal
from immuneML.util.Logger import log
from immuneML.util.ParameterValidator import ParameterValidator


[docs] class SignalParser: keyword = "signals" custom_func_keys = ['source_file', 'is_present_func'] @staticmethod @log def parse(signals: dict, symbol_table: SymbolTable): for key, signal_spec in signals.items(): assert "__" not in key, f"{SignalParser.__name__}: '__' is not valid part of signal names, please rename the signal." if "motifs" in signal_spec: signal = _parse_signal_with_motifs(key, signal_spec, symbol_table) else: signal = _parse_custom_func_signal(key, signal_spec) symbol_table.add(key, SymbolType.SIGNAL, signal) return symbol_table, signals
def _parse_custom_func_signal(key: str, signal_spec: dict) -> Signal: assert all(k in signal_spec for k in SignalParser.custom_func_keys), \ f"Signal {key}: for signals with custom functions the following keys need to be defined: " \ f"{SignalParser.custom_func_keys}, got: {list(signal_spec.keys())}" assert signal_spec['source_file'].endswith(".py") and Path(signal_spec['source_file']).is_file(), \ f"Signal {key}: no file {signal_spec['source_file']}" sys.path.insert(0, str(Path(signal_spec['source_file']).parent)) source_file = importlib.import_module(Path(signal_spec['source_file']).name[:-3]) functions = getmembers(source_file, isfunction) is_present_func = [func for func in functions if signal_spec['is_present_func'] == func[0]] assert len(is_present_func) == 1, \ f"Signal {key}: no function named {signal_spec['is_present_func']}." return Signal(id=key, is_present_custom_func=is_present_func[0][1]) def _parse_signal_with_motifs(key: str, signal_spec: dict, symbol_table: SymbolTable) -> Signal: assert all(k not in signal_spec for k in SignalParser.custom_func_keys) or \ all(signal_spec[k] is None for k in SignalParser.custom_func_keys), \ f"Signal {key}: define either motifs or the custom function." valid_motif_keys = symbol_table.get_keys_by_type(SymbolType.MOTIF) signal_motifs = [] for motif_group in signal_spec['motifs']: if isinstance(motif_group, str): ParameterValidator.assert_in_valid_list(motif_group, valid_motif_keys, SignalParser.__name__, f'{key}:motifs') signal_motifs.append(symbol_table.get(motif_group)) elif isinstance(motif_group, list): assert len( motif_group) == 2, f"{SignalParser.__name__}: {len(motif_group)} motifs specified for signal {key}, but only 2 allowed." for motif in motif_group: ParameterValidator.assert_in_valid_list(motif, valid_motif_keys, SignalParser.__name__, f'{key}:motifs') signal_motifs.append([symbol_table.get(motif_id) for motif_id in motif_group]) check_clonal_frequency(signal_spec) signal = Signal(key, signal_motifs, v_call=signal_spec.get('v_call'), j_call=signal_spec.get('j_call'), clonal_frequency=signal_spec.get('clonal_frequency', None), sequence_position_weights=signal_spec.get('sequence_position_weights', {})) return signal
[docs] def check_clonal_frequency(spec: dict, name: str = 'clonal_frequency', location: str = SignalParser.__name__): if name in spec and spec[name] is not None: ParameterValidator.assert_type_and_value(spec[name], dict, location, name) ParameterValidator.assert_all_in_valid_list(spec[name].keys(), ['a', 'loc'], location, name)