|
15 | 15 | from haystack.components.routers import ConditionalRouter
|
16 | 16 | from haystack.core.component import component
|
17 | 17 | from haystack.core.component.types import InputSocket, OutputSocket, Variadic
|
18 |
| -from haystack.core.errors import PipelineDrawingError, PipelineError, PipelineMaxLoops, PipelineRuntimeError |
| 18 | +from haystack.core.errors import ( |
| 19 | + PipelineConnectError, |
| 20 | + PipelineDrawingError, |
| 21 | + PipelineError, |
| 22 | + PipelineMaxLoops, |
| 23 | + PipelineRuntimeError, |
| 24 | +) |
19 | 25 | from haystack.core.pipeline import Pipeline, PredefinedPipeline
|
20 | 26 | from haystack.core.serialization import DeserializationCallbacks
|
21 | 27 | from haystack.document_stores.in_memory import InMemoryDocumentStore
|
@@ -759,6 +765,178 @@ def test__prepare_component_input_data_with_non_existing_input(self, caplog):
|
759 | 765 | "please check your run parameters." in caplog.text
|
760 | 766 | )
|
761 | 767 |
|
| 768 | + def test_connect(self): |
| 769 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 770 | + comp2 = component_class("Comp2", input_types={"value": int})() |
| 771 | + pipe = Pipeline() |
| 772 | + pipe.add_component("comp1", comp1) |
| 773 | + pipe.add_component("comp2", comp2) |
| 774 | + assert pipe.connect("comp1.value", "comp2.value") is pipe |
| 775 | + |
| 776 | + assert comp1.__haystack_output__.value.receivers == ["comp2"] |
| 777 | + assert comp2.__haystack_input__.value.senders == ["comp1"] |
| 778 | + assert list(pipe.graph.edges) == [("comp1", "comp2", "value/value")] |
| 779 | + |
| 780 | + def test_connect_already_connected(self): |
| 781 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 782 | + comp2 = component_class("Comp2", input_types={"value": int})() |
| 783 | + pipe = Pipeline() |
| 784 | + pipe.add_component("comp1", comp1) |
| 785 | + pipe.add_component("comp2", comp2) |
| 786 | + pipe.connect("comp1.value", "comp2.value") |
| 787 | + pipe.connect("comp1.value", "comp2.value") |
| 788 | + |
| 789 | + assert comp1.__haystack_output__.value.receivers == ["comp2"] |
| 790 | + assert comp2.__haystack_input__.value.senders == ["comp1"] |
| 791 | + assert list(pipe.graph.edges) == [("comp1", "comp2", "value/value")] |
| 792 | + |
| 793 | + def test_connect_with_sender_component_name(self): |
| 794 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 795 | + comp2 = component_class("Comp2", input_types={"value": int})() |
| 796 | + pipe = Pipeline() |
| 797 | + pipe.add_component("comp1", comp1) |
| 798 | + pipe.add_component("comp2", comp2) |
| 799 | + pipe.connect("comp1", "comp2.value") |
| 800 | + |
| 801 | + assert comp1.__haystack_output__.value.receivers == ["comp2"] |
| 802 | + assert comp2.__haystack_input__.value.senders == ["comp1"] |
| 803 | + assert list(pipe.graph.edges) == [("comp1", "comp2", "value/value")] |
| 804 | + |
| 805 | + def test_connect_with_receiver_component_name(self): |
| 806 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 807 | + comp2 = component_class("Comp2", input_types={"value": int})() |
| 808 | + pipe = Pipeline() |
| 809 | + pipe.add_component("comp1", comp1) |
| 810 | + pipe.add_component("comp2", comp2) |
| 811 | + pipe.connect("comp1.value", "comp2") |
| 812 | + |
| 813 | + assert comp1.__haystack_output__.value.receivers == ["comp2"] |
| 814 | + assert comp2.__haystack_input__.value.senders == ["comp1"] |
| 815 | + assert list(pipe.graph.edges) == [("comp1", "comp2", "value/value")] |
| 816 | + |
| 817 | + def test_connect_with_sender_and_receiver_component_name(self): |
| 818 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 819 | + comp2 = component_class("Comp2", input_types={"value": int})() |
| 820 | + pipe = Pipeline() |
| 821 | + pipe.add_component("comp1", comp1) |
| 822 | + pipe.add_component("comp2", comp2) |
| 823 | + pipe.connect("comp1", "comp2") |
| 824 | + |
| 825 | + assert comp1.__haystack_output__.value.receivers == ["comp2"] |
| 826 | + assert comp2.__haystack_input__.value.senders == ["comp1"] |
| 827 | + assert list(pipe.graph.edges) == [("comp1", "comp2", "value/value")] |
| 828 | + |
| 829 | + def test_connect_with_sender_not_in_pipeline(self): |
| 830 | + comp2 = component_class("Comp2", input_types={"value": int})() |
| 831 | + pipe = Pipeline() |
| 832 | + pipe.add_component("comp2", comp2) |
| 833 | + with pytest.raises(ValueError): |
| 834 | + pipe.connect("comp1.value", "comp2.value") |
| 835 | + |
| 836 | + def test_connect_with_receiver_not_in_pipeline(self): |
| 837 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 838 | + pipe = Pipeline() |
| 839 | + pipe.add_component("comp1", comp1) |
| 840 | + with pytest.raises(ValueError): |
| 841 | + pipe.connect("comp1.value", "comp2.value") |
| 842 | + |
| 843 | + def test_connect_with_sender_socket_name_not_in_pipeline(self): |
| 844 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 845 | + comp2 = component_class("Comp2", input_types={"value": int})() |
| 846 | + pipe = Pipeline() |
| 847 | + pipe.add_component("comp1", comp1) |
| 848 | + pipe.add_component("comp2", comp2) |
| 849 | + with pytest.raises(PipelineConnectError): |
| 850 | + pipe.connect("comp1.non_existing", "comp2.value") |
| 851 | + |
| 852 | + def test_connect_with_receiver_socket_name_not_in_pipeline(self): |
| 853 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 854 | + comp2 = component_class("Comp2", input_types={"value": int})() |
| 855 | + pipe = Pipeline() |
| 856 | + pipe.add_component("comp1", comp1) |
| 857 | + pipe.add_component("comp2", comp2) |
| 858 | + with pytest.raises(PipelineConnectError): |
| 859 | + pipe.connect("comp1.value", "comp2.non_existing") |
| 860 | + |
| 861 | + def test_connect_with_no_matching_types_and_same_names(self): |
| 862 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 863 | + comp2 = component_class("Comp2", input_types={"value": str})() |
| 864 | + pipe = Pipeline() |
| 865 | + pipe.add_component("comp1", comp1) |
| 866 | + pipe.add_component("comp2", comp2) |
| 867 | + with pytest.raises(PipelineConnectError): |
| 868 | + pipe.connect("comp1", "comp2") |
| 869 | + |
| 870 | + def test_connect_with_multiple_sender_connections_with_same_type_and_differing_name(self): |
| 871 | + comp1 = component_class("Comp1", output_types={"val1": int, "val2": int})() |
| 872 | + comp2 = component_class("Comp2", input_types={"value": int})() |
| 873 | + pipe = Pipeline() |
| 874 | + pipe.add_component("comp1", comp1) |
| 875 | + pipe.add_component("comp2", comp2) |
| 876 | + with pytest.raises(PipelineConnectError): |
| 877 | + pipe.connect("comp1", "comp2") |
| 878 | + |
| 879 | + def test_connect_with_multiple_receiver_connections_with_same_type_and_differing_name(self): |
| 880 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 881 | + comp2 = component_class("Comp2", input_types={"val1": int, "val2": int})() |
| 882 | + pipe = Pipeline() |
| 883 | + pipe.add_component("comp1", comp1) |
| 884 | + pipe.add_component("comp2", comp2) |
| 885 | + with pytest.raises(PipelineConnectError): |
| 886 | + pipe.connect("comp1", "comp2") |
| 887 | + |
| 888 | + def test_connect_with_multiple_sender_connections_with_same_type_and_same_name(self): |
| 889 | + comp1 = component_class("Comp1", output_types={"value": int, "other": int})() |
| 890 | + comp2 = component_class("Comp2", input_types={"value": int})() |
| 891 | + pipe = Pipeline() |
| 892 | + pipe.add_component("comp1", comp1) |
| 893 | + pipe.add_component("comp2", comp2) |
| 894 | + pipe.connect("comp1", "comp2") |
| 895 | + |
| 896 | + assert comp1.__haystack_output__.value.receivers == ["comp2"] |
| 897 | + assert comp2.__haystack_input__.value.senders == ["comp1"] |
| 898 | + assert list(pipe.graph.edges) == [("comp1", "comp2", "value/value")] |
| 899 | + |
| 900 | + def test_connect_with_multiple_receiver_connections_with_same_type_and_same_name(self): |
| 901 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 902 | + comp2 = component_class("Comp2", input_types={"value": int, "other": int})() |
| 903 | + pipe = Pipeline() |
| 904 | + pipe.add_component("comp1", comp1) |
| 905 | + pipe.add_component("comp2", comp2) |
| 906 | + pipe.connect("comp1", "comp2") |
| 907 | + |
| 908 | + assert comp1.__haystack_output__.value.receivers == ["comp2"] |
| 909 | + assert comp2.__haystack_input__.value.senders == ["comp1"] |
| 910 | + assert list(pipe.graph.edges) == [("comp1", "comp2", "value/value")] |
| 911 | + |
| 912 | + def test_connect_multiple_outputs_to_non_variadic_input(self): |
| 913 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 914 | + comp2 = component_class("Comp2", output_types={"value": int})() |
| 915 | + comp3 = component_class("Comp3", input_types={"value": int})() |
| 916 | + pipe = Pipeline() |
| 917 | + pipe.add_component("comp1", comp1) |
| 918 | + pipe.add_component("comp2", comp2) |
| 919 | + pipe.add_component("comp3", comp3) |
| 920 | + pipe.connect("comp1.value", "comp3.value") |
| 921 | + with pytest.raises(PipelineConnectError): |
| 922 | + pipe.connect("comp2.value", "comp3.value") |
| 923 | + |
| 924 | + def test_connect_multiple_outputs_to_variadic_input(self): |
| 925 | + comp1 = component_class("Comp1", output_types={"value": int})() |
| 926 | + comp2 = component_class("Comp2", output_types={"value": int})() |
| 927 | + comp3 = component_class("Comp3", input_types={"value": Variadic[int]})() |
| 928 | + pipe = Pipeline() |
| 929 | + pipe.add_component("comp1", comp1) |
| 930 | + pipe.add_component("comp2", comp2) |
| 931 | + pipe.add_component("comp3", comp3) |
| 932 | + pipe.connect("comp1.value", "comp3.value") |
| 933 | + pipe.connect("comp2.value", "comp3.value") |
| 934 | + |
| 935 | + assert comp1.__haystack_output__.value.receivers == ["comp3"] |
| 936 | + assert comp2.__haystack_output__.value.receivers == ["comp3"] |
| 937 | + assert comp3.__haystack_input__.value.senders == ["comp1", "comp2"] |
| 938 | + assert list(pipe.graph.edges) == [("comp1", "comp3", "value/value"), ("comp2", "comp3", "value/value")] |
| 939 | + |
762 | 940 |
|
763 | 941 | @component
|
764 | 942 | class FakeComponent:
|
|
0 commit comments