def cascade_batchrun_inputs(workflow: Tool, inputs: List[Dict],
                            options: BatchRunRequirements):
    fields_to_group = set(options.fields)
    fields_to_group.add(options.groupby)

    wfins = workflow.inputs_map()

    required_ar_depth_of_groupby_fields = {
        f: 1 + count_janisarray_depth(wfins[f].intype)
        for f in fields_to_group
    }

    ins = {}

    for inp in inputs:
        for k, v in inp.items():
            if k in fields_to_group:
                if k not in ins:
                    ins[k] = []

                # We'll look at the shape of the data, and decide whether
                # we can just use the value, or we need to wrap it in another array
                if count_array_depth(
                        v) < required_ar_depth_of_groupby_fields[k]:
                    v = [v]
                ins[k].extend(v)
            else:
                # overwrite the previous value
                ins[k] = v

    # If inputs
    return ins
    def inputs_modifier(self, tool: Tool, inputs: Dict,
                        hints: Dict[str, str]) -> Dict:
        new_inputs = {}
        for inp in tool.inputs_map().values():
            if inp.id() not in inputs:
                continue
            new_inputs[inp.id()] = self.process_single_input(
                inp.id(), inp.intype, inputs[inp.id()])

        return {**inputs, **new_inputs}
    def inputs_modifier(self, wf: Tool, inputs: Dict, hints: Dict[str, str]):
        nin = {**inputs}
        inmap = wf.inputs_map()

        # Change the 'cwd' just for the scope of this block
        with Path(self.cwd):
            for tag, value in nin.items():
                if tag not in inmap:
                    # Only localise tags within the inputsdict that are in the tool inputs
                    # This might be a problem later for passthrough inputs (Janis doesn't support yet)
                    continue
                intype = inmap[tag].intype

                # If the type of the input is:
                #   (a) A File / Directory
                isfiletype = isinstance(intype.received_type(),
                                        (File, Directory))

                #   (b) Array with a fundamental type (recursively searches if nested array) of File or Directory
                isbasefiletype = isinstance(
                    intype.received_type(), Array) and isinstance(
                        intype.fundamental_type(), (File, Directory))

                # (Skip if not one of these conditions)
                if not (isfiletype or isbasefiletype):
                    try:
                        nin[tag] = intype.coerce_value_if_possible(value)
                    except Exception as e:
                        raise Exception(
                            f"Couldn't coerce the input for '{tag}' ({value}) to type '{intype}': {e}"
                        )
                    continue

                # Qualify the fully qualify the filepath
                try:
                    nin[tag] = self.fully_qualify_filename_array_or_single(
                        value)
                except Exception as e:
                    raise Exception(
                        f"Couldn't qualify the filename for the input '{tag}' ({value}) to type '{intype}': {e}"
                    )

            return nin