def resolve_input_reference(reference, inputs_to_reference):
    """
    Replaces a given input_reference by a string extracted from inputs_to_reference.

    :param reference: The input reference to resolve.
    :param inputs_to_reference: A dictionary containing information about the given inputs.

    :raise InvalidInputReference: If the given input reference could not be resolved.

    :return: A string which is the resolved input reference.
    """
    original_reference = reference

    parts = _build_reference_parts(reference)

    if len(parts) < 2:
        raise InvalidInputReference('InputReference should at least contain "$(inputs.<identifier>)". The following '
                                    'input reference does not comply with it:\n{}'.format(original_reference))
    elif parts[0] != "inputs":
        raise InvalidInputReference('InputReference should begin with "inputs". The following input reference does not '
                                    'comply with it:\n{}'.format(original_reference))

    # remove 'inputs'
    parts = parts[1:]

    parts = _create_array_indices(parts)

    try:
        resolved = _resolve_keys_from_parts(inputs_to_reference, parts)
    except InvalidInputReference as e:
        raise InvalidInputReference('Could not resolve input reference "{}".\n{}'.format(original_reference, str(e)))

    return resolved
Beispiel #2
0
def _build_reference_parts(reference):
    """
    Splits the given reference into parts.
    Example:
    _build_reference_parts('$(inputs.identifier["attribute"])') == ["inputs", "identifier", "attribute"]
    :param reference: The reference to split
    :return: A list of strings
    """
    # remove "$(" and ")"
    reference = reference[2:-1]
    try:
        parts = split_into_parts_with_separators(reference,
                                                 ATTRIBUTE_WRAPPING_SYMBOLS,
                                                 remove_separators=True)
    except ParsingError as e:
        raise InvalidInputReference(
            'Could not resolve input reference $({}). Parsing failed with the following message:\n{}'
            .format(reference, str(e)))

    tmp_parts = []
    for p in parts:
        for split in p.split(ATTRIBUTE_SEPARATOR_SYMBOL):
            if split:
                tmp_parts.append(split)
    parts = tmp_parts
    return parts
def complete_input_references_in_outputs(cli_outputs, inputs_to_reference):
    """
    Takes the cli outputs and inputs to reference and returns the cli outputs, but with resolved input references

    :param cli_outputs: The cli outputs to resolve input references for
    :param inputs_to_reference: The inputs to reference
    """
    resolved_outputs = deepcopy(cli_outputs)

    for output_key, output_value in resolved_outputs.items():
        if output_value['type'] == 'stdout' or output_value['type'] == 'stderr':
            continue
        output_binding = output_value['outputBinding']

        try:
            resolved_glob = resolve_input_references(output_binding['glob'],
                                                     inputs_to_reference)
        except InvalidInputReference as e:
            raise InvalidInputReference(
                'Invalid Input Reference for output key "{}":\n{}'.format(
                    output_key, str(e)))

        output_binding['glob'] = resolved_glob

    return resolved_outputs
def split_input_references(to_split):
    """
    Returns the given string in normal strings and unresolved input references.
    An input reference is identified as something of the following form $(...).

    Example:
    split_input_reference("a$(b)cde()$(fg)") == ["a", "$(b)", "cde()", "$(fg)"]

    :param to_split: The string to split
    :raise InvalidInputReference: If an input reference is not closed and a new reference starts or the string ends.
    :return: A list of normal strings and unresolved input references.
    """
    try:
        result = split_into_parts(to_split, INPUT_REFERENCE_START, INPUT_REFERENCE_END)
    except ParsingError as e:
        raise InvalidInputReference('Could not parse input reference "{}". Failed with the following message:\n{}'
                                    .format(to_split, str(e)))
    return result
Beispiel #5
0
def _create_array_indices(parts):
    """
    Iterates over parts and tries to split array indices.
    :param parts: The parts that whose indices should be split.
    :return: A new list of parts, with extra elements defining the indices.
    """
    new_parts = []
    for part in parts:
        split_part = split_into_parts(part,
                                      *INDEX_SEPARATOR_SYMBOLS,
                                      remove_separators=True)
        if len(split_part) == 1:
            new_parts.append(split_part[0])
        elif len(split_part) > 1:
            new_parts.append(split_part[0])
            new_parts.extend([_try_to_int(p) for p in split_part[1:]])
        else:
            raise InvalidInputReference(
                'Could not create array indices. Part "{}" of {} is invalid.'.
                format(part, parts))

    return new_parts
Beispiel #6
0
def _resolve_keys_from_parts(inputs_to_reference, key_list):
    """
    Uses the keys in list key_list to get recursive values in inputs_to_reference.
    Like return inputs_to_reference[key_list[0]] [key_list[1]] ...

    :rtype: str
    :param inputs_to_reference: A recursive dictionary or list
    :type inputs_to_reference: dict
    :param key_list: A list of keys to insert into the inputs to reference
    :return: The last value of d, after inserting all keys in key_list.
    """
    handled_keys = 'inputs'
    for key in key_list:
        if isinstance(inputs_to_reference, dict):
            if isinstance(key, str):
                last_inputs_to_reference_keys = list(
                    inputs_to_reference.keys())
                inputs_to_reference = inputs_to_reference.get(key)
                if inputs_to_reference is None:
                    raise InvalidInputReference(
                        'Could not resolve key "{}" in "{}".\n"{}" has the following keys: {}'
                        .format(key, handled_keys, handled_keys,
                                last_inputs_to_reference_keys))
            else:
                raise InvalidInputReference(
                    'Could not resolve "{}" in "{}", because "{}" has type "{}". Expected type is "str".'
                    .format(key, handled_keys, key,
                            type(key).__name__))
        elif isinstance(inputs_to_reference, list):
            if isinstance(key, int):
                if key < len(inputs_to_reference):
                    inputs_to_reference = inputs_to_reference[key]
                else:
                    raise InvalidInputReference(
                        'Index {} is out of bounds in "{}", because "{}" has length {}.'
                        .format(key, handled_keys, handled_keys,
                                len(inputs_to_reference)))
            else:
                raise InvalidInputReference(
                    'Could not resolve "{}" in "{}", because "{}" is a list and the index "{}" ({}) is not given as int'
                    .format(key, handled_keys, handled_keys, key,
                            type(key).__name__))
        else:
            raise InvalidInputReference(
                'Could not resolve "{}", because type of "{}" is neither dict nor list'
                .format(key, handled_keys))

        if isinstance(key, int):
            handled_keys = '{}[{}]'.format(handled_keys, key)
        else:
            handled_keys = '{}.{}'.format(handled_keys, key)

    if isinstance(inputs_to_reference, dict):
        raise InvalidInputReference(
            '"{}" could not be resolved completely. It is a dict, with the following keys: {}'
            .format(handled_keys, list(inputs_to_reference.keys())))
    if isinstance(inputs_to_reference, list):
        raise InvalidInputReference(
            '"{}" could not be resolved completely. It is a list, with length {}'
            .format(handled_keys, len(inputs_to_reference)))

    return inputs_to_reference