Repository: deepset-ai/haystack

Issue:
`Pipeline.connect()` should return the `Pipeline` instance
When calling `connect()` it would be useful if the method returns the instance of the `Pipeline` too. 

This way one could chain multiple connect together with ease.

```
pipe = Pipeline()

pipe.connect("first", "second").connect("second", "third")
```

This could also be useful when creating a `Pipeline` in a notebook, as usually `connect()` is the last statement of the cell we can also show a representation of the `Pipeline`.


Discussion:

Patch:
diff --git a/haystack/core/pipeline/pipeline.py b/haystack/core/pipeline/pipeline.py
index a435f52029..d996a11812 100644
--- a/haystack/core/pipeline/pipeline.py
+++ b/haystack/core/pipeline/pipeline.py
@@ -210,7 +210,7 @@ def add_component(self, name: str, instance: Component) -> None:
             visits=0,
         )
 
-    def connect(self, connect_from: str, connect_to: str) -> None:
+    def connect(self, connect_from: str, connect_to: str) -> "Pipeline":
         """
         Connects two components together. All components to connect must exist in the pipeline.
         If connecting to an component that has several output connections, specify the inputs and output names as
@@ -223,7 +223,7 @@ def connect(self, connect_from: str, connect_to: str) -> None:
                 in the format `component_name.connection_name` if the component has multiple inputs.
 
         Returns:
-            None
+            The Pipeline instance
 
         Raises:
             PipelineConnectError: if the two components cannot be connected (for example if one of the components is
@@ -339,7 +339,7 @@ def connect(self, connect_from: str, connect_to: str) -> None:
 
         if receiver in sender_socket.receivers and sender in receiver_socket.senders:
             # This is already connected, nothing to do
-            return
+            return self
 
         if receiver_socket.senders and not receiver_socket.is_variadic:
             # Only variadic input sockets can receive from multiple senders
@@ -363,6 +363,7 @@ def connect(self, connect_from: str, connect_to: str) -> None:
             to_socket=receiver_socket,
             mandatory=receiver_socket.is_mandatory,
         )
+        return self
 
     def get_component(self, name: str) -> Component:
         """
diff --git a/releasenotes/notes/connect-return-pipeline-dcc1e0786b19861e.yaml b/releasenotes/notes/connect-return-pipeline-dcc1e0786b19861e.yaml
new file mode 100644
index 0000000000..686acfa039
--- /dev/null
+++ b/releasenotes/notes/connect-return-pipeline-dcc1e0786b19861e.yaml
@@ -0,0 +1,12 @@
+---
+enhancements:
+  - |
+    Change `Pipeline.connect()` to return the instance of `Pipeline`.
+    This way we can chain multiple `connect()` like so:
+    ```python
+    pipeline.connect("fetcher", "converter") \
+    .connect("converter", "splitter") \
+    .connect("splitter", "ranker") \
+    .connect("ranker", "prompt_builder") \
+    .connect("prompt_builder", "llm")
+    ```


Test patch:
diff --git a/test/core/pipeline/test_connect.py b/test/core/pipeline/test_connect.py
index 92f0afc4a3..96d753069c 100644
--- a/test/core/pipeline/test_connect.py
+++ b/test/core/pipeline/test_connect.py
@@ -18,7 +18,7 @@ def test_connect():
     pipe = Pipeline()
     pipe.add_component("comp1", comp1)
     pipe.add_component("comp2", comp2)
-    pipe.connect("comp1.value", "comp2.value")
+    assert pipe.connect("comp1.value", "comp2.value") is pipe
 
     assert comp1.__haystack_output__.value.receivers == ["comp2"]
     assert comp2.__haystack_input__.value.senders == ["comp1"]