Skip to content

Commit 22bbfa2

Browse files
Fix OpenSearch sync store: add dependency and update codegen
- Add opensearch-py dependency to sync library's pyproject.toml - Update codegen script to transform AsyncOpenSearch → OpenSearch - Regenerate sync code with correct synchronous OpenSearch client - Improve ImportError message for missing opensearch dependency This fixes the type checking errors in the sync library where the generated code was incorrectly using AsyncOpenSearch instead of the synchronous OpenSearch client. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: William Easton <[email protected]>
1 parent ad57849 commit 22bbfa2

File tree

7 files changed

+29
-23
lines changed

7 files changed

+29
-23
lines changed

key-value/key-value-aio/src/key_value/aio/stores/opensearch/store.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
get_source_from_body,
4545
)
4646
except ImportError as e:
47-
msg = "OpenSearchStore requires py-key-value-aio[opensearch]"
47+
msg = "OpenSearchStore requires opensearch-py[async]>=2.0.0. Install with: pip install 'py-key-value-aio[opensearch]'"
4848
raise ImportError(msg) from e
4949

5050

key-value/key-value-sync/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ valkey = ["valkey-glide-sync>=2.1.0"]
4040
vault = ["hvac>=2.3.0", "types-hvac>=2.3.0"]
4141
memcached = ["aiomcache>=0.8.0"]
4242
elasticsearch = ["elasticsearch>=8.0.0", "aiohttp>=3.12"]
43+
opensearch = ["opensearch-py[async]>=2.0.0"]
4344
pydantic = ["pydantic>=2.11.9"]
4445
keyring = ["keyring>=25.6.0"]
4546
keyring-linux = ["keyring>=25.6.0", "dbus-python>=1.4.0"]
@@ -66,7 +67,7 @@ env_files = [".env"]
6667

