From d9d4fae57f55d9f44f829c03dc5e9e2596eb0344 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Tue, 14 Jan 2025 15:31:26 +0100 Subject: [PATCH 1/8] Add Secret handling in OpenSearchDocumentStore --- .../opensearch/document_store.py | 57 +++++++++++++++--- .../opensearch/tests/test_document_store.py | 59 +++++++++++++++++++ 2 files changed, 108 insertions(+), 8 deletions(-) diff --git a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py index 6cb5295f0..874f75ad4 100644 --- a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py +++ b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py @@ -9,6 +9,7 @@ from haystack.dataclasses import Document from haystack.document_stores.errors import DocumentStoreError, DuplicateDocumentError from haystack.document_stores.types import DuplicatePolicy +from haystack.utils.auth import Secret from opensearchpy import OpenSearch from opensearchpy.helpers import bulk @@ -45,7 +46,10 @@ def __init__( mappings: Optional[Dict[str, Any]] = None, settings: Optional[Dict[str, Any]] = DEFAULT_SETTINGS, create_index: bool = True, - http_auth: Any = None, + http_auth: Any = ( + Secret.from_env_var("OPENSEARCH_USERNAME", strict=False), # noqa: B008 + Secret.from_env_var("OPENSEARCH_PASSWORD", strict=False), # noqa: B008 + ), use_ssl: Optional[bool] = None, verify_certs: Optional[bool] = None, timeout: Optional[int] = None, @@ -79,6 +83,7 @@ def __init__( - a tuple of (username, password) - a list of [username, password] - a string of "username:password" + If not provided, will read values from OPENSEARCH_USERNAME and OPENSEARCH_PASSWORD environment variables. For AWS authentication with `Urllib3HttpConnection` pass an instance of `AWSAuth`. Defaults to None :param use_ssl: Whether to use SSL. Defaults to None @@ -97,6 +102,20 @@ def __init__( self._mappings = mappings or self._get_default_mappings() self._settings = settings self._create_index = create_index + + # Handle authentication + self._auth_secrets = None + if isinstance(http_auth, tuple) and len(http_auth) == 2: # noqa: PLR2004 + username, password = http_auth + if isinstance(username, Secret) and isinstance(password, Secret): + self._auth_secrets = (username, password) + username_val = username.resolve_value() + password_val = password.resolve_value() + if username_val and password_val: + http_auth = (username_val, password_val) + else: + http_auth = None + self._http_auth = http_auth self._use_ssl = use_ssl self._verify_certs = verify_certs @@ -174,15 +193,24 @@ def create_index( self.client.indices.create(index=index, body={"mappings": mappings, "settings": settings}) def to_dict(self) -> Dict[str, Any]: - # This is not the best solution to serialise this class but is the fastest to implement. - # Not all kwargs types can be serialised to text so this can fail. We must serialise each - # type explicitly to handle this properly. """ Serializes the component to a dictionary. :returns: Dictionary with serialized data. """ + + # Handle http_auth serialization + if self._auth_secrets: + http_auth = tuple(secret.to_dict() for secret in self._auth_secrets) + elif isinstance(self._http_auth, tuple): + # For non-Secret tuples, keep the values as-is + http_auth = self._http_auth + elif isinstance(self._http_auth, AWSAuth): + http_auth = self._http_auth.to_dict() + else: + http_auth = self._http_auth + return default_to_dict( self, hosts=self._hosts, @@ -194,7 +222,7 @@ def to_dict(self) -> Dict[str, Any]: settings=self._settings, create_index=self._create_index, return_embedding=self._return_embedding, - http_auth=self._http_auth.to_dict() if isinstance(self._http_auth, AWSAuth) else self._http_auth, + http_auth=http_auth, use_ssl=self._use_ssl, verify_certs=self._verify_certs, timeout=self._timeout, @@ -208,13 +236,26 @@ def from_dict(cls, data: Dict[str, Any]) -> "OpenSearchDocumentStore": :param data: Dictionary to deserialize from. - :returns: Deserialized component. """ - if http_auth := data.get("init_parameters", {}).get("http_auth"): + init_params = data.get("init_parameters", {}) + if http_auth := init_params.get("http_auth"): if isinstance(http_auth, dict): - data["init_parameters"]["http_auth"] = AWSAuth.from_dict(http_auth) + init_params["http_auth"] = AWSAuth.from_dict(http_auth) + elif isinstance(http_auth, tuple): + secrets: List[Optional[Any]] = [] + for auth_item in http_auth: + if isinstance(auth_item, dict) and "type" in auth_item: + # Handle Secret dict + secret = Secret.from_dict(auth_item) + secrets.append(secret if secret else None) + else: + # Handle plain value + secrets.append(auth_item) + + # Convert to tuple and only set if both values exist + init_params["http_auth"] = tuple(secrets) if all(secrets) else None return default_from_dict(cls, data) diff --git a/integrations/opensearch/tests/test_document_store.py b/integrations/opensearch/tests/test_document_store.py index 043f59891..0d6a8a74f 100644 --- a/integrations/opensearch/tests/test_document_store.py +++ b/integrations/opensearch/tests/test_document_store.py @@ -263,6 +263,65 @@ def test_to_dict_aws_auth(self, _mock_opensearch_client, monkeypatch: pytest.Mon }, } + @patch("haystack_integrations.document_stores.opensearch.document_store.OpenSearch") + def test_init_with_env_var_secrets(self, _mock_opensearch_client, monkeypatch): + """Test the default initialization using environment variables""" + monkeypatch.setenv("OPENSEARCH_USERNAME", "user") + monkeypatch.setenv("OPENSEARCH_PASSWORD", "pass") + + document_store = OpenSearchDocumentStore(hosts="testhost") + assert document_store.client + _mock_opensearch_client.assert_called_once() + assert _mock_opensearch_client.call_args[1]["http_auth"] == ("user", "pass") + + @patch("haystack_integrations.document_stores.opensearch.document_store.OpenSearch") + def test_init_with_missing_env_vars(self, _mock_opensearch_client): + """Test that auth is None when environment variables are missing""" + document_store = OpenSearchDocumentStore(hosts="testhost") + assert document_store.client + _mock_opensearch_client.assert_called_once() + assert _mock_opensearch_client.call_args[1]["http_auth"] is None + + @patch("haystack_integrations.document_stores.opensearch.document_store.OpenSearch") + def test_to_dict_with_env_var_secrets(self, _mock_opensearch_client, monkeypatch): + """Test serialization with environment variables""" + monkeypatch.setenv("OPENSEARCH_USERNAME", "user") + monkeypatch.setenv("OPENSEARCH_PASSWORD", "pass") + + document_store = OpenSearchDocumentStore(hosts="testhost") + serialized = document_store.to_dict() + + assert "http_auth" in serialized["init_parameters"] + auth = serialized["init_parameters"]["http_auth"] + assert isinstance(auth, tuple) + # Check that we have two Secret dictionaries with correct env vars + assert auth[0]["type"] == "env_var" + assert auth[0]["env_vars"] == ["OPENSEARCH_USERNAME"] + assert auth[1]["type"] == "env_var" + assert auth[1]["env_vars"] == ["OPENSEARCH_PASSWORD"] + + @patch("haystack_integrations.document_stores.opensearch.document_store.OpenSearch") + def test_from_dict_with_env_var_secrets(self, _mock_opensearch_client, monkeypatch): + """Test deserialization with environment variables""" + # Set environment variables so the secrets resolve properly + monkeypatch.setenv("OPENSEARCH_USERNAME", "user") + monkeypatch.setenv("OPENSEARCH_PASSWORD", "pass") + + data = { + "type": "haystack_integrations.document_stores.opensearch.document_store.OpenSearchDocumentStore", + "init_parameters": { + "hosts": "testhost", + "http_auth": ( + {"type": "env_var", "env_vars": ["OPENSEARCH_USERNAME"], "strict": False}, + {"type": "env_var", "env_vars": ["OPENSEARCH_PASSWORD"], "strict": False}, + ), + }, + } + document_store = OpenSearchDocumentStore.from_dict(data) + assert document_store.client + _mock_opensearch_client.assert_called_once() + assert _mock_opensearch_client.call_args[1]["http_auth"] == ("user", "pass") + @pytest.mark.integration class TestDocumentStore(DocumentStoreBaseTests): From b2786377809603ce2f4de9752d04bbdf237a5361 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Wed, 15 Jan 2025 11:03:48 +0100 Subject: [PATCH 2/8] only serialize auth secrets when values are resolvable --- .../document_stores/opensearch/document_store.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py index 874f75ad4..0f26bf18b 100644 --- a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py +++ b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py @@ -202,7 +202,12 @@ def to_dict(self) -> Dict[str, Any]: # Handle http_auth serialization if self._auth_secrets: - http_auth = tuple(secret.to_dict() for secret in self._auth_secrets) + # If all secrets are resolved, serialize them + if all(secret.resolve_value() for secret in self._auth_secrets): + http_auth = tuple(secret.to_dict() for secret in self._auth_secrets) + else: + # If any secrets are not resolved, don't serialize them (backwards compatibility) + http_auth = None elif isinstance(self._http_auth, tuple): # For non-Secret tuples, keep the values as-is http_auth = self._http_auth From 33a681e3fc50eaf7cc228261be28649124cf5fcc Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Wed, 15 Jan 2025 14:34:06 +0100 Subject: [PATCH 3/8] Update integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py Co-authored-by: tstadel <60758086+tstadel@users.noreply.github.com> --- .../document_stores/opensearch/document_store.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py index 0f26bf18b..2e3cc87f9 100644 --- a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py +++ b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py @@ -46,10 +46,10 @@ def __init__( mappings: Optional[Dict[str, Any]] = None, settings: Optional[Dict[str, Any]] = DEFAULT_SETTINGS, create_index: bool = True, - http_auth: Any = ( + http_auth: Any = [ Secret.from_env_var("OPENSEARCH_USERNAME", strict=False), # noqa: B008 Secret.from_env_var("OPENSEARCH_PASSWORD", strict=False), # noqa: B008 - ), + ], use_ssl: Optional[bool] = None, verify_certs: Optional[bool] = None, timeout: Optional[int] = None, From 3f4aa3c1336489e7102befb124ac89f4a75171c2 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Wed, 15 Jan 2025 17:36:43 +0100 Subject: [PATCH 4/8] Fixes --- integrations/langfuse/example/chat.py | 3 +- .../opensearch/document_store.py | 42 +++++++++---------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/integrations/langfuse/example/chat.py b/integrations/langfuse/example/chat.py index 2308ed1f4..ca835125b 100644 --- a/integrations/langfuse/example/chat.py +++ b/integrations/langfuse/example/chat.py @@ -13,6 +13,7 @@ from haystack.dataclasses import ChatMessage from haystack.utils.auth import Secret from haystack.utils.hf import HFGenerationAPIType +from haystack.components.generators.utils import print_streaming_chunk from haystack_integrations.components.connectors.langfuse import LangfuseConnector from haystack_integrations.components.generators.anthropic import AnthropicChatGenerator @@ -33,7 +34,7 @@ "cohere": CohereChatGenerator, } -selected_chat_generator = generators[selected_chat_generator]() +selected_chat_generator = generators[selected_chat_generator](model="gpt-3.5-turbo", streaming_callback=print_streaming_chunk) if __name__ == "__main__": diff --git a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py index 2e3cc87f9..82f8458aa 100644 --- a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py +++ b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py @@ -46,10 +46,10 @@ def __init__( mappings: Optional[Dict[str, Any]] = None, settings: Optional[Dict[str, Any]] = DEFAULT_SETTINGS, create_index: bool = True, - http_auth: Any = [ + http_auth: Any = ( Secret.from_env_var("OPENSEARCH_USERNAME", strict=False), # noqa: B008 Secret.from_env_var("OPENSEARCH_PASSWORD", strict=False), # noqa: B008 - ], + ), use_ssl: Optional[bool] = None, verify_certs: Optional[bool] = None, timeout: Optional[int] = None, @@ -104,17 +104,16 @@ def __init__( self._create_index = create_index # Handle authentication - self._auth_secrets = None - if isinstance(http_auth, tuple) and len(http_auth) == 2: # noqa: PLR2004 + if isinstance(http_auth, (tuple, list)) and len(http_auth) == 2: # noqa: PLR2004 username, password = http_auth if isinstance(username, Secret) and isinstance(password, Secret): - self._auth_secrets = (username, password) username_val = username.resolve_value() password_val = password.resolve_value() - if username_val and password_val: - http_auth = (username_val, password_val) - else: - http_auth = None + http_auth = [username_val, password_val] if username_val and password_val else None + else: + http_auth = list(http_auth) + elif isinstance(http_auth, str): + http_auth = http_auth.split(":", 1) self._http_auth = http_auth self._use_ssl = use_ssl @@ -201,16 +200,12 @@ def to_dict(self) -> Dict[str, Any]: """ # Handle http_auth serialization - if self._auth_secrets: - # If all secrets are resolved, serialize them - if all(secret.resolve_value() for secret in self._auth_secrets): - http_auth = tuple(secret.to_dict() for secret in self._auth_secrets) - else: - # If any secrets are not resolved, don't serialize them (backwards compatibility) - http_auth = None - elif isinstance(self._http_auth, tuple): - # For non-Secret tuples, keep the values as-is - http_auth = self._http_auth + if isinstance(self._http_auth, list) and all(isinstance(item, Secret) for item in self._http_auth): + http_auth = [secret.to_dict() for secret in self._http_auth if secret.resolve_value()] + elif isinstance(self._http_auth, (tuple, list)): + http_auth = list(self._http_auth) + elif isinstance(self._http_auth, str): + http_auth = self._http_auth.split(":", 1) elif isinstance(self._http_auth, AWSAuth): http_auth = self._http_auth.to_dict() else: @@ -248,7 +243,7 @@ def from_dict(cls, data: Dict[str, Any]) -> "OpenSearchDocumentStore": if http_auth := init_params.get("http_auth"): if isinstance(http_auth, dict): init_params["http_auth"] = AWSAuth.from_dict(http_auth) - elif isinstance(http_auth, tuple): + elif isinstance(http_auth, (tuple, list)): secrets: List[Optional[Any]] = [] for auth_item in http_auth: if isinstance(auth_item, dict) and "type" in auth_item: @@ -259,8 +254,11 @@ def from_dict(cls, data: Dict[str, Any]) -> "OpenSearchDocumentStore": # Handle plain value secrets.append(auth_item) - # Convert to tuple and only set if both values exist - init_params["http_auth"] = tuple(secrets) if all(secrets) else None + # Convert to list and only set if both values exist + init_params["http_auth"] = list(secrets) if all(secrets) else None + elif isinstance(http_auth, str): + # Split string into username and password + init_params["http_auth"] = http_auth.split(":", 1) return default_from_dict(cls, data) From b703fa2c6475305c08b3b99a6b0e56777c102a29 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Wed, 15 Jan 2025 17:41:01 +0100 Subject: [PATCH 5/8] Revert accidental commit --- integrations/langfuse/example/chat.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/integrations/langfuse/example/chat.py b/integrations/langfuse/example/chat.py index ca835125b..2308ed1f4 100644 --- a/integrations/langfuse/example/chat.py +++ b/integrations/langfuse/example/chat.py @@ -13,7 +13,6 @@ from haystack.dataclasses import ChatMessage from haystack.utils.auth import Secret from haystack.utils.hf import HFGenerationAPIType -from haystack.components.generators.utils import print_streaming_chunk from haystack_integrations.components.connectors.langfuse import LangfuseConnector from haystack_integrations.components.generators.anthropic import AnthropicChatGenerator @@ -34,7 +33,7 @@ "cohere": CohereChatGenerator, } -selected_chat_generator = generators[selected_chat_generator](model="gpt-3.5-turbo", streaming_callback=print_streaming_chunk) +selected_chat_generator = generators[selected_chat_generator]() if __name__ == "__main__": From fb903dfb5fecd5807b8f58798bc4544e04256be4 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Thu, 16 Jan 2025 11:01:15 +0100 Subject: [PATCH 6/8] Special list of Secrets handling only, keep everything else as it was before --- .../opensearch/document_store.py | 48 ++++++++----------- .../opensearch/tests/test_document_store.py | 11 +++-- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py index 82f8458aa..0b7cbbe1f 100644 --- a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py +++ b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py @@ -102,18 +102,16 @@ def __init__( self._mappings = mappings or self._get_default_mappings() self._settings = settings self._create_index = create_index + self._http_auth_are_secrets = False # Handle authentication if isinstance(http_auth, (tuple, list)) and len(http_auth) == 2: # noqa: PLR2004 username, password = http_auth if isinstance(username, Secret) and isinstance(password, Secret): + self._http_auth_are_secrets = True username_val = username.resolve_value() password_val = password.resolve_value() http_auth = [username_val, password_val] if username_val and password_val else None - else: - http_auth = list(http_auth) - elif isinstance(http_auth, str): - http_auth = http_auth.split(":", 1) self._http_auth = http_auth self._use_ssl = use_ssl @@ -198,14 +196,13 @@ def to_dict(self) -> Dict[str, Any]: :returns: Dictionary with serialized data. """ - # Handle http_auth serialization - if isinstance(self._http_auth, list) and all(isinstance(item, Secret) for item in self._http_auth): - http_auth = [secret.to_dict() for secret in self._http_auth if secret.resolve_value()] - elif isinstance(self._http_auth, (tuple, list)): - http_auth = list(self._http_auth) - elif isinstance(self._http_auth, str): - http_auth = self._http_auth.split(":", 1) + if isinstance(self._http_auth, list) and self._http_auth_are_secrets: + # Recreate the Secret objects for serialization + http_auth = [ + Secret.from_env_var("OPENSEARCH_USERNAME", strict=False).to_dict(), + Secret.from_env_var("OPENSEARCH_PASSWORD", strict=False).to_dict(), + ] elif isinstance(self._http_auth, AWSAuth): http_auth = self._http_auth.to_dict() else: @@ -244,22 +241,19 @@ def from_dict(cls, data: Dict[str, Any]) -> "OpenSearchDocumentStore": if isinstance(http_auth, dict): init_params["http_auth"] = AWSAuth.from_dict(http_auth) elif isinstance(http_auth, (tuple, list)): - secrets: List[Optional[Any]] = [] - for auth_item in http_auth: - if isinstance(auth_item, dict) and "type" in auth_item: - # Handle Secret dict - secret = Secret.from_dict(auth_item) - secrets.append(secret if secret else None) - else: - # Handle plain value - secrets.append(auth_item) - - # Convert to list and only set if both values exist - init_params["http_auth"] = list(secrets) if all(secrets) else None - elif isinstance(http_auth, str): - # Split string into username and password - init_params["http_auth"] = http_auth.split(":", 1) - + # to maintain backwards compatibility this could be many different types, just use Any + secrets: Any = None + + are_secrets = all(isinstance(item, dict) and "type" in item for item in http_auth) + if are_secrets: + # it would be nice to use deserialize_secrets_inplace here but that function + # is not able to handle lists of secrets + secrets = [ + Secret.from_dict(item) for item in http_auth if isinstance(item, dict) and "type" in item + ] + else: + secrets = http_auth + init_params["http_auth"] = secrets return default_from_dict(cls, data) def count_documents(self) -> int: diff --git a/integrations/opensearch/tests/test_document_store.py b/integrations/opensearch/tests/test_document_store.py index 0d6a8a74f..82c21e6fe 100644 --- a/integrations/opensearch/tests/test_document_store.py +++ b/integrations/opensearch/tests/test_document_store.py @@ -272,7 +272,7 @@ def test_init_with_env_var_secrets(self, _mock_opensearch_client, monkeypatch): document_store = OpenSearchDocumentStore(hosts="testhost") assert document_store.client _mock_opensearch_client.assert_called_once() - assert _mock_opensearch_client.call_args[1]["http_auth"] == ("user", "pass") + assert _mock_opensearch_client.call_args[1]["http_auth"] == ["user", "pass"] @patch("haystack_integrations.document_stores.opensearch.document_store.OpenSearch") def test_init_with_missing_env_vars(self, _mock_opensearch_client): @@ -293,7 +293,8 @@ def test_to_dict_with_env_var_secrets(self, _mock_opensearch_client, monkeypatch assert "http_auth" in serialized["init_parameters"] auth = serialized["init_parameters"]["http_auth"] - assert isinstance(auth, tuple) + assert isinstance(auth, list) + assert len(auth) == 2 # Check that we have two Secret dictionaries with correct env vars assert auth[0]["type"] == "env_var" assert auth[0]["env_vars"] == ["OPENSEARCH_USERNAME"] @@ -311,16 +312,16 @@ def test_from_dict_with_env_var_secrets(self, _mock_opensearch_client, monkeypat "type": "haystack_integrations.document_stores.opensearch.document_store.OpenSearchDocumentStore", "init_parameters": { "hosts": "testhost", - "http_auth": ( + "http_auth": [ {"type": "env_var", "env_vars": ["OPENSEARCH_USERNAME"], "strict": False}, {"type": "env_var", "env_vars": ["OPENSEARCH_PASSWORD"], "strict": False}, - ), + ], }, } document_store = OpenSearchDocumentStore.from_dict(data) assert document_store.client _mock_opensearch_client.assert_called_once() - assert _mock_opensearch_client.call_args[1]["http_auth"] == ("user", "pass") + assert _mock_opensearch_client.call_args[1]["http_auth"] == ["user", "pass"] @pytest.mark.integration From a68e7ffe25bd0059cea8e94ace2a76ef600cc88b Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Thu, 16 Jan 2025 11:05:22 +0100 Subject: [PATCH 7/8] Small improvement --- .../document_stores/opensearch/document_store.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py index 0b7cbbe1f..28ce23925 100644 --- a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py +++ b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py @@ -246,11 +246,8 @@ def from_dict(cls, data: Dict[str, Any]) -> "OpenSearchDocumentStore": are_secrets = all(isinstance(item, dict) and "type" in item for item in http_auth) if are_secrets: - # it would be nice to use deserialize_secrets_inplace here but that function - # is not able to handle lists of secrets - secrets = [ - Secret.from_dict(item) for item in http_auth if isinstance(item, dict) and "type" in item - ] + # Simplified list comprehension since all items are confirmed to be secrets + secrets = [Secret.from_dict(item) for item in http_auth] else: secrets = http_auth init_params["http_auth"] = secrets From a4e7abf492605ed78922576cc2a0e852ed4a8838 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Thu, 16 Jan 2025 11:09:44 +0100 Subject: [PATCH 8/8] More simplifications --- .../document_stores/opensearch/document_store.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py index 28ce23925..7deaad285 100644 --- a/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py +++ b/integrations/opensearch/src/haystack_integrations/document_stores/opensearch/document_store.py @@ -241,16 +241,8 @@ def from_dict(cls, data: Dict[str, Any]) -> "OpenSearchDocumentStore": if isinstance(http_auth, dict): init_params["http_auth"] = AWSAuth.from_dict(http_auth) elif isinstance(http_auth, (tuple, list)): - # to maintain backwards compatibility this could be many different types, just use Any - secrets: Any = None - are_secrets = all(isinstance(item, dict) and "type" in item for item in http_auth) - if are_secrets: - # Simplified list comprehension since all items are confirmed to be secrets - secrets = [Secret.from_dict(item) for item in http_auth] - else: - secrets = http_auth - init_params["http_auth"] = secrets + init_params["http_auth"] = [Secret.from_dict(item) for item in http_auth] if are_secrets else http_auth return default_from_dict(cls, data) def count_documents(self) -> int: