# Buggy code
def __init__(
    self,
    func: Callable,
    inputs: Union[None, str, List[str], Dict[str, str]],
    outputs: Union[None, str, List[str], Dict[str, str]],
    *,
    name: str = None,
    tags: Union[str, Iterable[str]] = None,
    decorators: Iterable[Callable] = None,
):
    """Create a node in the pipeline by providing a function to be called
    along with variable names for inputs and/or outputs.

    Args:
        func: A function that corresponds to the node logic.
            The function should have at least one input or output.
        inputs: The name or the list of the names of variables used as
            inputs to the function. The number of names should match
            the number of arguments in the definition of the provided
            function. When Dict[str, str] is provided, variable names
            will be mapped to function argument names.
        outputs: The name or the list of the names of variables used
            as outputs to the function. The number of names should match
            the number of outputs returned by the provided function.
            When Dict[str, str] is provided, variable names will be mapped
            to the named outputs the function returns.
        name: Optional node name to be used when displaying the node in
            logs or any other visualisations.
        tags: Optional set of tags to be applied to the node.
        decorators: Optional list of decorators to be applied to the node.

    Raises:
        ValueError: Raised in the following cases:
            a) When the provided arguments do not conform to
            the format suggested by the type hint of the argument.
            b) When the node produces multiple outputs with the same name.
            c) An input has the same name as an output.

    """

    if not callable(func):
        raise ValueError(
            _node_error_message(
                "first argument must be a function, not `{}`.".format(
                    type(func).__name__
                )
            )
        )

    if inputs and not isinstance(inputs, (list, dict, str)):
        raise ValueError(
            _node_error_message(
                "`inputs` type must be one of [String, List, Dict, None], "
                "not `{}`.".format(type(inputs).__name__)
            )
        )

    if outputs and not isinstance(outputs, (list, dict, str)):
        raise ValueError(
            _node_error_message(
                "`outputs` type must be one of [String, List, Dict, None], "
                "not `{}`.".format(type(outputs).__name__)
            )
        )

    if not inputs and not outputs:
        raise ValueError(
            _node_error_message("it must have some `inputs` or `outputs`.")
        )

    self._validate_inputs(func, inputs)

    self._func = func
    self._inputs = inputs
    self._outputs = outputs
    self._name = name
    self._tags = set(_to_list(tags))
    self._decorators = list(decorators or [])

    self._validate_unique_outputs()
    self._validate_inputs_dif_than_outputs()


# Traceback (AttributeError)
/home/markf94/.../kedro-project/.venv/bin/python -m piptools compile /home/markf94/.../kedro-project/src/requirements.in
Traceback (most recent call last):
File "/usr/lib64/python3.7/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "/usr/lib64/python3.7/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/home/markf94/.../kedro-project/.venv/lib/python3.7/site-packages/piptools/__main__.py", line 17, in <module>
cli()
File "/home/markf94/.../kedro-project/.venv/lib/python3.7/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/home/markf94/.../kedro-project/.venv/lib/python3.7/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/home/markf94/.../kedro-project/.venv/lib/python3.7/site-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/markf94/.../kedro-project/.venv/lib/python3.7/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/markf94.../kedro-project/.venv/lib/python3.7/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/markf94/.../kedro-project/.venv/lib/python3.7/site-packages/click/decorators.py", line 21, in new_func
return f(get_current_context(), *args, **kwargs)
File "/home/markf94/.../kedro-project/.venv/lib/python3.7/site-packages/piptools/scripts/compile.py", line 304, in cli
for ireq in filter(is_pinned_requirement, ireqs):
File "/home/markf94/.../kedro-project/.venv/lib/python3.7/site-packages/piptools/utils.py", line 122, in is_pinned_requirement
if ireq.editable:
AttributeError: 'ParsedRequirement' object has no attribute 'editable'

# Fixed code
def __init__(
    self,
    func: Callable,
    inputs: Union[None, str, List[str], Dict[str, str]],
    outputs: Union[None, str, List[str], Dict[str, str]],
    *,
    name: str = None,
    tags: Union[str, Iterable[str]] = None,
    decorators: Iterable[Callable] = None,
    confirms: Union[str, List[str]] = None,
):
    """Create a node in the pipeline by providing a function to be called
    along with variable names for inputs and/or outputs.

    Args:
        func: A function that corresponds to the node logic.
            The function should have at least one input or output.
        inputs: The name or the list of the names of variables used as
            inputs to the function. The number of names should match
            the number of arguments in the definition of the provided
            function. When Dict[str, str] is provided, variable names
            will be mapped to function argument names.
        outputs: The name or the list of the names of variables used
            as outputs to the function. The number of names should match
            the number of outputs returned by the provided function.
            When Dict[str, str] is provided, variable names will be mapped
            to the named outputs the function returns.
        name: Optional node name to be used when displaying the node in
            logs or any other visualisations.
        tags: Optional set of tags to be applied to the node.
        decorators: Optional list of decorators to be applied to the node.
        confirms: Optional name or the list of the names of the datasets
            that should be confirmed. This will result in calling
            ``confirm()`` method of the corresponding data set instance.
            Specified dataset names do not necessarily need to be present
            in the node ``inputs`` or ``outputs``.

    Raises:
        ValueError: Raised in the following cases:
            a) When the provided arguments do not conform to
            the format suggested by the type hint of the argument.
            b) When the node produces multiple outputs with the same name.
            c) An input has the same name as an output.

    """

    if not callable(func):
        raise ValueError(
            _node_error_message(
                "first argument must be a function, not `{}`.".format(
                    type(func).__name__
                )
            )
        )

    if inputs and not isinstance(inputs, (list, dict, str)):
        raise ValueError(
            _node_error_message(
                "`inputs` type must be one of [String, List, Dict, None], "
                "not `{}`.".format(type(inputs).__name__)
            )
        )

    if outputs and not isinstance(outputs, (list, dict, str)):
        raise ValueError(
            _node_error_message(
                "`outputs` type must be one of [String, List, Dict, None], "
                "not `{}`.".format(type(outputs).__name__)
            )
        )

    if not inputs and not outputs:
        raise ValueError(
            _node_error_message("it must have some `inputs` or `outputs`.")
        )

    self._validate_inputs(func, inputs)

    self._func = func
    self._inputs = inputs
    self._outputs = outputs
    self._name = name
    self._tags = set(_to_list(tags))
    self._decorators = list(decorators or [])

    self._validate_unique_outputs()
    self._validate_inputs_dif_than_outputs()
    self._confirms = confirms