6768
[dependency-groups]
6869
dev = [
69-
"py-key-value-sync[memory,disk,redis,elasticsearch,memcached,mongodb,vault,rocksdb]",
70+
"py-key-value-sync[memory,disk,redis,elasticsearch,opensearch,memcached,mongodb,vault,rocksdb]",
7071
"py-key-value-sync[valkey]; platform_system != 'Windows'",
7172
"py-key-value-sync[pydantic]",
7273
"py-key-value-sync[keyring]",

key-value/key-value-sync/src/key_value/sync/code_gen/stores/opensearch/store.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from key_value.sync.code_gen.stores.opensearch.utils import LessCapableJsonSerializer, new_bulk_action
2727

2828
try:
29-
from opensearchpy import AsyncOpenSearch
29+
from opensearchpy import OpenSearch
3030
from opensearchpy.exceptions import RequestError
3131

3232
from key_value.sync.code_gen.stores.opensearch.utils import (
@@ -37,7 +37,7 @@
3737
get_source_from_body,
3838
)
3939
except ImportError as e:
40-
msg = "OpenSearchStore requires py-key-value-aio[opensearch]"
40+
msg = "OpenSearchStore requires opensearch-py[async]>=2.0.0. Install with: pip install 'py-key-value-aio[opensearch]'"
4141
raise ImportError(msg) from e
4242

4343
logger = logging.getLogger(__name__)
@@ -118,7 +118,7 @@ class OpenSearchStore(
118118
`OpenSearchV1CollectionSanitizationStrategy` strategies.
119119
"""
120120

121-
_client: AsyncOpenSearch
121+
_client: OpenSearch
122122

123123
_index_prefix: str
124124

@@ -133,7 +133,7 @@ class OpenSearchStore(
133133
def __init__(
134134
self,
135135
*,
136-
opensearch_client: AsyncOpenSearch,
136+
opensearch_client: OpenSearch,
137137
index_prefix: str,
138138
default_collection: str | None = None,
139139
key_sanitization_strategy: SanitizationStrategy | None = None,
@@ -172,7 +172,7 @@ def __init__(
172172
def __init__(
173173
self,
174174
*,
175-
opensearch_client: AsyncOpenSearch | None = None,
175+
opensearch_client: OpenSearch | None = None,
176176
url: str | None = None,
177177
api_key: str | None = None,
178178
index_prefix: str,
@@ -203,7 +203,7 @@ def __init__(
203203
if api_key:
204204
client_kwargs["api_key"] = api_key
205205

206-
self._client = AsyncOpenSearch(**client_kwargs)
206+
self._client = OpenSearch(**client_kwargs)
207207
else:
208208
msg = "Either opensearch_client or url must be provided"
209209
raise ValueError(msg)

key-value/key-value-sync/src/key_value/sync/code_gen/stores/opensearch/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# DO NOT CHANGE! Change the original file instead.
44
from typing import Any, TypeVar, cast
55

6-
from opensearchpy import AsyncOpenSearch
6+
from opensearchpy import OpenSearch
77
from opensearchpy.serializer import JSONSerializer
88

99

@@ -128,6 +128,6 @@ def default(self, data: Any) -> Any: # type: ignore[reportIncompatibleMethodOve
128128
raise TypeError(msg)
129129

130130
@classmethod
131-
def install_serializer(cls, client: AsyncOpenSearch) -> None:
131+
def install_serializer(cls, client: OpenSearch) -> None:
132132
# OpenSearch uses a different serializer architecture
133133
client.transport.serializer = cls() # type: ignore[reportUnknownMemberType]

key-value/key-value-sync/tests/code_gen/stores/opensearch/test_opensearch.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from inline_snapshot import snapshot
1111
from key_value.shared.stores.wait import wait_for_true
1212
from key_value.shared.utils.managed_entry import ManagedEntry
13-
from opensearchpy import AsyncOpenSearch
13+
from opensearchpy import OpenSearch
1414
from typing_extensions import override
1515

1616
from key_value.sync.code_gen.stores.base import BaseStore
@@ -35,12 +35,12 @@
3535
OPENSEARCH_VERSIONS_TO_TEST = ["2.11.0", "2.18.0"]
3636

3737

38-
def get_opensearch_client() -> AsyncOpenSearch:
39-
return AsyncOpenSearch(hosts=[OS_URL], use_ssl=False, verify_certs=False)
38+
def get_opensearch_client() -> OpenSearch:
39+
return OpenSearch(hosts=[OS_URL], use_ssl=False, verify_certs=False)
4040

4141

4242
def ping_opensearch() -> bool:
43-
os_client: AsyncOpenSearch = get_opensearch_client()
43+
os_client: OpenSearch = get_opensearch_client()
4444

4545
with os_client:
4646
try:
@@ -49,7 +49,7 @@ def ping_opensearch() -> bool:
4949
return False
5050

5151

52-
def cleanup_opensearch_indices(opensearch_client: AsyncOpenSearch):
52+
def cleanup_opensearch_indices(opensearch_client: OpenSearch):
5353
with contextlib.suppress(Exception):
5454
indices = opensearch_client.indices.get(index="opensearch-kv-store-e2e-test-*")
5555
for index in indices:
@@ -101,7 +101,7 @@ def setup_opensearch(self, request: pytest.FixtureRequest) -> Generator[None, No
101101
yield
102102

103103
@pytest.fixture
104-
def opensearch_client(self, setup_opensearch: None) -> Generator[AsyncOpenSearch, None, None]:
104+
def opensearch_client(self, setup_opensearch: None) -> Generator[OpenSearch, None, None]:
105105
os_client = get_opensearch_client()
106106

107107
with os_client:
@@ -111,7 +111,7 @@ def opensearch_client(self, setup_opensearch: None) -> Generator[AsyncOpenSearch
111111

112112
@override
113113
@pytest.fixture
114-
def default_store(self, opensearch_client: AsyncOpenSearch) -> Generator[BaseStore, None, None]:
114+
def default_store(self, opensearch_client: OpenSearch) -> Generator[BaseStore, None, None]:
115115
store = OpenSearchStore(
116116
opensearch_client=opensearch_client, index_prefix="opensearch-kv-store-e2e-test", default_collection="test-collection"
117117
)
@@ -121,7 +121,7 @@ def default_store(self, opensearch_client: AsyncOpenSearch) -> Generator[BaseSto
121121

122122
@override
123123
@pytest.fixture
124-
def collection_sanitized_store(self, opensearch_client: AsyncOpenSearch) -> Generator[BaseStore, None, None]:
124+
def collection_sanitized_store(self, opensearch_client: OpenSearch) -> Generator[BaseStore, None, None]:
125125
store = OpenSearchStore(
126126
opensearch_client=opensearch_client,
127127
index_prefix="opensearch-kv-store-e2e-test",
@@ -134,7 +134,7 @@ def collection_sanitized_store(self, opensearch_client: AsyncOpenSearch) -> Gene
134134

135135
@override
136136
@pytest.fixture
137-
def key_sanitized_store(self, opensearch_client: AsyncOpenSearch) -> Generator[BaseStore, None, None]:
137+
def key_sanitized_store(self, opensearch_client: OpenSearch) -> Generator[BaseStore, None, None]:
138138
store = OpenSearchStore(
139139
opensearch_client=opensearch_client,
140140
index_prefix="opensearch-kv-store-e2e-test",
@@ -147,7 +147,7 @@ def key_sanitized_store(self, opensearch_client: AsyncOpenSearch) -> Generator[B
147147

148148
@override
149149
@pytest.fixture
150-
def fully_sanitized_store(self, opensearch_client: AsyncOpenSearch) -> Generator[BaseStore, None, None]:
150+
def fully_sanitized_store(self, opensearch_client: OpenSearch) -> Generator[BaseStore, None, None]:
151151
store = OpenSearchStore(
152152
opensearch_client=opensearch_client,
153153
index_prefix="opensearch-kv-store-e2e-test",

scripts/build_sync_library.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ class RenameAsyncToSync(ast.NodeTransformer): # type: ignore
219219
"__aiter__": "__iter__",
220220
"asyncio.locks": "threading",
221221
"AsyncElasticsearch": "Elasticsearch",
222+
"AsyncOpenSearch": "OpenSearch",
222223
"AsyncDatabase": "Database",
223224
"AsyncCollection": "Collection",
224225
"AsyncMongoClient": "MongoClient",

uv.lock

Lines changed: 7 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)