Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions haystack/core/pipeline/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ def remove_component(self, name: str) -> Component:

return instance

def connect(self, sender: str, receiver: str) -> "PipelineBase": # noqa: PLR0915 PLR0912
def connect(self, sender: str, receiver: str) -> "PipelineBase": # noqa: PLR0915 PLR0912 C901 pylint: disable=too-many-branches
"""
Connects two components together.

Expand Down Expand Up @@ -456,13 +456,20 @@ def connect(self, sender: str, receiver: str) -> "PipelineBase": # noqa: PLR091
except KeyError as exc:
raise ValueError(f"Component named {receiver_component_name} not found in the pipeline.") from exc

if not sender_sockets:
raise PipelineConnectError(
f"'{sender_component_name}' does not have any output connections. "
f"Please check that the output types of '{sender_component_name}.run' are set, "
f"for example by using the '@component.output_types' decorator."
)

# If the name of either socket is given, get the socket
sender_socket: Optional[OutputSocket] = None
if sender_socket_name:
sender_socket = sender_sockets.get(sender_socket_name)
if not sender_socket:
raise PipelineConnectError(
f"'{sender} does not exist. "
f"'{sender}' does not exist. "
f"Output connections of {sender_component_name} are: "
+ ", ".join([f"{name} (type {_type_name(socket.type)})" for name, socket in sender_sockets.items()])
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fixes:
- |
Return a more informative error message when attempting to connect two components and the sender component does not have any OutputSockets defined.
34 changes: 34 additions & 0 deletions test/core/pipeline/test_pipeline_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,40 @@ def test_remove_component_allows_you_to_reuse_the_component(self):
# instance = pipe2.get_component("some")
# assert instance == component

def test_connect_with_nonexistent_output_socket_name(self):
"""Test connecting using a non-existent output socket name."""
comp1 = component_class("Comp1", output_types={"output": int})()
comp2 = component_class("Comp2", input_types={"value": int})()
pipe = PipelineBase()
pipe.add_component("comp1", comp1)
pipe.add_component("comp2", comp2)

with pytest.raises(PipelineConnectError) as excinfo:
pipe.connect("comp1.value", "comp2.value")

assert "'comp1.value' does not exist" in str(excinfo.value)
assert "Output connections of comp1 are: output (type int)" in str(excinfo.value)

def test_connect_with_no_output_sockets(self):
"""Test connecting from a component that has no output sockets at all."""

@component
class NoOutputComponent:
def run(self):
pass

comp1 = NoOutputComponent()
comp2 = component_class("Comp2", input_types={"value": int})()
pipe = PipelineBase()
pipe.add_component("comp1", comp1)
pipe.add_component("comp2", comp2)

with pytest.raises(PipelineConnectError) as excinfo:
pipe.connect("comp1.value", "comp2.value")

assert "'comp1' does not have any output connections" in str(excinfo.value)
assert "@component.output_types" in str(excinfo.value)

# UNIT
def test_get_component_name(self):
pipe = PipelineBase()
Expand Down
Loading