Repository: kedro-org/kedro
File: kedro/pipeline/modular_pipeline.py (Python)

Code before:
    return _is_single_parameter(name) or _is_all_parameters(name)


def _validate_inputs_outputs(
    inputs: AbstractSet[str], outputs: AbstractSet[str], pipe: Pipeline
) -> None:
    """Safeguards to ensure that:
    - parameters are not specified under inputs
    - inputs are only free inputs
    - outputs do not contain free inputs
    """
    inputs = {_strip_transcoding(k) for k in inputs}
    outputs = {_strip_transcoding(k) for k in outputs}

    if any(_is_parameter(i) for i in inputs):
        raise ModularPipelineError(
            "Parameters should be specified in the 'parameters' argument"
        )

    free_inputs = {_strip_transcoding(i) for i in pipe.inputs()}

    if not inputs <= free_inputs:
        raise ModularPipelineError("Inputs must not be outputs from another node")

    if outputs & free_inputs:
        raise ModularPipelineError("Outputs can't contain free inputs to the pipeline")


def _validate_datasets_exist(
    inputs: AbstractSet[str],
    outputs: AbstractSet[str],
    parameters: AbstractSet[str],
    pipe: Pipeline,
) -> None:
    """Validate that inputs, parameters and outputs map correctly onto the provided nodes."""
    inputs = {_strip_transcoding(k) for k in inputs}
    outputs = {_strip_transcoding(k) for k in outputs}

    existing = {_strip_transcoding(ds) for ds in pipe.datasets()}
    non_existent = (inputs | outputs | parameters) - existing
    if non_existent:
        possible_matches = []
        for non_existent_input in non_existent:
            possible_matches += difflib.get_close_matches(non_existent_input, existing)

        error_msg = f"Failed to map datasets and/or parameters onto the nodes provided: {', '.join(sorted(non_existent))}"
        suggestions = (
            f" - did you mean one of these instead: {', '.join(sorted(possible_matches))}"
            if possible_matches
            else ""
        )

Review comment (suggestion):
I'm conscious that we only really define this term deep in [this docstring](https://docs.kedro.org/en/stable/api/kedro.pipeline.Pipeline.html#kedro.pipeline.Pipeline.inputs). 

Perhaps we need to also define the term something like this:

```suggestion
        raise ModularPipelineError("Outputs can't contain free inputs to the pipeline (i.e. The names of inputs that must be provided at runtime so that the pipeline is runnable).
--
 

<br class="Apple-interchange-newline">)")
```

Code after:
    return _is_single_parameter(name) or _is_all_parameters(name)


def _validate_inputs_outputs(
    inputs: AbstractSet[str], outputs: AbstractSet[str], pipe: Pipeline
) -> None:
    """Safeguards to ensure that:
    - parameters are not specified under inputs
    - inputs are only free inputs
    - outputs do not contain free inputs
    """
    inputs = {_strip_transcoding(k) for k in inputs}
    outputs = {_strip_transcoding(k) for k in outputs}

    if any(_is_parameter(i) for i in inputs):
        raise ModularPipelineError(
            "Parameters should be specified in the 'parameters' argument"
        )

    free_inputs = {_strip_transcoding(i) for i in pipe.inputs()}

    if not inputs <= free_inputs:
        raise ModularPipelineError(
            "Inputs must not be outputs from another node in the same pipeline"
        )

    if outputs & free_inputs:
        raise ModularPipelineError(
            "All outputs must be generated by some node within the pipeline"
        )


def _validate_datasets_exist(
    inputs: AbstractSet[str],
    outputs: AbstractSet[str],
    parameters: AbstractSet[str],
    pipe: Pipeline,
) -> None:
    """Validate that inputs, parameters and outputs map correctly onto the provided nodes."""
    inputs = {_strip_transcoding(k) for k in inputs}
    outputs = {_strip_transcoding(k) for k in outputs}

    existing = {_strip_transcoding(ds) for ds in pipe.datasets()}
    non_existent = (inputs | outputs | parameters) - existing
    if non_existent:
        sorted_non_existent = sorted(non_existent)
        possible_matches = []
        for non_existent_input in sorted_non_existent:
            possible_matches += difflib.get_close_matches(non_existent_input, existing)

        error_msg = f"Failed to map datasets and/or parameters onto the nodes provided: {', '.join(sorted_non_existent)}"